Keras函数式API
之前所有的神经网络都是基于Sequential模型实现的,而且网络都是层的线性叠加。但是在实际情况下,有些网络需要多个独立的输入,有些网络需要多个输出;而且有些层之间具有内部分支。
不用Sequential序贯模型的解决方案:Keras函数式API
在线阅读地址:https://livebook.manning.com/book/deep-learning-with-python/about-this-book
多输入模型
有些任务需要多模态输入(multimodal),这些任务合并来自不同输入的数据源,并使用不同类型的神经网络层来处理不同类型的数据。
一个案例来理解:利用输入数据来预测一件二手衣服的价格
函数式API简介
In [1]:
1 | import tensorflow as tf |
函数式API和Sequential模型对比
In [2]:
1 | from keras.models import Sequential, Model |
1、对应的Sequential模型代码:
In [3]:
1 | # # Sequential模型 |
2、对应的函数式API版本:
In [4]:
1 | # 对应的函数式API版本 |
绘制模型计算图(新增)
In [5]:
1 | # 绘制模型计算图 |
在将Model类实例化的过程中,Keras会在后台检索从 input_tensor 到 output_sensor所包含的每层,并将这些组成一个类图的数据结构,即一个Model。
我们可以看到outputs_tensor是通过input_tensor多次变换得到的。
In [6]:
1 | # 模型编译、训练等 |
In [7]:
1 | # 对于这种Model实例进行编译、训练或者评估时,其API和Sequential相同 |
Out[7]:
1 | 56.22259521484375 |
实现多输入模型
函数式API能够构建多个输入的模型。一般使用keras.layers.add、keras.layers.concatenate等方法将不同的层进入合并。
一个典型的模型有两个输入:
- 一个自然语言描述的问题
- 一个文本片段(新闻等)
模型需要生成一个回答,通常这个回答只包含一个词语,可以通过对某个预定义的词表做softmax得到。
函数式API实现双输入问答模型
下面函数式API构建的模型设置两个分支:文本输入和问题输入;分别编码为向量,连接这两个向量。在连接好的基础上添加一个softmax分类器:
In [8]:
1 | from keras.models import Model |
模型实例化时输入两个输入和输出:
In [9]:
1 | model = Model([text_input, question_input], answer) # 指定两个输入和输出 |
训练双输入模型
提供2个方法:
- 向模型输入一个由numpy数组组成的列表
- 输入一个由输入名称映射为numpy数组的字典
In [10]:
1 | # 将数据输入到多输入模型中 |
Out[10]:
1 | array([[0., 0., 0., ..., 0., 0., 0.], |
In [11]:
1 |
In [12]:
1 | # 方式2:传入一个将输入名称映射成Numpy数组的字典 |
Out[12]:
1 | <keras.callbacks.History at 0x15cd18dd0> |
多输出模型
用函数式API实现一个三输出的模型。一个简单的例子就是网络试图同时预测数据的不同性质,比如根据数据同时预测用户的年龄、性别和收入水平等
搭建多输出模型
In [13]:
1 | # 作用:用函数式API实现一个三输出模型 |
通过上面的代码我们看到,每个网络的各个头都有指定不同的损失函数。预测不同的目标是不同的任务。
合并不同损失最简单的方法就是:对所有的损失求和
编译选项:多重损失
In [14]:
1 |
In [15]:
1 |
损失加权
严重不平衡的损失贡献会导致模型针对单个损失值最大的任务优先优化,而不考虑其他的优化。
为了解决这个问题,我们可以为每个最终损失的最大贡献分配不同大小的重要性:损失加权
In [16]:
1 | # model.compile(optimizer="rmsprop", |
In [17]:
1 | # 上面的等效写法:只有输出层指定了名称下面的写法才生效 |
训练模型(修改)
多输出模型的训练输入可以是Numpy数组组成的列表或者字典。
假设posts
输入数据,age_targets、income_targets、gender_targets
是样本标签,那么向模型输入数据的代码如下:
1 | #写法1 |
1 | # 写法2 |