使用LSTM进行CNTK转学习:将预训练网络附加到另一个网络

时间:2017-03-28 21:27:38

标签: cntk

我有一个预先训练的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维向量。 我该如何工作? 感谢

1 个答案:

答案 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的计算机前面,无法测试,所以我可能犯了错误。)