AlexNet比LeNet更深更大,带来了更好的精度,那么是不是再深一些再大一些,我们就会更好?
更深更大,可以通过更多的全连接层(太贵)、更多的卷积层以及将卷积层组成块来实现。
VGG思想:将小块先组成大块,最后再去组合。
VGG块:用大量的3x3(一般再大效果会不好)的卷积层堆起来加一个池化层做VGG块,然后用这些VGG块组成网络。
所谓的VGG网络,其实就是将AlexNet网络中看起来不规则的池化和卷积层规则化了一下,让网络看上去更加规则。
(但我还是感觉是在水论文,这两个的本质本身是一样的……)
目前三种网络:
LeNet:(1985)
2卷积层+池化层
2全连接层
AlexNet:(2012)
更大更深的网络
加入了ReLU,Dropout,数据增强
VGG:(2014)
更大更深的AlexNet(重复的VGG块)
结果
首先说明一下,这里将所有层的通道数缩小了4,也就是这是一个简化版的VGG网络,见代码详情。
沐神结果:
可以看到,即便是简化版的VGG网络,精确度却达到了91%,比AlexNet要高一些,那么如果不简化,精确度一定会更高。
当然,在这里我仍然不太认可VGG的成就,其本质不过是多加了几层卷积层而已,当年AlexNet要是多加几层卷积层,也能上90%,VGG只不过管理上方便一点。“更容易去管理每一层网络”,这是我认为VGG唯一的贡献,除此之外,我还是觉得他就是在水论文。
我的结果(我与沐神不同的是我最后两层卷积层的通道数是沐神的二倍)
Q&A
1、在以后发论文、出成果的时候,尽量用简单的东西,这样才可能被人们更广泛更重复地去使用。
代码
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):
layers.append(nn.Conv2d(in_channels, out_channels,kernel_size=3, padding=1)) # 加入卷积层
layers.append(nn.ReLU())
in_channels = out_channels # 第一层之后,将in_channels改为out_channels,因为后序输出作为输入
layers.append(nn.MaxPool2d(kernel_size=2,stride=2)) # 最后加一层池化
return nn.Sequential(*layers) # 这便是我们最后的一个VGG块(本质上其实就是一个多层网络,和AlexNet换汤不换药的感觉……)
conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 1024)) # 5个块
# 224除以2的5次方是7,不能在除了,所以就五块VGG(每块VGG最后的pool会将样本高宽缩小一半)
# 第一个数字是卷积层数目,第二个数字是输出通道数目
def vgg(conv_arch):
conv_blks = []
in_channels = 1
# 卷积层部分
for (num_convs, out_channels) in conv_arch:
conv_blks.append(vgg_block(num_convs, in_channels, out_channels))
in_channels = out_channels # 第一层之后,将in_channels改为out_channels,因为后序输出作为输入
# 后面就很简单了,把卷积池化叠起来,最后拉成一个向量,随后在做相应的全连接层和ReLu激活,最后以对应的类别输出即可
return nn.Sequential(
*conv_blks, nn.Flatten(),
# 全连接层部分
nn.Linear(out_channels * 7 * 7, 4096), nn.ReLU(), nn.Dropout(0.5),
nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(0.5),
nn.Linear(4096, 10))
net = vgg(conv_arch)
X = torch.randn(size=(1, 1, 224, 224))
# 这里输出的形状,是以VGG块为单元输出的,相对AlexNet来说,更加清晰一些
for blk in net:
X = blk(X)
print(blk.__class__.__name__,'output shape:\t',X.shape)
# [由于VGG-11比AlexNet计算量更大,因此我们构建了一个通道数较少的网络],足够用于训练Fashion-MNIST数据集
# 这里的操作是将VGG块中的通道数统一除以4
ratio = 4
small_conv_arch = [(pair[0], pair[1] // ratio) for pair in conv_arch]
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())