我有一个预先训练的Seq-to-Seq插槽标记网络,其最简单的形式如下:
Network_1 = Sequential ([
Embedding(emb_dim)
Recurrence(LSTM(LSTM_dim))
Dense(num_labels)
])
我想将其输出用作另一个网络中的初始层。基本上我想将network_1(预训练)中的嵌入连接到network_2中的嵌入层,如下所示:
Network_2 = Sequential ([
Concat_embeddings ( Embedding(emb_dim), Network_1_embed() )
Recurrence(LSTM(LSTM_dim))
(Label('encoded_h'), Label('encoded_c'))
])
def Network_1_embed():
loaded_model = load_model(path_to_network_1_saved_model);
cloned_model = loaded_model.clone(CloneMethod.freeze);
return cloned_model
def Concat_embeddings(emb1, emb2):
X=Placeholder();
return splice(emb1(X), emb2(X))
这给了我以下错误 ValueError:Times:右侧操作数的1个前导维度与形状“[50360]”不匹配左操作数的尾随尺寸与形状'[293]'
作为参考,我们得到[293],因为emb_dim = 256,num_network_1_labels = 37,而[50360]是network_2输入的词汇量。 Network_1在训练时也具有相同的词汇表映射,因此它可以采用相同的输入,并为每个令牌输出37维向量。 我该如何工作? 感谢
答案 0 :(得分:0)
我认为您的问题是您使用整个Network_1
作为嵌入,而不仅仅是其嵌入图层。
一种方法是分别定义embed
并通过Network_1
进行培训:
embed = Embedding(emb_dim)
Network_1 = Sequential ([
embed,
Recurrence(LSTM(LSTM_dim)),
Dense(num_labels)
])
然后训练Network_1
,但保存embed
:
embed.save(EMBED_PATH)
说明:由于Network_1
只调用embed
,因此他们会共享参数,以便培训Network_1
将训练embed
的参数。保存embed
然后会为您提供由Network_1
训练的嵌入图层。实际上非常直截了当。
然后,要训练你的第二个模型(在第二个脚本中),从磁盘加载embed
并使用它:
Network_1_embed = load_model(EMBED_PATH)
Network_2 = Sequential ([
( Embedding(emb_dim), Network_1_embed() ),
splice,
Recurrence(LSTM(LSTM_dim)),
(Label('encoded_h'), Label('encoded_c'))
])
请注意使用函数元组作为传递给Sequential()
的第一项。元组意味着将两个函数应用于同一输入,并生成两个输出,然后输入后续函数splice
。
要保持embed
不变,请使用Freeze选项克隆它,就像您在示例中所做的那样。
(我不是在拥有最新CNTK的计算机前面,无法测试,所以我可能犯了错误。)