【问题标题】:CNTK Transfer Learning with LSTM: appending pretrained network to another networkCNTK 使用 LSTM 进行迁移学习:将预训练的网络附加到另一个网络
【发布时间】:2017-03-28 21:27:38
【问题描述】:

我有一个预训练的 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: 形状为“[50360]”的右操作数的 1 个前导维度与形状为“[293]”的左操作数的尾随维度不匹配

作为参考,我们得到 [293],因为 emb_dim=256,num_network_1_labels=37,而 [50360] 是 network_2 输入的词汇量。 Network_1 在训练时也具有相同的词汇表映射,因此它可以采用相同的输入,并为每个标记输出一个 37 维向量。 我该如何进行这项工作? 谢谢

【问题讨论】:

    标签: cntk


    【解决方案1】:

    我认为您的问题是您使用整个 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,无法测试,所以可能是我犯了错误。)

    【讨论】:

    • 我可以只使用嵌入层,这可能没问题,因为当端到端学习时,嵌入层会学习一些区分向量。但是,我特别想使用 LSTM 来提取嵌入,因为顺序过程提供了更好的向量,例如,如果我已经训练它来提取 POS 标签,并使用第二个网络来完成在不同数据集上训练的一些更高级别的 LU 任务。我将尝试仅使用您建议的嵌入层的 tuple+splice 组合,但了解如何执行此操作将非常有帮助。
    • 有一个图像迁移学习的例子(例如github.com/Microsoft/CNTK/blob/master/Examples/Image/…),但我认为它更简单一些,因为它没有序列,基本上可以像你建议的那样克隆最后两层.我一直在寻找类似的东西,但在本练习中使用序列。
    • 啊,对不起,我误会了。你能试试你的代码,但用( Embedding(emb_dim), Network_1_embed() ), splice替换Concat_embeddings ( Embedding(emb_dim), Network_1_embed() )吗?
    • 我尝试了你的建议。收到此错误:[TypeError: CNTK Function expected 1 arguments, got 0] at Concat_embeddings ( Embedding(emb_dim), Network_1_embed() )。
    • 也作为参考,我实际上是在尝试在link 给出的示例中将第一个网络注入编码器部分,其中输入可能有点棘手
    猜你喜欢
    • 2015-05-05
    • 2012-05-30
    • 1970-01-01
    • 2018-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-13
    • 2019-03-02
    相关资源
    最近更新 更多