Рубрики
Без рубрики

Создание сети ассоциаций слов с нуля

С тех пор, как я впервые запустил один словесный домен этим летом, я получил много запросов на шарнир … Tagged с помощью Python, NLP, MachineLearning, Spacy.

С тех пор, как я первый запущен Этим летом один словесный домены я получил множество запросов на функцию поиска, чтобы помочь ориентироваться в постоянно растущем списке доменов на сайте (текущее число составляет около 500 тыс. Доменов).

Моя первая мысль, когда я начал планировать реализацию этой функции:

О, это не должно быть слишком сложно, я просто собираюсь:

  1. Получите список слов, которые наиболее похожи на поисковый запрос пользователя, используя Библиотека Spacy NLP и отображать их на сайте.
  2. Также покажите список TLD, которые доступны для этого конкретного запроса.

Нет.

Однако, когда я начал переводить свое видение на код, я столкнулся с несколькими техническими ограничениями.

Во-первых, я хотел, чтобы поиск был быстр быстро, поэтому расчет сходства косинуса в режиме реального времени-это не хоть-это просто займет слишком много времени.

Кроме того, даже если бы я смог оптимизировать время расчета до <50 мс, как мне развернуть модель Spacy в Интернет, когда даже en_core_web_md Сама модель более 200 МБ рассчитана?

Мне потребовалось 3 дня, чтобы выяснить жизнеспособное решение для этого, поэтому я надеюсь, что этот пост в блоге поможет вам сделать это за гораздо более короткое время.

После проведения нескольких исследований я пришел к выводу, что у меня был только один способ сократить время поиска до уровней до 50 мс-предварительно обучая модель локально и кэшируя результаты в PostgreSQL.

По сути, я буду делать, так это создание сети ассоциаций слов, которая отображает отношения между 20 -километровыми словами, которые в настоящее время находятся в моей базе данных.

Представьте себе это:

ПРИМЕЧАНИЕ. Десятичные значения на каждом из краев представляют оценки сходства между вспомогательными терминами и корневой термин

Теперь представьте это снова, но на этот раз с 20 000 прилагательных, существительных, глаголов и 10 других категорий + французские и испанские слова*.

Я знаю, звучит довольно безумно и круто одновременно, верно?

Сначала я установил библиотеку Spacy в свою виртуальную среду и загрузил en_core_web_md модель:

pip install spacy
python3 -m spacy download en_core_web_md

Затем я импортировал их в свое приложение Flask и загрузил слова векторы:

import spacy
import en_core_web_md
nlp = en_core_web_md.load()

Теперь пришло время построить слово «ассоциация». Я впервые взял список слоев, которые были в Домены одного слова и токенизировать их. Затем, используя вложенную для петли, я рассчитал сходство косинуса между каждым из терминов, сохранив список из 100 наиболее похожих вспомогательных терминов для каждого слова, используя AddTolist функционируют и хранили все в словаре. Код для всего, что является следующим:

# Add to list function to add the list of significant scores to list
def addToList(ele, lst, num_ele):
    if ele in lst:
        return lst
    if len(lst) >= num_ele: #if list is at capacity
        if ele[1] > float(lst[-1][1]): #if element's sig_score is larger than smallest sig_score in list
            lst.pop(-1)
            lst.append((ele[0], str(ele[1])))
            lst.sort(key = lambda x: float(x[1]), reverse=True)
    else:
        lst.append((ele[0], str(ele[1])))
        lst.sort(key = lambda x: float(x[1]), reverse=True)
    return lst

import json

# list of English vocabs
en_vocab = ['4k', 'a', 'aa', ...]

# tokenizing the words in the vocab list
tokens = nlp(' '.join(en_vocab))

# initiate empty dictionary to store the results 
en_dict = {}

# Nested for loop to calculate cosine similarity scores
for i in range(len(en_vocab)):
    word = en_vocab[i]
    print('Processing for '+ word + ' ('+ str(i) + ' out of '+ str(len(en_vocab)) + ' words)')
    for j in range(i+1, len(en_vocab)):
        prev_list_i = en_dict[str(tokens[i])]['similar_words']
        en_dict[str(tokens[i])]['similar_words'] = addToList((str(tokens[j]), tokens[i].similarity(tokens[j])), prev_list_i, 100)
        prev_list_j = en_dict[str(tokens[j])]['similar_words']
        en_dict[str(tokens[j])]['similar_words'] = addToList((str(tokens[i]), tokens[i].similarity(tokens[j])), prev_list_j, 100)

    with open('data.json', 'w') as f:
        json.dump(en_dict, f)

Этот код занял вечность, чтобы запустить. Для 20 000 слов было в общей сложности 200 010 000 комбинаций (20000 + 19999 + 19998 + … + 3 + 2 + *, 010 000). Учитывая, что каждая комбинация заняла около полумиллисекунды, чтобы полностью выполнить полмитисекунды, когда все это заняло около 36 часов.

