赞
踩
虽然AlexNet证明深层神经网络卓有成效,但它没有提供一个通用的模板来指导后续的研究人员设计新的网络。研究人员开始从单个神经元的角度思考问题,发展到整个层,现在又转向块(不断使用重复层的模式)。
经典卷积神经网络的基本组成部分是下面的这个序列:
一个VGG块与之类似,由一系列卷积层组成,后面再加上用于空间下采样的最大汇聚层。在最初的VGG论文中,作者使用了带有 3×3 卷积核、填充为1(保持高度和宽度)的卷积层,和带有 2×2 汇聚窗口、步幅为2(每个块后的分辨率减半)的最大汇聚层。
下面代码vgg_block()实现了一个VGG块,该函数有三个参数,分别对应于卷积层的数量num_convs、输入通道的数量in_channels 和输出通道的数量out_channels.:
def vgg_block(nums_conv2d,in_channels,out_channels):
blocks = []
for _ in range(nums_conv2d):
blocks.append(nn.Conv2d(in_channels=in_channels,out_channels=out_channels,kernel_size=3,padding=1))
blocks.append(nn.ReLU())
in_channels = out_channels
blocks.append(nn.MaxPool2d(kernel_size=2,stride=2))
return nn.Sequential(*blocks)
与AlexNet、LeNet一样,VGG网络可以分为两部分:第一部分主要由卷积层和汇聚层组成,第二部分由全连接层组成,如下图所示。卷积块的作用主要是替换AlexNet网络前面五层卷积层,因为AlexNet卷积层的卷积核大小,通道数,步幅数设置的没有规律,而使用VGG块更有利于网络更加简洁,从而使网络架构不会那么复杂
原始VGG网络有5个卷积块,其中前两个块各有一个卷积层,后三个块各包含两个卷积层。 第一个模块有64个输出通道,每个后续模块将输出通道数量翻倍,直到该数字达到512。由于该网络使用8个卷积层和3个全连接层,因此它通常被称为VGG-11。
VGG模型代码:
def vgg(conv2d_arch): VGG_blocks = [] in_channels = 1 #for循环来添加每个卷积块,卷积层模块 for nums_conv2d,out_channels in conv2d_arch: VGG_blocks.append(vgg_block(nums_conv2d=nums_conv2d,in_channels=in_channels,out_channels=out_channels)) in_channels = out_channels #下一层卷积层输入channels数为上一层卷积层输出channels return nn.Sequential(*VGG_blocks, nn.Flatten(), # 全连接层模块则与AlexNet中的相同。in_channels数为最后一层卷积层的输出channels(然后赋值给in_channels,在for循环里面赋值进行的,作为下一层Flatten层的输入,铺平展开后,输入到全连接层,因此全连接层输入in_features=in_channels*7*7) nn.Linear(in_features=in_channels*7*7,out_features=4096),#7*7是因为输入尺寸是224*224,经过每个卷积块后尺寸都会除以2,经过五个卷积块后,则输出尺寸大小为224/2/2/2/2/2=7 nn.ReLU(), nn.Dropout(0.5), nn.Linear(in_features=4096,out_features=4096), nn.ReLU(), nn.Dropout(), nn.Linear(in_features=4096,out_features=10)) X = torch.randn(size=(1,1,224,224)) #conv2d_arch含有五个VGG块,指定了每个VGG块里卷积层个数和输出通道数,为一个超参数 conv2d_arch = ((1,64),(1,128),(2,256),(2,512),(2,512)) #ratio = 4 #small_conv2d_arch = ((pair[0],pair[1] // ratio) for pair in conv2d_arch) VGGNet = vgg(conv2d_arch) #构建一个高度和宽度为224的单通道数据样本X,来观察每个层输出的形状 for layer in VGGNet: X = layer(X) print(layer.__class__.__name__,'output shape : \t',X.shape)
每层尺寸输出结果如下:
Sequential output shape: torch.Size([1, 64, 112, 112])
Sequential output shape: torch.Size([1, 128, 56, 56])
Sequential output shape: torch.Size([1, 256, 28, 28])
Sequential output shape: torch.Size([1, 512, 14, 14])
Sequential output shape: torch.Size([1, 512, 7, 7])
Flatten output shape: torch.Size([1, 25088])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 10])
从上面的输出结果看出VGG在经过每个卷积块(每个卷积块内部最后面有一个最大池化层,步幅为2,kernel size为2*2)后输出形状尺寸的高度和宽度减半,经过五个卷积块后,输出尺寸为输入尺寸除以五次2,也即是要除以32等于7,因此最终输出尺寸形状高度和宽度都为7。最后再展平表示,送入全连接层处理。
import d2l.torch import torch from torch import nn def vgg_block(nums_conv2d,in_channels,out_channels): blocks = [] for _ in range(nums_conv2d): blocks.append(nn.Conv2d(in_channels=in_channels,out_channels=out_channels,kernel_size=3,padding=1)) blocks.append(nn.ReLU()) in_channels = out_channels blocks.append(nn.MaxPool2d(kernel_size=2,stride=2)) return nn.Sequential(*blocks) def vgg(conv2d_arch): VGG_blocks = [] in_channels = 1 #for循环来添加每个卷积块,卷积层模块 for nums_conv2d,out_channels in conv2d_arch: VGG_blocks.append(vgg_block(nums_conv2d=nums_conv2d,in_channels=in_channels,out_channels=out_channels)) in_channels = out_channels #下一层卷积层输入channels数为上一层卷积层输出channels return nn.Sequential(*VGG_blocks, nn.Flatten(), # 全连接层模块则与AlexNet中的相同。in_channels数为最后一层卷积层的输出channels(然后赋值给in_channels,在for循环里面赋值进行的,作为下一层Flatten层的输入,铺平展开后,输入到全连接层,因此全连接层输入in_features=in_channels*7*7) nn.Linear(in_features=in_channels*7*7,out_features=4096),#7*7是因为输入尺寸是224*224,经过每个卷积块后尺寸都会除以2,经过五个卷积块后,则输出尺寸大小为224*2*2*2*2*2=7 nn.ReLU(), nn.Dropout(0.5), nn.Linear(in_features=4096,out_features=4096), nn.ReLU(), nn.Dropout(), nn.Linear(in_features=4096,out_features=10)) X = torch.randn(size=(1,1,224,224)) #conv2d_arch含有五个VGG块,指定了每个VGG块里卷积层个数和输出通道数,为一个超参数 conv2d_arch = ((1,64),(1,128),(2,256),(2,512),(2,512)) ratio = 4 small_conv2d_arch = ((pair[0],pair[1] // ratio) for pair in conv2d_arch)#由于VGG-11比AlexNet计算量更大,因此我们构建了一个通道数较少的网络,足够用于训练Fashion-MNIST数据集。 VGGNet = vgg(small_conv2d_arch) #构建一个高度和宽度为224的单通道数据样本X,来观察每个层输出的形状 for layer in VGGNet: X = layer(X) print(layer.__class__.__name__,'output shape : \t',X.shape) lr,num_epochs,batch_size = 0.05,20,100 #除了使用比AlexNet略高的学习率外,模型训练过程与 AlexNet类似 train_iter,test_iter = d2l.torch.load_data_fashion_mnist(batch_size=batch_size,resize=224) #调用d2l里面封装好的训练模型函数,这个训练函数跟前面LeNet里面训练模型函数一模一样 d2l.torch.train_ch6(VGGNet,train_iter=train_iter,test_iter=test_iter,num_epochs=num_epochs,lr=lr,device=d2l.torch.try_gpu())
VGG模型训练和测试输出结果如下图所示:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。