keras LSTM 获取隐藏状态(将句子序列转换为文档上下文向量)

keras LSTM get hidden-state (converting sentece-sequence to document context vectors)

我正在尝试使用 keras 通过 LSTM 从句子向量创建文档上下文向量(因此每个文档都由一系列句子向量组成)。

我的目标是使用 keras 复制以下博客 post:https://andriymulyar.com/blog/bert-document-classification

我有一个(玩具)张量,它看起来像这样:X = np.array(features).reshape(5, 200, 768)所以 5 个文档,每个文档都有 200 个句子向量序列 - 每个句子向量有 768 个特征。

因此,为了从我的句子向量中嵌入,我将我的文档编码为单热向量来学习 LSTM:

y = [1,2,3,4,5] # 5 documents in toy-tensor
y = np.array(y)
yy = to_categorical(y)
yy = yy[0:5,1:6]

到目前为止,我的代码是这样的

inputs1=Input(shape=(200,768))
lstm1, states_h, states_c =LSTM(5,dropout=0.3,recurrent_dropout=0.2, return_state=True)(inputs1)
model1=Model(inputs1,lstm1)
model1.compile(loss='categorical_crossentropy',optimizer='rmsprop',metrics=['acc']) 
model1.summary()
model1.fit(x=X,y=yy,batch_size=100,epochs=10,verbose=1,shuffle=True,validation_split=0.2)

当我打印 states_h 时,我得到一个形状为 =(?,5) 的张量,我真的不知道如何访问张量内的向量,它们应该代表我的文档。

print(states_h)
Tensor("lstm_51/while/Exit_3:0", shape=(?, 5), dtype=float32)

还是我做错了什么?据我了解,应该有 5 个文档向量,例如doc1=[...] ; ...; doc5=[...] 这样我就可以将文档向量重新用于分类任务。

TF 1.x 与 tf.keras(使用 TF 1.15 测试)

Keras 使用符号张量进行运算。因此,print(states_h) 不会给你任何东西,除非你将数据传递给占位符 states_h depends on(在本例中为 inputs1)。您可以按如下方式进行。

import tensorflow.keras.backend as K

inputs1=Input(shape=(200,768))
lstm1, states_h, states_c =LSTM(5,dropout=0.3,recurrent_dropout=0.2, return_state=True)(inputs1)
model1=Model(inputs1,lstm1)
model1.compile(loss='categorical_crossentropy',optimizer='rmsprop',metrics=['acc']) 
model1.summary()
model1.fit(x=X,y=yy,batch_size=100,epochs=10,verbose=1,shuffle=True,validation_split=0.2)

sess = K.get_session()
out = sess.run(states_h, feed_dict={inputs1:X})

然后 out 将是 (batch_size, 5) 大小的输出。

TF 2.x 与 tf.keras

以上代码将无法正常工作。而且我仍然没有找到如何让它与 TF 2.0 一起工作(尽管 TF 2.0 仍然会根据 docs 生成占位符)。当我找到如何为 TF 2.x.

修复此问题时,我将编辑我的答案

好吧,打印一个张量恰恰表明了这一点:它是一个张量,它具有那种形状和那种类型。

如果你想看到数据,你需要提供数据。
状态不是权重,它们不是持久的,它们只存在于输入数据中,就像任何其他模型输出一样。

您应该创建一个模型来输出此信息(您的没有)以便获取它。您可以有两个模型:

#this is the model you compile and train - exactly as you are already doing
training_model = Model(inputs1,lstm1)     

#this is just for getting the states, nothing else, don't compile, don't train
state_getting_model = Model(inputs1, [lstm1, states_h, states_c]) 

(别担心,这两个模型将共享相同的权重并一起更新,即使您只训练 training_model

现在您可以:

关闭急切模式(也可能 "on"):

lstm_out, states_h_out, states_c_out = state_getting_model.predict(X)
print(states_h_out)
print(states_c_out)

开启急切模式:

lstm_out, states_h_out, states_c_out = state_getting_model(X)
print(states_h_out.numpy())
print(states_c_out.numpy())