python - 具有适用于 Word2Vec 模型的 Keras 功能 API 的产品合并层

标签 python nlp keras word2vec word-embedding

我正在尝试使用 Keras 实现带有负采样的 Word2Vec CBOW,遵循发现的代码 here :

EMBEDDING_DIM = 100

sentences = SentencesIterator('test_file.txt')
v_gen = VocabGenerator(sentences=sentences, min_count=5, window_size=3,
                       sample_threshold=-1, negative=5)

v_gen.scan_vocab()
v_gen.filter_vocabulary()
reverse_vocab = v_gen.generate_inverse_vocabulary_lookup('test_lookup')

# Generate embedding matrix with all values between -1/2d, 1/2d
embedding = np.random.uniform(-1.0 / (2 * EMBEDDING_DIM),
                              1.0 / (2 * EMBEDDING_DIM),
                              (v_gen.vocab_size + 3, EMBEDDING_DIM))

# Creating CBOW model
# Model has 3 inputs
# Current word index, context words indexes and negative sampled word indexes
word_index = Input(shape=(1,))
context = Input(shape=(2*v_gen.window_size,))
negative_samples = Input(shape=(v_gen.negative,))

# All inputs are processed through a common embedding layer
shared_embedding_layer = (Embedding(input_dim=(v_gen.vocab_size + 3),
                                    output_dim=EMBEDDING_DIM,
                                    weights=[embedding]))

word_embedding = shared_embedding_layer(word_index)
context_embeddings = shared_embedding_layer(context)
negative_words_embedding = shared_embedding_layer(negative_samples)

# Now the context words are averaged to get the CBOW vector
cbow = Lambda(lambda x: K.mean(x, axis=1),
              output_shape=(EMBEDDING_DIM,))(context_embeddings)

# Context is multiplied (dot product) with current word and negative
# sampled words
word_context_product = merge([word_embedding, cbow], mode='dot')
negative_context_product = merge([negative_words_embedding, cbow],
                                 mode='dot',
                                 concat_axis=-1)

# The dot products are outputted
model = Model(input=[word_index, context, negative_samples],
              output=[word_context_product, negative_context_product])

# Binary crossentropy is applied on the output
model.compile(optimizer='rmsprop', loss='binary_crossentropy')
print(model.summary())

model.fit_generator(v_gen.pretraining_batch_generator(reverse_vocab),
                    samples_per_epoch=10,
                    nb_epoch=1)

但是,我在合并部分遇到错误,因为嵌入层是 3D 张量,而 cbow 只有 2 维。我假设我需要将嵌入(即 [?, 1, 100]) reshape 为 [1, 100],但我找不到如何使用功能 API reshape 。 我正在使用 Tensorflow 后端。

此外,如果有人可以指出使用 Keras 的 CBOW 的其他实现(Gensim 免费),我很乐意看看!

谢谢!

编辑:这是错误

Traceback (most recent call last):
  File "cbow.py", line 48, in <module>
    word_context_product = merge([word_embedding, cbow], mode='dot')
    .
    .
    .
ValueError: Shape must be rank 2 but is rank 3 for 'MatMul' (op: 'MatMul') with input shapes: [?,1,100], [?,100].

最佳答案

ValueError: Shape must be rank 2 but is rank 3 for 'MatMul' (op: 'MatMul') with input shapes: [?,1,100], [?,100].

确实,您需要 reshape word_embedding 张量。有两种方法:

  • 无论您使用从 keras.layers.core 导入的 Reshape() 层,其操作方式如下:

    word_embedding = Reshape((100,))(word_embedding)
    

    Reshape 的参数是具有目标形状的元组。

  • 或者您可以使用 Flatten() 层,同样从 keras.layers.core 导入,使用方式如下:

    word_embedding = Flatten()(word_embedding)
    

    不采取任何参数,它只会删除“空”维度。

这对你有帮助吗?

编辑:

事实上,第二个merge()有点棘手。 Keras 中的 dot 合并仅接受相同秩的张量,因此相同的 len(shape)。 因此,您要做的就是使用 Reshape() 层添加回 1 个空维度,然后使用功能 dot_axes 而不是 concat_axisdot 合并无关。 这就是我建议您的解决方案:

word_embedding = shared_embedding_layer(word_index)
# Shape output = (None,1,emb_size)
context_embeddings = shared_embedding_layer(context)
# Shape output = (None, 2*window_size, emb_size)
negative_words_embedding = shared_embedding_layer(negative_samples)
# Shape output = (None, negative, emb_size)

# Now the context words are averaged to get the CBOW vector
cbow = Lambda(lambda x: K.mean(x, axis=1),
                     output_shape=(EMBEDDING_DIM,))(context_embeddings)
# Shape output = (None, emb_size)
cbow = Reshape((1,emb_size))(cbow)
# Shape output = (None, 1, emb_size)

# Context is multiplied (dot product) with current word and negative
# sampled words
word_context_product = merge([word_embedding, cbow], mode='dot')
# Shape output = (None, 1, 1)
word_context_product = Flatten()(word_context_product)
# Shape output = (None,1)
negative_context_product = merge([negative_words_embedding, cbow], mode='dot',dot_axes=[2,2])
# Shape output = (None, negative, 1)
negative_context_product = Flatten()(negative_context_product)
# Shape output = (None, negative)

有效吗? :)

问题来自于 TF 在矩阵乘法方面的刚性。使用“点”模式合并会调用后端 batch_dot() 函数,与 Theano 不同,TensorFlow 要求矩阵具有相同的秩: read here

关于python - 具有适用于 Word2Vec 模型的 Keras 功能 API 的产品合并层,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42514986/

相关文章:

nlp - 使用spaCy将单词向量映射到最相似/最接近的单词

tensorflow - TF/Keras 稀疏分类交叉熵

python - 如何在 pandas dataframe Python 中查找带有分隔符的字符串并将其替换为新行

python - 如何使用 boto 遍历 DynamoDB 表中的所有项目?

nlp - 为 SpaCy 模型创建训练数据的方法?

python - Keras 中具有自定义损失的无监督编码

python - 如何在 TensorFlow 2 中获取 Keras 张量的值?

python - 删除行并将它们的值分配给其他行

python - python中的目录文件导入错误

Python 的 SpaCy EntityRuler 没有返回任何结果