Python深度学习中Keras如何多输入多输出,以及中间层输出

浏览: 6523

在许多新手的眼中,深度学习模型构建好了之后,就只能是固定的输入和输出,甚至构建的模型只能是一个输入一个输出。其实深度学习模型很灵活,想有几个输入就有几个输入,想有几个输出就几个输出,想要哪一层的输出,就要哪一层的输出。今天,我们就用keras的几个例子,让大家对深度模型有个更深入的了解。

多输入多输出

什么情况下需要模型多个输入多个输出呢?

•多输入,单输出

比如在做文本分类任务时,我不仅仅通过文本content去预测结果,还想使用标题特征。

    content_in = Input(shape=(300,)) #输入文本长度为300
    title_in = Input(shape=(20,)) #输入标题为20

    emb_layer = Embedding(4000, 300) #embedding层,4000表示词的总数,300是输出维度

    # 文本向量和标题向量共享了embedding层
    content_emb = emb_layer(content_in)
    title_emb = emb_layer(title_in)

    lstm_content = LSTM(128)(content_emb)
    lstm_title = LSTM(128)(title_emb)

    #将lstm编码之后的两个向量进行相加,然后再经过dense层
    add = Lambda(lambda x: x[0]+x[1])([lstm_content, lstm_title])

    out = Dense(1, activation='sigmoid')(add)

    上面的例子有两个输入content_in和title_in,经过同一个embedding层之后,得到对应的向量,然后再分别经过LSTM层进行特征提取,将两个输出通过Lambda层直接相加后,经过dense层就直接进行了分类。这是两个输入,一个输出的情况。

    •多输入,多输出

    还是以文本分类为例,这个时候,我的任务变成要对文本内容和标题分别进行分类,将他们放在一起的目的只是为了共享embedding层,以获取某种关联特征。我们只需要将上面的代码做个简单的修改。

      content_in = Input(shape=(300,)) #输入文本长度为300
      title_in = Input(shape=(20,)) #输入标题为20

      emb_layer = Embedding(4000, 300) #embedding层,4000表示词的总数,300是输出维度

      # 文本向量和标题向量共享了embedding层
      content_emb = emb_layer(content_in)
      title_emb = emb_layer(title_in)

      lstm_content = LSTM(128)(content_emb)
      lstm_title = LSTM(128)(title_emb)

      out_content = Dense(1, activation='sigmoid', name='out_content')(lstm_content)
      out_title = Dense(1, activation='sigmoid', name='out_title')(lstm_title)

      model = Model([content_in, title_in], [out_content, out_title])

      最后模型有两个输出。上个丑图,方便理解。

      输入和输出因为有两个,需要整成list的形式。喂数据的时候,也要以类似的形式输入进去,比如model.fit([X_content, X_title], [Y_content, Y_content])

      在编译模型的时候,有一点点不同,这里详细讲一下。如果你对这两个输出没有什么特别需求,可以使用下面的代码简单编译。

        model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

        模型在训练的时候,对两个输出都采用“binary_crossentropy”计算loss,并都使用“adam”优化器进行优化。那如果我两个输出的类型不同怎么办?能不能使用不同的loss呢?答案是可以,并且还可以对不同的输出的loss,设置不同的权重。

          model.compile(loss={"out_content": 'binary_crossentropy', "out_title": 'categorical_crossentropy' #假设title是个多分类},loss_weights = {"out_content": 0.8,"out_title": 0.3},optimizer='adam', metrics=['accuracy'])

          注意到,模型是根据输出层的名字(name参数)来区分不同输出的loss。并且也是根据名字来确定权重。那么怎么给不同输出设置不同优化器呢?这个小编也想知道啊,可它不能够啊。一个比较实用的操作是给不同层设置不同的学习率,这个需要改写优化器函数,不在本文的范畴之内,有兴趣的同学,可以绞尽脑汁去网上找找,反正小编是找了好久才找到一个靠谱的。

          中间层的输出

          还有一种情况啊,我搭建好的模型,只是为了去训练参数,我任务的最终目标并不是模型的output,而是模型当中的某一层。比如我训练好了一个语言模型,但是我想要的是embedding层的词向量,又比如我训练了一个encoder-decoder模型,我只想要其中的中间表示向量,这该咋整呢?还还还以上面的代码为例,超级简单。

            content_in = Input(shape=(300,)) #输入文本长度为300
            emb_layer = Embedding(4000, 300, name='emb') #embedding层,4000表示词的总数,300是输出维度
            content_emb = emb_layer(content_in)
            lstm_content = LSTM(128)(content_emb)
            out = Dense(1, activation='sigmoid')(lstm_content)
            model = Model(content_in, out)

            为了简单说明,我们使用单输入单输出模型进行介绍。假设你已经用自己的数据训练好了上面模型的参数,但是你的真实目标并不是为了进行文本分类,而是想要这个模型的embedding层,用作获取词向量。怎么做呢?简单来讲,就是把你想要的子模型截取出来。

              emb_model = Model(inputs=model.input,outputs=model.get_layer('emb').output)

              输入还是原来模型的输入,但输出是指定名称的层,即”emb“。再来个丑图说明一下

              整体框架图是原模型,训练好参数之后,我只取前两层新构建一个模型(参数依旧是原模型的参数)。

              总结

              好了,一些base骚操作就介绍给大家。当大家明白了深度学习层之间的关系之后,就不觉得它有多么难理解了,理解了这些东西,大家应该就不难用keras去完成一些以前觉得很难实现的操作了。

              推荐 0
              本文由 ID王大伟 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
              转载、引用前需联系作者,并署名作者且注明文章出处。
              本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

              0 个评论

              要回复文章请先登录注册