Keras函数式API
一、简介
Keras函数式API可以构建类图模型、在不同的输入之间共享某一层。
Keras回调函数+TensorBoard基于浏览器的可视化工具—>在训练中监控模型
1、为什么不用Sequential模型?
因为Sequential模型假设网络单入单出且层与层之间线性堆叠。在需要多模态输入的任务中无法完成,此时需要构造可以同时查看所有输入模态,并进行联合学习的多分支模型。或在遇到同一个输入但有多个输出,且输出之间存在联系的问题时,就需要构造一个不是线性堆叠的,更灵活的模型。这时候就要使用Keras的函数式API来完成一些更复杂的模型(如多输入、多输出、类图模型)。
2、函数式API
函数式API可以直接操作张量,也可以把层当作函数来使用,接受张量并返回张量。
例:
model=keras.Sequential([
keras.layers.Dense(128,activation=tf.nn.relu,input_shape=(28,28,1)),
keras.layers.Dense(128,activation=tf.nn.relu),
keras.layers.Dense(10,activation=tf.nn.softmax)
])
换成函数式API:
#函数式API实现
input_tensor = Input(shape=(28,28,1))
x = keras.layers.Dense(128,activation=tf.nn.relu)(input_tensor)
x = keras.layers.Dense(128,activation=tf.nn.relu)(x)
ootput_tensor = keras.layers.Dense(10,activation=tf.nn.softmax)(x)
model = Model(input_tensor,output_tensor) #将输入输出转换为一个模型
输入是长度可变的文本序列时:Input(shape = (None,), dtype = ‘int32’, name = ‘text’)
可以通过在 Input 上或在另一个层的输出上调用任何模型来将其当作层来处理。通过调用模型,您不仅可以重用模型的架构,还可以重用它的权重。即模型可以嵌套:模型可以包含子模型(因为模型就像层一样)。
如:
、、、
encoder = keras.Model(encoder_input, encoder_output, name="encoder")
、、、
decoder = keras.Model(decoder_input, decoder_output, name="decoder")
、、、
、、、
autoencoder_input = keras.Input(shape=(28, 28, 1), name="img")
encoded_img = encoder(autoencoder_input)
decoded_img = decoder(encoded_img)
autoencoder = keras.Model(autoencoder_input, decoded_img, name="autoencoder")
3、多输入输出模型
在某一处需要合并,在keras中可以用add层、concatenate层等来进行合并运算。
例,有这样一个模型:(模型的这种计算图呈现可以使用 keras.utils.plot_model 方法实现)
在模型中有不同输出可以通过指定层来给不同的输出层分配不同的损失函数:
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss={
"priority": keras.losses.BinaryCrossentropy(from_logits=True),
"department": keras.losses.CategoricalCrossentropy(from_logits=True),
},
loss_weights=[1.0, 0.2],
)
通过传递输入和目标的 NumPy 数组列表来训练模型:
model.fit(
{
"title": title_data, "body": body_data, "tags": tags_data},
{
"priority": priority_targets, "department": dept_targets},
epochs=2,
batch_size=32,
)
4、常用代码
创建一个输入节点
inputs = keras.Input(shape=(784,))
img_inputs = keras.Input(shape=(32, 32, 3))
添加层
x = layers.Dense(64, activation=“relu”)(x)
通过在层计算图中指定模型的输入和输出来创建 Model
model = keras.Model(inputs=inputs, outputs=outputs, name=“mnist_model”)
模型可视化:
将模型绘制为计算图
keras.utils.plot_model(model, “my_first_model.png”)
在绘制的计算图中显示每层的输入和输出形状
keras.utils.plot_model(model, “my_first_model_with_shape_info.png”, show_shapes=True)
二、inception模块和残差连接
inception模块和残差连接是常见神经网络组件。
1、inception模块
inception是一种卷积神经网络架构,它是模块的堆叠,模块本身像是小型独立网络。基本形式包含3~4个分支,主要精髓在于1*1卷积(逐点卷积),此时的卷积等价于每个方块的向量经过一个Dense层,将输入的信息混合到一起但不会跨空间信息混合。有助于区分开通道特征学习和空间特征学习。
(具体原理不再赘述,详见官方文档)
keras实现:
tf.keras.applications.InceptionV3(
include_top=True, weights=‘imagenet’, input_tensor=None,
input_shape=None, pooling=None, classes=1000,
classifier_activation=‘softmax’
)
tf.keras.applications.InceptionResNetV2(
include_top=True, weights=‘imagenet’, input_tensor=None,
input_shape=None, pooling=None, classes=1000,
classifier_activation=‘softmax’, **kwargs
)
另外一个Xception模型是Inception模型的一个极端形式,它将空间特征与通道特征完全分离。
2、残差连接
残差连接是一种类图网络组件,它解决了大规模深度学习模型梯度消失和表示瓶颈的问题。
一般超过10层的模型中添加残差连接都有用处。
残差连接让前面某层的输出作为后层的输入。前面的输出与后面层的激活相加而不是连接(两层激活形状相同,否则要转化为相同形状)
、、、
block_1_output = layers.MaxPooling2D(3)(x)
、、、
block_2_output = layers.add([x, block_1_output])
input_shape = (2, 3, 4)
x1 = tf.random.normal(input_shape)
x2 = tf.random.normal(input_shape)
y = tf.keras.layers.Add()([x1, x2])
print(y.shape)
(2, 3, 4)
前面说过两种连接方法add和concatenate,使用concatenate连接时则是直接连接:
x = np.arange(20).reshape(2, 2, 5)
print(x)
###
[[[ 0 1 2 3 4]
[ 5 6 7 8 9]]
[[10 11 12 13 14]
[15 16 17 18 19]]]
y = np.arange(20, 30).reshape(2, 1, 5)
print(y)
###
>[[[20 21 22 23 24]]
[[25 26 27 28 29]]]
tf.keras.layers.Concatenate(axis=1)([x, y])
###
<tf.Tensor: shape=(2, 3, 5), dtype=int64, numpy=
array([[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[20, 21, 22, 23, 24]],
[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[25, 26, 27, 28, 29]]])>
3、共享权重
之前提到,函数式API可以很方便地调用层,当重复使用层的时候,该层对不同输入的权重是共享的。这种模式可以很好的解决一些问题,比如:
语义相似性分析,分析句子的规则是一样的,所以可以使用同一个模型来进行语义分析,最后将结果使用concatenate层直接连接时候放入一个Dense(1)层进行二分类。
、、、
lstm = layers. LSTM(32)
left_input、、、
left_output = lstm(left_input)
right、、、
merged = layers. concatenate([left_output,right_output],axis=1)
predictions=layers. Dense(1,activation='sigmoid')(merged) #输出0~1之间的值来表示相似度
#接下来实例化模型
、、、
还可以实现连体视觉模型,共享卷积,多个摄像头通过同一个视觉模型分别提取视觉特征然后再合并,就可以避免使用两个模型训练。
结语
函数式API相比于sequential模型更灵活,能建立更复杂的拓扑结构。
学习内容参见官方文档