Keras 高级用法:函数式 API 7.1

Posted 神机喵算

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Keras 高级用法:函数式 API 7.1相关的知识,希望对你有一定的参考价值。

7.1.4 layer 有向无环图( DAG )

函数式 API,不仅仅可以构建多输入和多输出模型,也可以实现复杂的网络拓扑结构。我们利用Keras的神经网络能构件任意 layer 的有向无环图。其中的限定词“无环”意味着这些图不能有环。一个 layer 输入张量 x ,再生成 x ,这种情况是不可行的。只有一种处理 loop 的情形在循环 layer 内部:循环连接。

有些常见的神经网络是以 graph 实现的,其中两个有影响力的是:Inception 网络和残差连接。为了更好的理解如何使用函数式 API构建 layer 有向无环图,下面介绍用Keras如何实现两种神经网络。

  • Inception 网络

Inception  是卷积神经网络中流行的网络结构,它是由Google的Christian Szegedy 在2013 - 2014 年提出的。Inception 由一系列独立的小型网络堆叠而成,它们分成一些并行分支。Inception 最常见的形式是由三到四个分支,这些分支以 1 x 1 卷积开始,并紧跟一个 3 x 3 的卷积,最后将输出结果特征级联。这种设置有利于各个网络单独地学习空间特征和通道特征,比将它们联合学习更高效。更复的 Inception 一般涉及池化操作,不同空间尺寸的卷积(比如,在某些分支上用 5 x 5 代替 3 x 3 的卷积),以及不带空间尺寸卷积的分支(只有 1 x 1 卷积)。下面看下 Inception  V3 的网络结构,见图 7.8。

图 7.8  Inception  V3 的网络结构

1 x 1 卷积的作用

你已经知道了卷积是对输入张量沿着每块(tile)进行空间特征抽取(spatial patch),并对每个特征应用相同的变换。一种边界情况是:当特征抽取是由单个块组成时,卷积操作相当于通过 Dense layer 计算块向量。它将计算输入张量不同通道的混合信息特征,但是却没有跨整个空间混合信息特征(因为每次只计算一块)。

1 x 1 卷积,也称为pointwise卷积,它是 Inception  网络的特点,这些主要用来分解通道特征学习和空间特征学习。如果假设每个通道都是在空间上高度自相关的,那么这是合理的。但是不同的通道可能互相之间不是高度自相关的。

译者注:tile 指输入向量分块,也可指卷积核的分块;patch 上面指卷积核。

下面是用函数式 API 实现图 7.8 的 Inception网络,其中假设输入张量 x 的形状是 4D:

from keras import layers
'''Every branch has the same stride value (2), which is necessary to keep all branch outputs the same size so you can concatenate them.'''branch_a = layers.Conv2D(128, 1, activation='relu', strides=2)(x)
branch_b = layers.Conv2D(128, 1, activation='relu')(x)
'''In this branch, the striding occurs in the spatial convolution layer.'''branch_b = layers.Conv2D(128, 3, activation='relu', strides=2)(branch_b)
'''In this branch, the striding occurs in the average pooling layer.'''branch_c = layers.AveragePooling2D(3, strides=2)(x)branch_c = layers.Conv2D(128, 3, activation='relu')(branch_c)
branch_d = layers.Conv2D(128, 1, activation='relu')(x)branch_d = layers.Conv2D(128, 3, activation='relu')(branch_d)branch_d = layers.Conv2D(128, 3, activation='relu', strides=2)(branch_d)
'''Concatenates the branch outputs to obtain the module output'''output = layers.concatenate( [branch_a, branch_b, branch_c, branch_d], axis=-1)

注意,完整的 Inception V3网络结构在Keras keras.applications.inception_v3.InceptionV3可用,包括在ImageNet数据集上预先训练的权重。另一相近的模型是 Xception模型,Xception是“extreme inception”的缩写,是由 Inception启发而来的卷积结构。它利用 channel-wise 和 space-wise 特征分开学习的思想,并且用 depthwise separable convolution (由 depthwise convolution 紧跟 pointwise convolution组成。depthwise convolution的每个输入通道分开处理,pointwise convolution即 1 x 1 卷积)代替了 Inception网络结构。Xception和 Inception V3有相同的参数数量,却性能更好。

  • 残差连接

