web-dev-qa-db-ja.com

GensimのWord2Vecでget_keras_embedding()を適切に使用するにはどうすればよいですか?

埋め込みとRNNを使用して翻訳ネットワークを構築しようとしています。私はGensimWord2Vecモデルをトレーニングしましたが、Wordの関連付けをかなりよく学習しています。ただし、Kerasモデルにレイヤーを適切に追加する方法について頭を悩ませることはできませんでした。 (そして、出力に対して「逆埋め込み」を行う方法。しかし、それは答えられた別の質問です。デフォルトではできません。)

Word2Vecでは、文字列を入力すると、たとえば_model.wv[‘hello’]_、Wordのベクトル表現を取得します。ただし、Word2Vecの get_keras_embedding() によって返される_keras.layers.Embedding_レイヤーは、文字列入力ではなく、ワンホット/トークン化された入力を受け取ると思います。しかし、ドキュメントには、適切な入力が何であるかについての説明はありません。 埋め込みレイヤーの入力と1対1で対応するボキャブラリーのワンホット/トークン化されたベクトルを取得する方法がわかりません。

以下の詳細:

現在の私の回避策は、ネットワークにフィードする前に、Kerasの外部に埋め込みを適用することです。これを行うことに何か不利益はありますか?とにかく、埋め込みを訓練不可能に設定します。これまでのところ、メモリの使用は非常に非効率的であり(64ワードの長さの文のコレクションに対してKerasモデルを宣言する前でも50GBのように)、モデルの外部にパディングされた入力と重みをロードする必要があることに気付きました。多分ジェネレータが役立つことができます。

以下は私のコードです。入力は64ワードの長さに埋め込まれます。 Word2Vecの埋め込みには300の次元があります。埋め込みを機能させるために繰り返し実験を行ったため、ここにはおそらく多くの間違いがあります。提案は大歓迎です。

