Python 在keras中的一组文档上应用共享嵌入层

Python 在keras中的一组文档上应用共享嵌入层,python,neural-network,keras,embedding,Python,Neural Network,Keras,Embedding,我试图创建一个模型,在该模型中,我希望预测给定特定查询的特定文档集的顺序。我的想法基本上是为查询和文档使用共享嵌入层,然后使用每个文档和查询之间的余弦相似性(使用自定义lambda)合并两个“分支”。然后,损失函数将计算预期位置和预测相似性之间的差异 我的问题是:有没有一种方法可以为一组文本特征创建嵌入(前提是它们具有相同的长度) 通过应用embedding+Convolution1D+GlobalMapooling1d,我可以在“doc2vec-like-embedding”中正确地转换我的查

我试图创建一个模型,在该模型中,我希望预测给定特定查询的特定文档集的顺序。我的想法基本上是为查询和文档使用共享嵌入层,然后使用每个文档和查询之间的余弦相似性(使用自定义lambda)合并两个“分支”。然后,损失函数将计算预期位置和预测相似性之间的差异

我的问题是:有没有一种方法可以为一组文本特征创建嵌入(前提是它们具有相同的长度)

通过应用embedding+Convolution1D+GlobalMapooling1d,我可以在“doc2vec-like-embedding”中正确地转换我的查询,但我没有在文档集上使用相同的策略(鉴于我使用的是文本数据,重塑+2D卷积对我来说真的没有意义)

注意,我的一个限制是我需要为我的查询和文档集使用相同的嵌入层(我使用Keras的函数API来实现这一点)

[编辑,添加示例代码]

Q = Input(shape=(5, ))    # each query is made of 5 words
T = Input(shape=(50, 50)) # each search result is made of 50 words and 50 docs

emb = Embedding(
    max_val,
    embedding_dims,
    dropout=embedding_dropout
)

left = emb(Q)
left = Convolution1D(nb_filter=5,
                     filter_length=5,
                     border_mode='valid',
                     activation='relu',
                     subsample_length=1)(left)
left = GlobalMaxPooling1D()(left)

print(left)
right = emb(T)   # <-- this is my problem, I don't really know what to do/apply here

def merger(vests):
    x, y = vests
    x = K.l2_normalize(x, axis=0)             # Normalize rows
    y = K.l2_normalize(y, axis=-1)            # Normalize the vector
    return tf.matmul(x, y)  # obviously throws an error because of mismatching matrix ranks

def cos_dist_output_shape(shapes):
    shape1, shape2 = shapes
    return (50, 1)

merger_f = Lambda(merger)

predictions = merge([left, right], output_shape=cos_dist_output_shape, mode=merger_f)

model = Model(input=[Q, T], output=predictions)

def custom_objective(y_true, y_pred):
    ordered_output = tf.cast(tf.nn.top_k(y_pred)[1], tf.float32)  # returns the indices of the top values
    return K.mean(K.square(ordered_output - y_true), axis=-1)

model.compile(optimizer='adam', loss=custom_objective)

好的。如果我理解正确的话,您有50个长度为50的文本片段要嵌入

完成单词嵌入后,你会发现自己有一个形状的张量T(50,50,emb_大小)。 我要做的是在时间分布式包装器中使用LSTM层。在
emb(T)
之后添加这些行:

这将对50个文档中的每个文档应用相同的LSTM,并在每个文档处理结束时输出长度为5的最终状态。此步骤之后的右键形状为(50,5)。您已将每个文档嵌入到长度为5的向量中。 TimeDistributed的优点是,应用于每个文档的LSTM将共享相同的权重,因此您的文档将以相同的方式“处理”。您可以找到关于LSTM和TimeDistributed的文档


我希望这有点帮助

你有一些代码可以分享吗?到目前为止您已经尝试过的内容(例如:)是的,当然:)很抱歉没有从一开始就添加它@NassimBenthanks,非常感谢。我这里唯一的问题是试图理解为什么我需要一个LSTM在这种情况下,它字面上让我困惑。我将尝试:)感谢帮助lstm将一系列向量作为输入(2D数组),并通过逐个“读取”向量对其进行编码。它会在每次引入向量并输出最后一个状态时更新隐藏状态。因此,LSTM是一种“自然”的文本编码方式,因为文本是一系列单词向量(单词嵌入)。这有意义吗?一般来说,我的结果中没有太多的结构,所以我也将测试时间分布的conv1d。顺便说一句,你发布的那行在keras/layers/recurrent.py(
self.input\u dim=input\u shape[2]
in
def build..
)的第702行抛出了一个错误
indexer:tuple index out out of range
),添加input\u shape并不能修复itnvm,我还需要“时间分布”嵌入层,这确实解决了这个问题。对不起,我没有看到那个问题。另一种可能是将输入重塑为(50*50,)张量,嵌入这些单词,这将输出一个(50*50,emb_大小)张量,再次将其重塑为(50,50,emb_大小)。这两种方法都很好:)那么问题解决了吗?
right = TimeDistributed(emb)(T)
right = TimeDistributed(Convolution1D(nb_filter=5,
                        filter_length=5,
                        border_mode='valid',
                        activation='relu',
                        subsample_length=1)(right)
right = TimeDistributed(GlobalMaxPooling1D())(right)
right = TimeDistributed(LSTM(5))(right)