残差连接(residual connection)是一个常见的有向无环图网络组件,在许多2015 年后的网络结构中发现,包括 Xception 。它解决了困扰大规模深度学习模型的两个常见问题:梯度消失和特征表示瓶颈。一般来说,超过十个 layer 的模型添加残差连接可能是有益的。

残差连接仅仅是将一个前一个层 layer 的输出作为后一层的输入,有效地在序列网络结构中创建了一个快捷方式(shortcut)。假设两个激活函数具有相同的大小,则将前一个层 layer 的输出与后来的激活函数进行求和,而不是合并。若果激活函数大小不同,可以使用线性变换将前一层 layer 的激活转换成目标形状 (例如,不带激活函数的Dense layer,或者卷积特征图,不带激活函数的 1x1卷积)。

下面用 Keras 实现一个残差连接,输入张量 x 是 4D。当特征图大小相同,采用identity 残差连接:

from keras import layers
x = ...'''Applies a transformation to x'''y = layers.Conv2D(128, 3, activation='relu', padding='same')(x)y = layers.Conv2D(128, 3, activation='relu', padding='same')(y)y = layers.Conv2D(128, 3, activation='relu', padding='same')(y)
'''Adds the original x back to the output features'''y = layers.add([y, x])

当特征图大小不同,采用线性残差连接:

from keras import layers
x = ...y = layers.Conv2D(128, 3, activation='relu', padding='same')(x)y = layers.Conv2D(128, 3, activation='relu', padding='same')(y)y = layers.MaxPooling2D(2, strides=2)(y)'''Uses a 1 × 1 convolution to linearly downsample the originalx tensor to the same shape as y'''residual = layers.Conv2D(128, 1, strides=2, padding='same')(x)
'''Adds the residual tensor back to the output features'''y = layers.add([y, residual])

深度学习的特征表示瓶颈 

 在 Sequential 模型中,下一个特征表示层只能获取前一层经过激活函数的信息。假如某一层的特征维度太低,那么模型包含的特征会被该层限制。残差连接将更早一层的特征重新注入到下游层,从而部分地解决了深度学习模型中的特征表示瓶颈问题。

深度学习的梯度消失问题 

反向传播算法是深度神经网络的主要算法,它从输出端损失传播反馈信号到上一层。假如反馈信号传输的层数太深,那么信号可能冗余或者完全丢失,导致神经网络不可训练。该问题被称作梯度消失( vanishing gradients )。

 

上面问题经常出现在深度网络和带循环的网络,这两种情况下反馈信号必须经过长系列传播。你已经熟悉的 LSTM layer 是用来解决循环神经网络的:它引入一个 carry 跟踪传播特征到主流程。残差连接在前向的深度神经网络中采用相似的方法,但是看起来更简单:引入一个纯线性特征信息跟踪到主流程,因此可以帮助深度神经网络梯度传播。

7.1.5 共享层权重

函数式 API 更重要的特性是多次重用 layer 实例。当你调用 layer 实例两次,也只会一次实例化,两次使用的相同的权重。这有利于你构建共享分支模型,这些分支共享相同的知识并执行相同的操作,即共享相同的特征表示,从不同的输入数据集同时学习这些特征表示。

一个例子就是评估两个句子的语义相似度的模型。该模型有两个输入(比较的两个句子),输出一个 取值范围为 0 到 1 的分数,其中 0 表示句子不相关,1 表示句子是相同的,或者仅是对彼此的重新表述。它应用在对话系统中的自然语言去重查询。

