Переподготовка предварительно обученных вложений слов в Python с использованием Gensim - PullRequest
1 голос
/ 13 июня 2019

Я хочу переучить предварительно обученные встраивания слов в Python, используя Gensim.Предварительно обученные вложения, которые я хочу использовать, - это Word2Vec от Google в файле GoogleNews-vectors-absolute300.bin.

Следуя обучающей программе Gensim's word2vec, «невозможно возобновить обучение с моделями, созданными инструментом C, load_word2vec_format(). Вы все еще можете использовать их для запросов / сходства, но информация, жизненно важная для обучения (дерево слов) там отсутствует ».Поэтому я не могу использовать KeyedVectors и для обучения модели, которую учебник предлагает использовать:

    model = gensim.models.Word2Vec.load('/tmp/mymodel')
    model.train(more_sentences)

(https://rare -technologies.com / word2vec-tutorial / )

Однако, когда я пытаюсь это сделать:

from gensim.models import Word2Vec
model = Word2Vec.load('data/GoogleNews-vectors-negative300.bin')

Я получаю сообщение об ошибке:

    1330         # Because of loading from S3 load can't be used (missing readline in smart_open)
    1331         if sys.version_info > (3, 0):
    -> 1332             return _pickle.load(f, encoding='latin1')
    1333         else:
    1334             return _pickle.loads(f.read())

    UnpicklingError: invalid load key, '3'.

Я не нашел способа конвертировать бинарный файл Google в новый файл втекстовый файл, и даже если это так, я не уверен, решит ли это мою проблему.

Кто-нибудь имеет решение этой проблемы или знает о другом способе переподготовки предварительно обученных встраиваний слов?

Ответы [ 2 ]

1 голос
/ 13 июня 2019

Метод Word2Vec.load() может загружать только полные модели в собственном формате gensim (на основе выбора объектов Python), но не любые другие двоичные / текстовые форматы.

И, как отмечено в документации, что «невозможно возобновить обучение с моделями, созданными инструментом C», в файлах GoogleNews raw-vector просто недостаточно информации для восстановления полной рабочей модели.это было использовано для обучения их.(Это потребует как внутренних весов модели, не сохраненных в этом файле, так и информации о частоте слов для управления выборкой, также не сохраненной в этом файле.)

Лучшее, что вы можете сделать, - это создать новыйWord2Vec модель, затем вставьте в нее некоторые / все GoogleNews векторов, прежде чем приступить к тренировкам.Это подверженный ошибкам процесс без реальных лучших практик и множества предостережений относительно интерпретации конечных результатов.(Например, если вы вводите все векторы, но затем заново обучаете подмножество, используя только свой собственный корпус и частоты слов, чем больше вы тренируетесь - делая векторы слов более подходящими для вашего корпуса - тем меньше таких повторныхобученные слова будут иметь какую-либо полезную сопоставимость с оставшимися неподготовленными словами.)

По сути, если вы посмотрите на источник gensim Word2Vec и узнаете, как соединить такую ​​модель Франкенштейна, это можетподойдет.Но нет встроенной поддержки или удобных готовых рецептов, которые делают это легко, потому что это по сути мутный процесс.

0 голосов
/ 13 июня 2019

Я уже ответил на это здесь .

Сохраните новостную модель Google в виде текстового файла в формате wor2vec, используя gensim.

. Отнесите этот ответ , чтобы сохранить его в виде текстового файла
Затем попробуйтеэтот код

import os
import pickle
import numpy as np
import gensim
from gensim.models import Word2Vec, KeyedVectors
from gensim.models.callbacks import CallbackAny2Vec
import operator

os.mkdir("model_dir")

# class EpochSaver(CallbackAny2Vec):
#     '''Callback to save model after each epoch.'''
#     def __init__(self, path_prefix):
#         self.path_prefix = path_prefix
#         self.epoch = 0

#     def on_epoch_end(self, model):
#         list_of_existing_files = os.listdir(".")
#         output_path = 'model_dir/{}_epoch{}.model'.format(self.path_prefix, self.epoch)
#         try:
#             model.save(output_path)
#         except:
#             model.wv.save_word2vec_format('model_dir/model_{}.bin'.format(self.epoch), binary=True)
#         print("number of epochs completed = {}".format(self.epoch))
#         self.epoch += 1
#         list_of_total_files = os.listdir(".")

# saver = EpochSaver("my_finetuned")





# function to load vectors from existing model.
# I am loading glove vectors from a text file, benefit of doing this is that I get complete vocab of glove as well.
# If you are using a previous word2vec model I would recommed save that in txt format.
# In case you decide not to do it, you can tweak the function to get vectors for words in your vocab only.
def load_vectors(token2id, path,  limit=None):
    embed_shape = (len(token2id), 300)
    freqs = np.zeros((len(token2id)), dtype='f')

    vectors = np.zeros(embed_shape, dtype='f')
    i = 0
    with open(path, encoding="utf8", errors='ignore') as f:
        for o in f:
            token, *vector = o.split(' ')
            token = str.lower(token)
            if len(o) <= 100:
                continue
            if limit is not None and i > limit:
                break
            vectors[token2id[token]] = np.array(vector, 'f')
            i += 1

    return vectors


# path of text file of your word vectors.
embedding_name = "word2vec.txt"
data = "<training data(new line separated tect file)>"

# Dictionary to store a unique id for each token in vocab( in my case vocab contains both my vocab and glove vocab)
token2id = {}

# This dictionary will contain all the words and their frequencies.
vocab_freq_dict = {}

# Populating vocab_freq_dict and token2id from my data.
id_ = 0
training_examples = []
file = open("{}".format(data),'r', encoding="utf-8")
for line in file.readlines():
    words = line.strip().split(" ")
    training_examples.append(words)
    for word in words:
        if word not in vocab_freq_dict:
            vocab_freq_dict.update({word:0})
        vocab_freq_dict[word] += 1
        if word not in token2id:
            token2id.update({word:id_})
            id_ += 1

# Populating vocab_freq_dict and token2id from glove vocab.
max_id = max(token2id.items(), key=operator.itemgetter(1))[0]
max_token_id = token2id[max_id]
with open(embedding_name, encoding="utf8", errors='ignore') as f:
    for o in f:
        token, *vector = o.split(' ')
        token = str.lower(token)
        if len(o) <= 100:
            continue
        if token not in token2id:
            max_token_id += 1
            token2id.update({token:max_token_id})
            vocab_freq_dict.update({token:1})

with open("vocab_freq_dict","wb") as vocab_file:
    pickle.dump(vocab_freq_dict, vocab_file)
with open("token2id", "wb") as token2id_file:
    pickle.dump(token2id, token2id_file)



# converting vectors to keyedvectors format for gensim
vectors = load_vectors(token2id, embedding_name)
vec = KeyedVectors(300)
vec.add(list(token2id.keys()), vectors, replace=True)

# setting vectors(numpy_array) to None to release memory
vectors = None

params = dict(min_count=1,workers=14,iter=6,size=300)

model = Word2Vec(**params)

# using build from vocab to build the vocab
model.build_vocab_from_freq(vocab_freq_dict)

# using token2id to create idxmap
idxmap = np.array([token2id[w] for w in model.wv.index2entity])

# Setting hidden weights(syn0 = between input layer and hidden layer) = your vectors arranged accoring to ids
model.wv.vectors[:] = vec.vectors[idxmap]

# Setting hidden weights(syn0 = between hidden layer and output layer) = your vectors arranged accoring to ids
model.trainables.syn1neg[:] = vec.vectors[idxmap]


model.train(training_examples, total_examples=len(training_examples), epochs=model.epochs)
output_path = 'model_dir/final_model.model'
model.save(output_path)

...