_import gensim
Word2vec_model = gensim.models.Word2Vec.load(“Word2vec.model")
_
_from keras.models import Sequential
from keras.layers import Embedding, GRU, Input, Flatten, Dense, TimeDistributed, Activation, PReLU, RepeatVector, Bidirectional, Dropout
from keras.optimizers import Adam, Adadelta
from keras.callbacks import ModelCheckpoint
from keras.losses import sparse_categorical_crossentropy, mean_squared_error, cosine_proximity

keras_model = Sequential()
keras_model.add(Word2vec_model.wv.get_keras_embedding(train_embeddings=False))
keras_model.add(Bidirectional(GRU(300, return_sequences=True, dropout=0.1, recurrent_dropout=0.1, activation='tanh')))
keras_model.add(TimeDistributed(Dense(600, activation='tanh')))
# keras_model.add(PReLU())
# ^ For some reason I get error when I add Activation ‘outside’:
# int() argument must be a string, a bytes-like object or a number, not 'NoneType'
# But keras_model.add(Activation('relu')) works.
keras_model.add(Dense(source_arr.shape[1] * source_arr.shape[2]))
# size = max-output-sentence-length * embedding-dimensions to learn the embedding vector and find the nearest Word in Word2vec_model.wv.similar_by_vector() afterwards.
# Alternatively one can use Dense(vocab_size) and train the network to output one-hot categorical words instead.
# Remember to change Keras loss to sparse_categorical_crossentropy.
# But this won’t benefit from Word2Vec. 

keras_model.compile(loss=mean_squared_error,
              optimizer=Adadelta(),
              metrics=['mean_absolute_error'])
keras_model.summary()
_
__________________________________________________________________ 
Layer (type)                 Output Shape              Param #   
================================================================= 
embedding_19 (Embedding)     (None, None, 300)         8219700   
_________________________________________________________________ 
bidirectional_17 (Bidirectio (None, None, 600)         1081800   
_________________________________________________________________ 
activation_4 (Activation)    (None, None, 600)         0         
_________________________________________________________________ 
time_distributed_17 (TimeDis (None, None, 600)         360600    
_________________________________________________________________ 
dense_24 (Dense)             (None, None, 19200)       11539200  
================================================================= 
Total params: 21,201,300 
Trainable params: 12,981,600 
Non-trainable params: 8,219,700
_________________________________________________________________
_
_filepath="best-weights.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor='val_mean_absolute_error', verbose=1, save_best_only=True, mode='auto')
callbacks_list = [checkpoint]
keras_model.fit(array_of_Word_lists, array_of_Word_lists_AFTER_being_transformed_by_Word2vec, epochs=100, batch_size=2000, shuffle=True, callbacks=callbacks_list, validation_split=0.2)
_

モデルをテキストに合わせようとすると、エラーがスローされます。

_Train on 8000 samples, validate on 2000 samples Epoch 1/100

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-32-865f8b75fbc3> in <module>()
      2 checkpoint = ModelCheckpoint(filepath, monitor='val_mean_absolute_error', verbose=1, save_best_only=True, mode='auto')
      3 callbacks_list = [checkpoint]
----> 4 keras_model.fit(array_of_Word_lists, array_of_Word_lists_AFTER_being_transformed_by_Word2vec, epochs=100, batch_size=2000, shuffle=True, callbacks=callbacks_list, validation_split=0.2)

~/virtualenv/lib/python3.6/site-packages/keras/engine/training.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_Epoch, steps_per_Epoch, validation_steps, **kwargs)
   1040                                         initial_Epoch=initial_Epoch,
   1041                                         steps_per_Epoch=steps_per_Epoch,
-> 1042                                         validation_steps=validation_steps)
   1043 
   1044     def evaluate(self, x=None, y=None,

~/virtualenv/lib/python3.6/site-packages/keras/engine/training_arrays.py in fit_loop(model, f, ins, out_labels, batch_size, epochs, verbose, callbacks, val_f, val_ins, shuffle, callback_metrics, initial_Epoch, steps_per_Epoch, validation_steps)
    197                     ins_batch[i] = ins_batch[i].toarray()
    198 
--> 199                 outs = f(ins_batch)
    200                 if not isinstance(outs, list):
    201                     outs = [outs]

~/virtualenv/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py in __call__(self, inputs)
   2659                 return self._legacy_call(inputs)
   2660 
-> 2661             return self._call(inputs)
   2662         else:
   2663             if py_any(is_tensor(x) for x in inputs):

~/virtualenv/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py in _call(self, inputs)
   2612                 array_vals.append(
   2613                     np.asarray(value,
-> 2614                                dtype=tensor.dtype.base_dtype.name))
   2615         if self.feed_dict:
   2616             for key in sorted(self.feed_dict.keys()):

~/virtualenv/lib/python3.6/site-packages/numpy/core/numeric.py in asarray(a, dtype, order)
    490 
    491     """
--> 492     return array(a, dtype, copy=False, order=order)
    493 
    494 

ValueError: could not convert string to float: 'hello'
_

以下は Rajmakからの抜粋 トークナイザーを使用して単語をKerasEmbeddingの入力に変換する方法を示しています。

_tokenizer = Tokenizer(num_words=MAX_NB_WORDS) 
tokenizer.fit_on_texts(all_texts) 
sequences = tokenizer.texts_to_sequences(texts)
Word_index = tokenizer.Word_index
……
indices = np.arange(data.shape[0]) # get sequence of row index 
np.random.shuffle(indices) # shuffle the row indexes 
data = data[indices] # shuffle data/product-titles/x-axis
……
nb_validation_samples = int(VALIDATION_SPLIT * data.shape[0]) 
x_train = data[:-nb_validation_samples]
……
Word2vec = KeyedVectors.load_Word2vec_format(EMBEDDING_FILE, binary=True)
_

Keras埋め込みレイヤーは、Gensim Word2VecのWord2vec.get_keras_embedding(train_embeddings = False)メソッドで取得するか、次のように構築できます。 nullの単語の埋め込みは、事前にトレーニングされたベクトル(この場合はGoogleニュース)に見つからない単語の数を示します。これは、この文脈におけるブランドのユニークな言葉である可能性があります。

_from keras.layers import Embedding
Word_index = tokenizer.Word_index
nb_words = min(MAX_NB_WORDS, len(Word_index))+1

embedding_matrix = np.zeros((nb_words, EMBEDDING_DIM))
for Word, i in Word_index.items():
    if Word in Word2vec.vocab:
        embedding_matrix[i] = Word2vec.Word_vec(Word)
print('Null Word embeddings: %d' % np.sum(np.sum(embedding_matrix, axis=1) == 0))

embedding_layer = Embedding(embedding_matrix.shape[0], # or len(Word_index) + 1
                            embedding_matrix.shape[1], # or EMBEDDING_DIM,
                            weights=[embedding_matrix],
                            input_length=MAX_SEQUENCE_LENGTH,
                            trainable=False)

from keras.models import Sequential
from keras.layers import Conv1D, GlobalMaxPooling1D, Flatten
from keras.layers import Dense, Input, LSTM, Embedding, Dropout, Activation

model = Sequential()
model.add(embedding_layer)
model.add(Dropout(0.2))
model.add(Conv1D(300, 3, padding='valid',activation='relu',strides=2))
model.add(Conv1D(150, 3, padding='valid',activation='relu',strides=2))
model.add(Conv1D(75, 3, padding='valid',activation='relu',strides=2))
model.add(Flatten())
model.add(Dropout(0.2))
model.add(Dense(150,activation='sigmoid'))
model.add(Dropout(0.2))
model.add(Dense(3,activation='sigmoid'))

model.compile(loss='categorical_crossentropy',optimizer='rmsprop',metrics=['acc'])

model.summary()

model.fit(x_train, y_train, validation_data=(x_val, y_val), epochs=2, batch_size=128)
score = model.evaluate(x_val, y_val, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
_

ここで、_embedding_layer_は、以下を使用して明示的に作成されます。

_for Word, i in Word_index.items():
    if Word in Word2vec.vocab:
        embedding_matrix[i] = Word2vec.Word_vec(Word)
_

ただし、get_keras_embedding()を使用すると、埋め込み行列はすでに作成されて修正されています。 Tokenizerの各Word_indexをget_keras_embedding()のKeras埋め込み入力。

では、KerasでWord2Vecのget_keras_embedding()を使用する適切な方法は何ですか?

7
Moobie

だから私は解決策を見つけました。トークン化されたWordのインデックスは_Word2vec_model.wv.vocab[Word].index_にあり、その逆は_Word2vec_model.wv.index2Word[word_index]_によって取得できます。 get_keras_embedding()は前者を入力として受け取ります。

私は次のように変換を行います:

_source_Word_indices = []
for i in range(len(array_of_Word_lists)):
    source_Word_indices.append([])
    for j in range(len(array_of_Word_lists[i])):
        Word = array_of_Word_lists[i][j]
        if Word in Word2vec_model.wv.vocab:
            Word_index = Word2vec_model.wv.vocab[Word].index
            source_Word_indices[i].append(Word_index)
        else:
            # Do something. For example, leave it blank or replace with padding character's index.
            source_Word_indices[i].append(padding_index)
source = numpy.array(source_Word_indices)
_

そして最後に_keras_model.fit(source, ..._

5
Moobie