在本例子中,两个输入句子可以互换,因为语义相似是对称关系:A 和 B 相似等同于 B 和 A 相似。因此,这里我们使用单个 LSTM layer ,LSTM layer的特征表示是同时从两个输入学习的。这种也称为 Siamese LSTM 模型或者 shared LSTM。

下面用 Keras 函数式 API 实现共享层模型:

from keras import layersfrom keras import Inputfrom keras.models import Model
'''Instantiates a single LSTM layer, once'''lstm = layers.LSTM(32)
'''Building the left branch of the model: inputs are variable-length sequences of vectors of size 128.'''left_input = Input(shape=(None, 128))left_output = lstm(left_input)
'''Building the right branch of the model: when you call an existing layer instance, you reuse its weights.'''right_input = Input(shape=(None, 128))right_output = lstm(right_input)
'''Builds the classifier on top'''merged = layers.concatenate([left_output, right_output], axis=-1) predictions = layers.Dense(1, activation='sigmoid')(merged)
'''Instantiating and training the model: when you train such a model, the weights of the LSTM layer are updated based on both inputs.'''model = Model([left_input, right_input], predictions)model.fit([left_data, right_data], targets)

7.1.6 模型作为层

重要的是,在函数式 API中,模型能当作 layer 来有效地使用,可以认为模型是“更大的 layer”。Sequential 和 Model 类都是这样,这意味着可以在输入张量上调用一个模型,并输出一个输出张量:

y = model(x)

如果一个模型有多个输入张量和多个输出张量,那么可以调用一个张量list:

y1, y2 = model([x1, x2])

当调用一个 model 实例时,你正在重用 model 的权重,就如同调用一个 layer 实例。简单地调用一个实例,无论它是一个 layer 实例还是一个 model 实例,都将重用实例已有的学习表示,这是非常直观的。

一个简单的重用一个 model 实例的例子是,使用双摄像头作为输入建立一个视觉模型:两个平行的摄像头,相距几厘米。这样的模型可以感知深度,这在许多应用中都有用。在合并两个提要之前,你不需要两个独立的模型来从左右两边的摄像机中提取视觉特征。这样处理可以在两个输入之间使用相同权重的层共享,从而共享相同的特征表示。下面是如何在 Keras 中实现这个功能:

from keras import layersfrom keras import applicationsfrom keras import Input
'''The base image-processing model is the Xception network (convolutional base only).'''xception_base = applications.Xception(weights=None, include_top=False)
'''The inputs are 250 × 250 RGB images.'''left_input = Input(shape=(250, 250, 3))right_input = Input(shape=(250, 250, 3))
'''Calls the same vision model twice'''left_features = xception_base(left_input)right_input = xception_base(right_input)
'''The merged features contain information from the right visual feed and the left visual feed.'''merged_features = layers.concatenate( [left_features, right_input], axis=-1)
7.1.7 小结

本小节介绍了 Keras 的函数式 API ,它是构建高级神经网络结构必备的功能。下面总结下知识点:

  • 逐步说明解释什么情况下使用函数式 API ,而不是线性堆叠的 layer;

  • 如何用 Keras 函数式 API 构建多输入、多输出和复杂拓扑网络模型;

  • 如何在不同的模型分支重用一个 layer 或者 model 的权重,多次调用相同的 layer 或者 model 实例。

招聘:服务端开发、机器学习工程师

地点:北京,直接后台私信即可。

未完待续。。。

Enjoy!

  • 声明本资料仅供个人学习交流、研究,禁止用于其他目的。

  • 上述内容加入了个人的理解和提炼(若有引起不适,请阅读原文),希望能用通俗易懂、行文流畅的表达方式呈现给新手。


若发现以上文章有任何不妥,请联系我。


以上是关于Keras 高级用法:函数式 API 7.1的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Keras函数式API进行深度学习?

keras_API汇总积累(熟读手册)二,函数式API

keras_API汇总积累(熟读手册)二,函数式API

Keras Sequential顺序模型

Keras学习记录之模型

深度学习-Tensorflow Keras使用函数式API构建复杂模型