Не удается воспроизвести предварительно обученные векторы слов из векторных_ngrams

Просто любопытство, но я отлаживал код FastText gensim для репликации реализации слов вне словаря (OOV), и я не смог этого сделать. Итак, процесс, за которым я следую, - это обучение крошечной модели с игрушечным корпусом, а затем сравнение полученных векторов слова в словаре. Это означает, что если весь процесс в порядке, выходные массивы должны быть одинаковыми.

Вот код, который я использовал для теста:

from gensim.models import FastText
import numpy as np
# Default gensim's function for hashing ngrams
from gensim.models._utils_any2vec import ft_hash_bytes

# Toy corpus
sentences = [['hello', 'test', 'hello', 'greeting'],
             ['hey', 'hello', 'another', 'test']]

# Instatiate FastText gensim's class
ft = FastText(sg=1, size=5, min_count=1, \
window=2, hs=0, negative=20, \
seed=0, workers=1, bucket=100, \
min_n=3, max_n=4)

# Build vocab
ft.build_vocab(sentences)

# Fit model weights (vectors_ngram)
ft.train(sentences=sentences, total_examples=ft.corpus_count, epochs=5)

# Save model
ft.save('./ft.model')
del ft

# Load model
ft = FastText.load('./ft.model')

# Generate ngrams for test-word given min_n=3 and max_n=4
encoded_ngrams = [b"<he", b"<hel", b"hel", b"hell", b"ell", b"ello", b"llo", b"llo>", b"lo>"]
# Hash ngrams to its corresponding index, just as Gensim does
ngram_hashes = [ft_hash_bytes(n) % 100 for n in encoded_ngrams]
word_vec = np.zeros(5, dtype=np.float32)
for nh in ngram_hashes:
    word_vec += ft.wv.vectors_ngrams[nh]

# Compare both arrays
print(np.isclose(ft.wv['hello'], word_vec))

Выход этого скрипта False для каждого измерения сравниваемых массивов.

Было бы неплохо, если бы кто-нибудь мог указать мне, если я что-то упускаю или делаю что-то не так. Заранее спасибо!


person threepwood    schedule 04.03.2020    source источник


Ответы (1)


Расчет словарного вектора FastText полного слова представляет собой не просто сумму векторов его символьных n-грамм, но также необработанный вектор полного слова, который также обучен для слов в словаре.

В векторах полных слов, которые вы получаете от ft.wv[word] для известных слов, эта комбинация уже была предварительно рассчитана. См. метод adjust_vectors() для примера этого полного расчета:

https://github.com/RaRe-Technologies/gensim/blob/68ec5b8ed7f18e75e0b13689f4da53405ef3ed96/gensim/models/keyedvectors.py#L2282

Полные необработанные векторы находятся в массиве .vectors_vocab объекта model.wv.

(Если этого недостаточно для согласования вопросов: убедитесь, что вы используете последнюю версию gensim, так как было много недавних исправлений FT. И убедитесь, что ваш список хэшей ngram соответствует выходным данным метода ft_ngram_hashes() библиотеки — если нет, ваше ручное создание ngram-list и последующее хеширование могут делать что-то другое.)

person gojomo    schedule 04.03.2020
comment
Спасибо за ответ @gojomo, мне удалось воспроизвести ожидаемое поведение. Просто для уточнения, и извините, если это глупый вопрос, но в чем причина этого разделения на две матрицы, одну для .vectors_vocab, а другую для .vectors_ngrams? Поскольку исходная статья относится только к тому, что мы представляем слово суммой векторных представлений его n-грамм. - person threepwood; 05.03.2020
comment
Также из оригинальной статьи «Обогащение векторов слов информацией о подсловах» (FastText): Каждое слово w представлено в виде набора символов n-граммы. Мы добавляем специальные граничные символы ‹ и › в начале и в конце слов, позволяющие отличать префиксы и суффиксы от других последовательностей символов. Мы также включаем само слово w в набор его n-грамм, чтобы узнать представление для каждого слова (в дополнение к символьным n-граммам). [выделено автором] - person gojomo; 05.03.2020
comment
Первоначальная реализация Facebook C ++, IIRC, включала как векторы полных слов, так и векторы n-грамм в один непрерывный массив (с одной группой впереди, а другой сзади) - и пересчитывал окончательный (объединенный) вектор каждый раз, когда он был запрошен. Я считаю, что разработчик подхода gensim сохраняет необработанные/обученные векторы полных слов по мере необходимости для продолжения обучения, но кэширует комбинированные векторы для всех слов в словаре для оптимизации производительности. (Наличие этих полных конечных векторов в массиве позволяет массовым векторизованным операциям выполняться намного быстрее для most_similar и т. д.) - person gojomo; 05.03.2020