目录
一、使用块的网络 VGG
1.1 AlexNet--->VGG
AlexNet最大的问题是不规整,结构不那么清晰。我如果想要变深变大,来得到更好的精度,就需要更好的设计思想。
那么,问题就是怎么样变深变大?
因此, AlexNet思路的拓展,提出了一个叫VGG块的东西。
VGG块的核心思想是:用大量的3X3的卷积层堆起来,得到VGG块,得到最后的网络。
所以为什么用的是3X3卷积层而不是5X5卷积层?
是因为VGG块也尝试过使用5X5卷积层,但是发现在同样计算开销的情况下,堆更多的3X3卷积层的效果比用少一些的5X5卷积层更好,因为5X5卷积层的计算量比3X3卷积层大。
所以VGG块使用了n层的3X3卷积层,再加上一个2X2的最大池化层。
◼ VGG网络简介
VGG网络主要证明了增加网络的深度能够在一定程度上影响网络最终的性能。VGG有两种结构,VGG16和VGG19,两者并没有本质区别,只是网络深度不一样。VGG模型中卷积核大小全部为3*3。
VGGNet是由⽜津⼤学计算机视觉组参加图像分类竞赛时提出的,VGG即Visual Geometry Group,VGGNet相对于AlexNet来说,其在深度上翻了⼀番,最深可达19层,所以叫做Very Deep。
VGG可以应用在人脸识别、图像分类等方面,分别从VGG16~VGG19。
VGG研究卷积网络深度的初衷是想搞清楚卷积网络深度是如何影响大规模图像分类与识别的精度和准确率的,最初是VGG-16号称非常深的卷积网络全称为(GG-Very-Deep-16 CNN),VGG在加深网络层数同时为了避免参数过多,在所有层都采用3x3的小卷积核,卷积层步长被设置为1。
VGG的输入被设置为224x244大小的RGB图像,在训练集图像上对所有图像计算RGB均值,然后把图像作为输入传入VGG卷积网络,使用3x3或者1x1的filter,卷积步长被固定1。
VGG全连接层有3层,根据卷积层+全连接层总数目的不同可以从VGG11 ~ VGG19,最少的VGG11有8个卷积层与3个全连接层,最多的VGG19有16个卷积层+3个全连接层.
此外VGG网络并不是在每个卷积层后面跟上一个池化层,还是总数5个池化层,分布在不同的卷积层之下,下图是VGG11 ~GVV19的结构图:
与AlexNet、LeNet一样,VGG网络可以分为两个部分:第一部分主要由卷积层和汇聚层组成,第二部分由全连接层组成。如下图所示:
VGG神经网络连续连接上图的几个VGG块(在vgg_block函数中定义)。其中有超参数变量conv_arch。该变量指定了每个VGG块里的卷积层的个数和输出通道数。全连接模块则与AlexNet中的相同。
原始VGG网络中有5个卷积块,其中前两个块各有一个卷积层,后三个块包含两个卷积层。第一个模块有64个输出通道,每个后续模块将输出通道数量翻倍,直到数字达到512。由于该网络使用8个卷积层和3个全连接层,因此它通常被称为VGG-11。
1.2 VGG架构
其实就是替换掉了AlexNet的整个卷积层的架构,替换成n个VGG块,串在一起。
可以串不同的VGG块,不同大小得到不同的架构。比如VGG-16结构,VGG-19结构。
从图中可以看出, 现在的进度,AlexNet是一个很快的网络,每秒钟大概能做5000多次计算的样子,精度其实是不高的。VGG对的提升是很大的,但是代价是会慢很多,会慢5,6倍的样子,因为VGG更深了。
VGG是一个非常占内存的网络,VGG有一系列的模型,不同的模型中,快一点的模型自然精度低一些。
1.3 总结
二、VGG网络的代码实现
2.1 VGG网络(使用自定义)
(1)VGG块的实现,
需要的超参数:重复多少个卷积层、输入通道数、输出通道数
import torch
from torch import nn
from d2l import torch as d2l
def vgg_block(num_convs,in_channels,out_channels): # 需要的超参数:卷积层个数、输入通道数、输出通道数
layers = []
for _ in range(num_convs): # 重复n次
# 每次加入卷积层
layers.append(nn.Conv2d(in_channels,out_channels,kernel_size=3,padding=1))
layers.append(nn.ReLU()) # 每层后面加入激活函数
in_channels = out_channels # 更换
layers.append(nn.MaxPool2d(kernel_size=2,stride=2)) # 最后加入一个最大池化层
# 把这些层丢到Sequential,构成一个VGG块
return nn.Sequential(*layers) # *layers表示把列表里面的元素按顺序作为参数输入函数
(2)VGG-11网络:8个卷积层, 3个全连接层
需要告诉我一个架构:一共有5块,每一次告诉这一块里面有多少个卷积,通道数是多少。
根据每一块,调用函数vgg_block进行构建,
conv_arch = ((1,64),(1,128),(2,256),(2,512),(2,512)) # 第一个参数为几层卷积,第二个参数为输出通道数
def vgg(conv_arch):
conv_blks = []
in_channels = 1
for (num_convs, out_channels) in conv_arch:
# 根据每一块,调用函数vgg_block进行构建
conv_blks.append(vgg_block(num_convs,in_channels,out_channels))
in_channels = out_channels
# 与AlexNet相同,
return nn.Sequential(*conv_blks, nn.Flatten(),
nn.Linear(out_channels * 7 * 7, 4096),nn.ReLU(), # 线性层:输入宽度为out_channels * 7 * 7
nn.Dropout(0.5), nn.Linear(4096,4096),nn.ReLU(),
nn.Dropout(0.5), nn.Linear(4096,10))
(3)观察每个层输出的形状,
net = vgg(conv_arch)
# 观察每个层输出的形状
X = torch.randn(size=(1,1,224,224))
for blk in net:
X = blk(X)
print(blk.__class__.__name__,'output shape:\t', X.shape) # VGG使得高宽减半,通道数加倍
从图中我们可以看得到,
- 首先输入224X224进来,第一块就使得高宽减半成112,通道数拉到了64。
- 然后第二块使得通道数翻倍成128,高宽再减半成54。
- 然后一直翻倍减半,翻倍减半,
- 直到最后一层第五层的时候,没有翻倍减半了。
整体的思想就是,我把一个网络分成5块,每块把通道数翻倍,高宽减半,这是我们经常在神经网络用到的一个设计模式。
(4)由于VGG-11比AlexNet计算量更大,因此2我们构建了一个通道数较少的网络来训练,所以把所有通道数除以4。
参数上我们还是跑10次,批量大小为128,学习率稍微大一些为0.05,
# 由于VGG-11比AlexNet计算量更大,因此构建了一个通道数较少的网络,所以把所有通道数除以4
ratio = 4
small_conv_arch = [(pair[0], pair[1]//ratio) for pair in conv_arch] # 所有输出通道除以4
net = vgg(small_conv_arch)
lr, num_epochs, batch_size = 0.05, 10, 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size,resize=224)
d2l.train_ch6(net,train_iter,test_iter,num_epochs,lr,d2l.try_gpu())
从图中我们可以看得到,VGG-11已经是VGG里面比较小的网络了,通道数已经除以4了,认为是计算量减少了16倍,
计算复杂度=输入X输出
计算量减少了16倍的情况下,还是比AlexNet慢,要慢一倍。但是VGG-11的精度还不错,AlexNet是0.88,但是它是0.932。
意思是就算我用了一个VGG里面比较小的网络VGG-11,精度还是有不小的提升,用了更小的窗口但更深。