Image from unsplash.com by @ripato
前面的文章我们学习了如何使用 Tensorflow 2.0 训练卷积神经网络,今天我们将学习如何用卷积神经网络的升级版 ResNet 来实战 CIFAR100 数据集。
关注微信公众号获取源代码(二维码见文末)
1. 深度神经网络的困扰
自从2012 年,5层卷积神经网络在 ILSVRC12 挑战赛 ImageNet 数据集分类取得冠军之后,卷积神经网络再次火爆起来。随着计算机的运算能力的提高,越来约深的神经网络得到了应用。随着神经网络深度的增加,神经网络的准确率也得到了相应的提升。经典网络如 VGG 就将网络深度提高到了19层。
然而神经网络超过20层之后,错误率不仅不会下降,反而上升了,并且训练起来也越来越困难,这主要是由于深度神经网络存在梯度消失和梯度爆炸的问题。在较深层数 的神经网络中,梯度信息由网络的末层逐层传向网络的首层时,传递的过程中会出现梯度 接近于 0 或梯度值非常大的现象。网络层数越深,这种现象可能会越严重。
VGG13 网络模型结构2. ResNet 简介
ResNet 的发明就是为了解决深度神经网络梯度消失和梯度爆炸的问题。既然加深网络会导致上诉问题,是否可以给神经网络“短路”,让其有退回稍微浅层结构的能力,至少不能比浅层神经网络差吧。
这种“短路”操作,就是在若干个卷积神经层中间加一条路径,神经网络可以选择
添加短路的 VGG13 网络结构
- 经过这几个卷积层完成特征变换。
- 直接跳过这几个卷积层
- 将上面两者结合起来
�����ResNet 由华人科学家何凯明等人在2015年发明,如今已经能够将神经网络扩展到一千多层。感兴趣的读者请前往这里阅读论文原文。
3. ResNet 结构
论文原文介绍了 18层,34层,50层,101层和152层一共五种ResNet,虽然深度不同,但是结构框架是一致的,只要掌握结构规律,可以将网络结构的层数无限扩散下去。
这里以18层的 ResNet18 为例,介绍一下其基本结构:
最里面的一层是ResNet 最基本的结构,我们这里叫做BasicBlock
, 该 Block 由两层卷积神经网络外加一个 “短路” 联接构成。若干个 BasicBlock
又可以构建一个 ResBlock
, 4个 ResBlock
外加一个预处理层和一个全连接层,一共就构成了 18 层 (2 x 2 x 4 + 2 )的 ResNet18 结构.
4. ResNet18 代码实战
首先我们创建最基本单元 BasicBlcok
这里需要注意以下几点:
- BasicBlock 类继承自 tf.keras.layers.Layer 类。
num_filters
缩小图片的尺寸。identity_layer
必须与卷积神经网络的输出尺寸一致,这里使用 1x1 的filter 来调节。- 涉及到 batch normaisation 的记住传入training 参数,training在验证的时候需要设置为 False .
class BasicBlock(layers.Layer):
def __init__(self, num_filters, stride = 1):
super().__init__()
self.conv1 = layers.Conv2D(num_filters,(3,3),strides=stride,padding='same')
self.bn1 = layers.BatchNormalization()
self.relu = layers.ReLU()
self.conv2 = layers.Conv2D(num_filters,(3,3),strides=1,padding='same')
self.bn2 = layers.BatchNormalization()
if stride != 1:
self.identity_layer = layers.Conv2D(num_filters,(1,1),strides=stride)
else:
self.identity_layer = lambda x:x
def call(self, input, training = None):
output = self.conv1(input)
output = self.bn1(output, training=training)
output = self.relu(output)
output = self.conv2(output)
output = self.bn2(output,training=training)
identity_out = self.identity_layer(input)
output = layers.add([output,identity_out])
output = tf.nn.relu(output)
return output
然后,用基本单元构建 ResBlock 层,然后再由ResBlock 和 Pre_process 以及最后一个全链接层构建一个 ReNet 模型
这里需要注意以下几点:
- ResNet class 模型继承 keras.Model.
- Layer_dim 存储 resblock 维度信息
layers.GlobalAveragePooling2D()
不关心图片尺寸,可以在 h * w 纬度上平均尺化。- 这里模型输出是 logits 没有加 softmax 层
class ResNet(keras.Model):
def __init__(self, layer_dim, class_num): #layer_dim res18:[2,2,2,2] or res34[3,4,6,3]
super().__init__()
self.pre_process = Sequential([layers.Conv2D(64,(3,3),strides = 1, padding = 'same'),
layers.BatchNormalization(),
layers.ReLU(),
layers.MaxPool2D((2,2),strides= 1, padding = 'same')
])
self.resblock0 = self.build_resblock(64, layer_dim[0], stride = 1)
self.resblock1 = self.build_resblock(128, layer_dim[1], stride = 2)
self.resblock2 = self.build_resblock(256, layer_dim[2], stride = 2)
self.resblock3 = self.build_resblock(512, layer_dim[3], stride = 2)
self.avg_pool = layers.GlobalAveragePooling2D()
self.dense = layers.Dense(class_num)
def build_resblock(self,filter_num,basic_block_num, stride):
resblock = Sequential()
for _ in range(basic_block_num):
basic_block = BasicBlock(filter_num, stride = stride)
resblock.add(basic_block)
return resblock
def call(self, input, training = None):
output = self.pre_process(input, training = training) #[b, 64, h, w]
output = self.resblock0(output, training = training) #[b, 64, h, w]
output = self.resblock1(output, training = training) #[b, 128, h, w]
output = self.resblock2(output, training = training) #[b, 256, h, w]
output = self.resblock3(output, training = training) #[b, 512, h, w]
output = self.avg_pool(output) #[b, 512, 1,1]
output = self.dense(output) #[b, class_num]
return output
最后,ResNet18 中间是 [2, 2, 2, 2] 结构,既4个resblock, 每个resblock包涵两个BasicBlcok。 ResNet34 中间为[3, 4, 6, 3]结构。实例ResNet18 和 ResNet34 也非常简单,仅需要传入不同的 layer_dim 即可。
## ResNet 18
model = ResNet([2,2,2,2], 100)
## ResNet 34
model = ResNet([3,4,6,3], 100)
模型训练和验证过程请参考之前文章或者查看源代码,就不在这里赘述了。
相关文章
Tensorflow2.0-数据加载和预处理
Tensorflow 2.0 快速入门 —— 引入Keras 自定义模型
Tensorflow 2.0 快速入门 —— 自动求导与线性回归
Tensorflow 2.0 轻松实现迁移学习
Tensorflow入门——Eager模式像原生Python一样简洁优雅
Tensorflow 2.0 —— 与 Keras 的深度融合
首发steemit
欢迎扫描二维码关注我的微信公众号“tensorflow机器学习”,一起学习,共同进步
网友评论