Но после того, как эти изнурительные 36 часов были вверх, у меня был полный список слов, а также 100 самых похожих слов для каждого из них.

Чтобы улучшить скорости извлечения данных, я продолжил хранить данные в PostgreSQL – реляционная база данных, которая невероятно масштабируется и мощна, особенно когда речь идет о больших объемах данных. Я сделал это со следующими строками кода:

def store_db_postgres():

    with open('data.json', 'r') as f:
        data = json.load(f)

    for word in data.keys():
        db_cursor.execute("""INSERT INTO dbname (word, param) VALUES (%s, %s);""", (word, json.dumps(data[word]['similarity'])))
        db_conn.commit()

    return 'OK', 200

И, вуаля! Теперь вы можете пройти через миллионы ребра в сети словесных ассоциаций с минимальной задержкой (в последний раз я проверял, это было на уровнях 50 мс). Инструмент поиска живет на Домены одного слова Теперь – не стесняйтесь поиграть с этим.

* Французские и испанские слова были обучены fr_core_news_md и es_core_news_md модели соответственно.

Вот и сложная часть. Я знал, что, хотя у меня было более 20 тысяч наиболее часто используемых английских слов в моей сети словах, всегда будет шанс, когда запрос пользователя не является частью моей базы знаний.

Поэтому я хотел добавить опцию для пользователей для получения результатов на лету. Чтобы сделать это, мне нужно было загрузить модель Spacy в Интернет, чтобы я мог создать дополнительные ребра в сеть Word Association в режиме реального времени.

Тем не менее, это было невозможно на Heroku, учитывая жесткий предел размера слизняки 500 МБ (мой текущий размер слизняка уже 300 МБ). Мне нужна была более мощная альтернатива, и тогда я решил пойти с AWS Lambda.

У меня была первая встреча с функцией Lambda, когда мне пришлось использовать их для размещения компонента NLP A Фильм Чатбот Что я помог построить для моего класса ИИ этой осенью.

В то время как функции Lambda были довольно сложными для установки в начале, с помощью удобного Библиотека Zappa И тонны постов Stackoverflow, я смог создать самую собственную функцию Lambda One Word, которая найдет самые похожие слова для данного запроса и вернуть их в формате JSON.

Я не буду слишком глубоко вдаваться в сорняки по поводу процесса развертывания, но это был Руководство Это очень помогло мне. Кроме того, вот основная функция драйвера, которая найдет список 100 лучших наиболее связанных слов для данного запроса:

@app.route('/generate')
@cross_origin()
def generate_results():
    # get vocab
    vocab_pickle = s3.get_object(Bucket='intellisearch-assets', Key='vocab')['Body'].read()
    vocab_only = pickle.loads(vocab_pickle)
    vocab_only = list(set(vocab_only))
    # add new query to vocab
    vocab_only.insert(0, query)
    # store vocab back to pickle
    serialized_vocab = pickle.dumps(vocab_only)
    s3.put_object(Bucket='intellisearch-assets', Key='vocab', Body = serialized_vocab)
    # do the rest
    tokens = nlp(' '.join(vocab_only))
    results = []
    for i in range(1, len(vocab_only)):
        if str(tokens[i]) != query:
            results.append([str(tokens[i]), tokens[0].similarity(tokens[i])])
    results.sort(key=lambda x: x[1], reverse=True)
    return results[:100]

Здесь я храню список слоев в форме маринованного файла на AWS S3, и всякий раз, когда у меня есть новый запрос, я использую s3.get_object Чтобы вернуть список и обновить его, вставив новое слово в список. Обратите внимание, что я использую @cross_origin () Декоратор из Flask’s Cors Library, так как я призываю эту функцию Lambda из моего приложения Heroku.

И это … почти все. Все, что мне нужно было сделать сейчас, это подключить конечную точку API API AWS Lambda к моему первоначальному приложению Heroku, чтобы помочь составить список соответствующих слов для данного поискового запроса, который пользователь вводит на сайте. Вот схема для этого:

import requests
url = + query
response = requests.get(url)
similar_words = response.json()
print(similar_words)

Наконец, момент истины – вот Закринг записи Показывая, как поиск в реальном времени работает на одном домене слова.

И вот вы идете-полностью функциональный алгоритм поиска, созданный на вершине сети ассоциации слов, содержащей 20 000 узлов и миллионы краев.

Не стесняйтесь поиграть с инструментом поиска в верхней части каждой страницы на Домены одного слова Анкет Если у вас есть какие -либо отзывы, или если вы найдете ошибку, не стесняйтесь присылать мне сообщение через чат, Страница контакта , Электронная почта или Twitter – Я бы хотел помочь!

Оригинал: “https://dev.to/steventey/building-a-word-association-network-from-scratch-1j7e”