PyTorch深度学习实战 | 典型卷积神经网络
Posted TiAmo zhang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PyTorch深度学习实战 | 典型卷积神经网络相关的知识,希望对你有一定的参考价值。
在深度学习的发展过程中,出现了很多经典的卷积神经网络,它们对深度学习的学术研究和工业生产都起到了巨大的促进作用,如VGG、ResNet、Inception和DenseNet等,很多投入实用的卷积神经都是在它们的基础上进行改进的。初学者应从试验开始,通过阅读论文和实现代码(tensorflow.keras.applications包中实现了很多有影响力的神经网络模型的源代码)来全面了解它们。下文简要讨论两个有代表性的卷积神经网络,它们都是卷积层、池化层、全连接层等的不同组合。
01、VGG-16,VGG-19
VGG-16[32]是牛津大学的Visual Geometry Group在2015年发布的共16层的卷积神经网络,有约1.38亿个网络参数。该网络常被初学者用来学习和体验卷积神经网络。
VGG-16模型是针对ImageNet挑战赛设计的,该挑战赛的数据集为ILSVRC-2012图像分类数据集。ILSVRC-2012图像分类数据集的训练集有总共有1281167张图片,分为1000个类别,它的验证集有50000张图片样本,每个类别50个样本。
ILSVRC-2012图像分类数据集是2009年开始创建的ImageNet图像数据集的一部分。基于该图像数据集举办了具有很大影响力的ImageNet挑战赛,很多新模型就是在该挑战赛上发布的。
图 1 VGG-16模型的网络结构
VGG-16模型的网络结构如图1所示,从左侧输入大小为224×224×3的彩色图片,在右侧输出该图片的分类。
输入层之后,先是2个大小为3×3、卷积核数为64、步长为1、零填充的卷积层,此时的数据维度大小为224×224×64,在水平方向被拉长了。
然后是1个大小为2×2的最大池化层,将数据的维度降为112×112×64,再经过2个大小为3×3、卷积核数为128、步长为1、零填充的卷积层,再一次在水平方向上被拉长,变为112×112×128。
然后是1个大小为2×2的最大池化层,和3个大小为3×3、卷积核数为256、步长为1、零填充的卷积层,数据维度变为56×56×256。
然后是1个大小为2×2的最大池化层,和3个大小为3×3、卷积核数为512、步长为1、零填充的卷积层,数据维度变为28×28×512。
然后是1个大小为2×2的最大池化层,和3个大小为3×3、卷积核数为512、步长为1、零填充的卷积层,数据维度变为14×14×512。
然后是1个大小为2×2的最大池化层,数据维度变为7×7×512。
然后是1个Flatten层将数据拉平。
最后是3个全连接层,节点数分别为4096、4096和1000。
除最后一层全连接层采用Softmax激活函数外,所有卷积层和全连接层都采用relu激活函数。
从上面网络结构可见,经过卷积层,通道数量不断增加,而经过池化层,数据的长度和宽度不断减少。
Visual Geometry Group后又发布了19层的VGG-19模型。
TensorFlow实现了VGG-16模型和VGG-19模型 。TensorFlow还提供了用ILSVRC-2012-CLS图像分类数据集预先训练好的VGG-16和VGG-19模型,下面给出一个用预先训练好的模型来识别一幅图片(图2)的例子。
图2 试验用的小狗照片
代码清单1 VGG-19预训练模型应用(vgg19_app.py)
1. import tensorflow.keras.applications.vgg19 as vgg19
2. import tensorflow.keras.preprocessing.image as imagepre
3.
4. # 加载预训练模型
5. model = vgg19.VGG19(weights='E:\\\\MLDatas\\\\vgg19_weights_tf_dim_ordering_tf_kernels.h5', include_top=True) # 加载预先下载的模型
6. # 加载图片并转换为合适的数据形式
7. image = imagepre.load_img('116.jpg', target_size=(224, 224))
8. imagedata = imagepre.img_to_array(image)
9. imagedata = imagedata.reshape((1,) + imagedata.shape)
10.
11. imagedata = vgg19.preprocess_input(imagedata)
12. prediction = model.predict(imagedata) # 分类预测
13. results = vgg19.decode_predictions(prediction, top=3)
14. print(results)
15. #[[('n02113624', 'toy_poodle', 0.6034094), ('n02113712', 'miniature_poodle', 0.34426507), ('n02113799', 'standard_poodle', 0.0124355545)]]
可见,图片为toy poodle的概率最大,为0.6。
02、残差网络
随着网络层次的加深,训练集的损失函数可能会呈现出先下降再上升的现象,称为网络退化(degradation)现象。残差网络(ResNet)[33]提出了抑制梯度消散、网络退化来加速训练收敛的方法,克服了层数多导致的收敛慢、甚至无法收敛的问题,使网络的层数得以增加。
残差单元是残差网络的基本组成部分,它的特点是有一条跨层的短接。图3示例了一个残差单元。该单元有两条传递路径,除了常规的卷积、批标准化、激活处理路径外,还有一条跨层的直接传递路径。
图3 残差单元示例
残差网络一般要由很多残差单元首尾连接而成。残差网络的思想是通过跨层的短接,在误差反向传播时,去掉不变的主体部分,从而突出微小的变化,使得网络对误差更加敏感。通过短接还使得误差消散问题得到了较好的解决。试验结果证明残差网络具有良好的学习效果。
图3所示残差单元在TensorFlow框架下的实现见代码清单2,其中第28行是将两条处理路径传来的数据相加。该代码来自tensorflow.keras.applications包,该包包含了许多经典模型的实现代码,值得读者仔细分析。
代码清单 2残差单元[1]
1. def block1(x, filters, kernel_size=3, stride=1, conv_shortcut=True, name=None):
2. bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1
3. if conv_shortcut:
4. shortcut = layers.Conv2D(
5. 4 * filters, 1, strides=stride, name=name + '_0_conv')(
6. x)
7. shortcut = layers.BatchNormalization(
8. axis=bn_axis, epsilon=1.001e-5, name=name + '_0_bn')(
9. shortcut)
10. else:
11. shortcut = x
12. x = layers.Conv2D(filters, 1, strides=stride, name=name + '_1_conv')(x)
13. x = layers.BatchNormalization(
14. axis=bn_axis, epsilon=1.001e-5, name=name + '_1_bn')(
15. x)
16. x = layers.Activation('relu', name=name + '_1_relu')(x)
17. x = layers.Conv2D(
18. filters, kernel_size, padding='SAME', name=name + '_2_conv')(
19. x)
20. x = layers.BatchNormalization(
21. axis=bn_axis, epsilon=1.001e-5, name=name + '_2_bn')(
22. x)
23. x = layers.Activation('relu', name=name + '_2_relu')(x)
24. x = layers.Conv2D(4 * filters, 1, name=name + '_3_conv')(x)
25. x = layers.BatchNormalization(
26. axis=bn_axis, epsilon=1.001e-5, name=name + '_3_bn')(
27. x)
28. x = layers.Add(name=name + '_add')([shortcut, x])
29. x = layers.Activation('relu', name=name + '_out')(x)
30. return x
03、源码展示
链接: https://pan.baidu.com/s/1kG88Z39otL7GrVhiSOJlqA?pwd=6yb8 提取码: 6yb8
深度学习:《PyTorch入门到项目实战》卷积神经网络:填充(padding)和步幅(stride)
【深度学习】:《PyTorch入门到项目实战》(十二)填充(padding)和步幅(stride)
- ✨本文收录于【深度学习】:《PyTorch入门到项目实战》专栏,此专栏主要记录如何使用
PyTorch
实现深度学习笔记,尽量坚持每周持续更新,欢迎大家订阅!- 🌸个人主页:JoJo的数据分析历险记
- 📝个人介绍:小编大四统计在读,目前保研到统计学top3高校继续攻读统计研究生
- 💌如果文章对你有帮助,欢迎✌
关注
、👍点赞
、✌收藏
、👍订阅
专栏- 参考资料:本专栏主要以沐神《动手学深度学习》为学习资料,记录自己的学习笔记,能力有限,如有错误,欢迎大家指正。同时沐神上传了的教学视频和教材,大家可以前往学习。
- 视频:动手学深度学习
- 教材:动手学深度学习
文章目录
前言
在之前,我们介绍了卷积核对输入特征的影响。假设输入特征为 n × n n\\times n n×n,核形状为 f × f f\\times f f×f,那么经过卷积核作用后,得到的输出形状为 ( n − f + 1 ) × ( n − f + 1 ) (n-f+1)\\times (n-f+1) (n−f+1)×(n−f+1)。可以看出,通常情况下输出特征会由于卷积核的作用而减小。而深度神经网络中,由于卷积核的作用,会导致我们的输出过早的变的很小,导致我们无法构建深层的神经网络。本章介绍另外两个影响输出形状的方法,扩充(padding)和步幅(stride)。
- 有时候,输出远远小于输入,这是因为卷积核的影响,而在原始图像较小的情况下,任意丢失很多信息,这个时候我们需要使用填充是解决此问题。
- 有时,我们可能希望大幅降低图像的宽度和高度。例如,我们发现一个图像实在是太大了。这个时候使用步幅可以快速将输出变小。
1. padding
为了构建深度神经网络,你需要学会使用的一个基本的卷积操作就是padding。首先让我们来回忆一下卷积是如何计算的:
这其实有两个缺陷:
- 第一个是如果每一次使用一个卷积操作,我们的图像都会缩小。 例如我们从 6x6 通过一个 3x3的卷积核,做不了几次卷积,我们的图片就会变得非常小,也许它会缩小到只有1x1。
- 第二个缺陷是图片角落或者边际上的像素只会在输出中被使用一次 因为它只通过那个3x3的过滤器(filter)一次 然而图片中间的一个像素,会有许多3x3的过滤器(filter)在那个像素上重叠 所以相对而言 角落或者边界上的像素被使用的次数少很多,这样我们就丢失了许多图片上靠近边界的信息。
所以为了同时解决上述的两个问题。我们能做的是在使用卷积操作前,对图片进行填充,通常是用0来进行填充,具体如下所示。
我们可以沿着图像边缘再填充一层像素。这样那么3×3的图像就被我们填充成了一个5×5的图像。如果你用2×2的卷积核对这个5×5的图像卷积,我们得到的输出就不是2×2,而是4×4的图像,你就得到了一个尺寸比原始图像3×3还大图像。习惯上,我们都用用0去填充,如果
p
p
p是填充参数,在这个案例中,
p
=
1
p=1
p=1,因为我们在周围都填充了一个像素点,输出也就变成了
(
n
+
2
p
−
f
+
1
)
×
(
n
+
2
p
−
f
+
1
)
(n+2p-f+1)×(n+2p-f+1)
(n+2p−f+1)×(n+2p−f+1)。所以,要是我们想要保持图像大小不变,则意味着
2
p
−
f
+
1
=
0
2p-f+1=0
2p−f+1=0,则
p
=
f
−
1
2
p=\\fracf-12
p=2f−1,在后面我们的卷积核通常会设置为奇数。
为了指定卷积操作中的padding,我们可以指定 p p p的值。以上就是padding,下面我们讨论一下如何在卷积中设置步长。
2.步幅(stride)
卷积窗口从输入张量的左上角开始,向下、向右滑动。 在前面的例子中,我们默认每次滑动一个元素。 但是,有时候为了高效计算或是缩减采样次数,卷积窗口可以跳过中间位置,每次滑动多个元素。卷积中的步幅是另一个构建卷积神经网络的基本操作,例如,下面是一个步幅为3的情况。
如果我们用一个 f × f f×f f×f的过滤器卷积一个 n × n n×n n×n的图像,padding为 p p p,步幅为 s s s,在这个例子中 s = 3 s=3 s=3,因为现在我们不是一次移动一个步长,而是一次移动 s s s步,输出于是变为 [ n + 2 p − f s + 1 ] [ × n + 2 p − f s + 1 ] [\\fracn+2p - fs + 1] [\\times \\fracn+2p - fs + 1] [sn+2p−f+1][×sn+2p−f+1]。[] 表示向下取整。
3.代码实现
3.1 padding实现
在pytorch
中,padding和stride的都可以在nn
中实现
# 导入相关库
import torch
from torch import nn
# 定义计算卷积层函数
def comp_conv2d(conv2d, X):
# 这里的(1,1)表示批量大小和通道数都是1
X = X.reshape((1, 1) + X.shape)
Y = conv2d(X)
# 省略前两个维度:批量大小和通道
return Y.reshape(Y.shape[2:])
# 请注意,padding参数这里每边都填充了1行或1列,因此总共添加了2行或2列
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)#因此这里相当于是一个3×3的kernel加padding=1,那么根据我们的公式可以得到,最终得到的输出和输入一致
X = torch.rand(size=(8, 8))
comp_conv2d(conv2d, X).shape
torch.Size([8, 8])
3.2 stride实现
步幅使用stride参数实现,具体代码如下,设置步幅为2,padding为1,kernel_size为3×3,那么这样根据公式 [ n + 2 p − f s + 1 ] [\\fracn+2p-fs+1] [sn+2p−f+1]这里n为8,p=1,f=3,s=2,会返回一个4×4的输出。
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
comp_conv2d(conv2d, X).shape
torch.Size([4, 4])
本章的介绍到此介绍,如果文章对你有帮助,请多多点赞、收藏、评论、关注支持!!
以上是关于PyTorch深度学习实战 | 典型卷积神经网络的主要内容,如果未能解决你的问题,请参考以下文章