2014年,牛津大学计算机视觉组(Visual Geometry Group)和Google DeepMind公司一起研发了新的卷积神经网络,并命名为VGGNet。VGGNet是比AlexNet更深的深度卷积神经网络,该模型获得了2014年ILSVRC竞赛的第二名,第一名是GoogLeNet。
论文原文:Very Deep Convolutional Networks for Large-Scale Image Recognition
本文将首先介绍 VGGNet 的基本结构,然后讲述VGGNet的创新点,最后给出了基于pytorch的VGGNet代码实现。
一、 网络结构
VGG 的结构与 AlexNet 类似,区别是深度更深,但形式上更加简单,提出了模块化的概念。VGG由5层卷积层、3层全连接层、1层softmax输出层构成,层与层之间使用maxpool(最大化池)分开,所有隐藏层的激活单元都采用ReLU。作者在原论文中,根据卷积层不同的子层数量,设计了A、A-LRN、B、C、D、E这6种网络结构。
VGGNet包含很多级别的网络,深度从11层到19层不等。为了解决初始化(权重初始化)等问题,VGG采用的是一种Pre-training的方式,先训练浅层的的简单网络VGG11,再复用VGG11的权重初始化VGG13,如此反复训练并初始化VGG19,能够使训练时收敛的速度更快。比较常用的是VGGNet-16和VGGNet-19。
二、创新点
1. 使用多个小卷积核构成的卷积层代替较大的卷积层
两个3x3卷积核的堆叠相当于5x5卷积核的视野,三个3x3卷积核的堆叠相当于7x7卷积核的视野。一方面减少参数,另一方面拥有更多的非线性变换,增加了CNN对特征的学习能力。VGGNet还提出,用的卷积核越小,效果会越好(越小的话,可以有更多的卷积核数量,网络构建会越深)。
感受野是什么呢?在卷积神经网络中,决定某一层输出结果中一个元素所对应的输入层的区域大小,被称作感受野。通俗的来说就是,输出特征图上的一个单元对应输入层上的区域大小。
2. 引入1*1的卷积核
在不影响输入输出维度的情况下,引入更多非线性变换,降低计算量,同时,还可以用它来整合各通道的信息,并输出指定通道数。并且在网络测试阶段,将训练阶段的3个全连接替换为3个卷积,测试重新用训练时的参数,使得测试得到的全卷积网络因为没有全连接的限制,因而可以接收任意宽或高的输入。
3. 预训练策略
训练时,先训练级别简单(层数较浅)的VGGNet的A级网络,然后使用A网络的权重来初始化后面的复杂模型,加快训练的收敛速度;
4. 采用Multi-Scale方法来做数据增强
在训练时,将同一张图片缩放到不同的尺寸,在随机剪裁到224*224的大小,能够增加数据量。在预测时,将同一张图片缩放到不同尺寸做预测,最后取平均值。增加训练的数据量,防止模型过拟合。
三、 代码
import torch.nn as nn
import torch.utils.model_zoo as model_zoo
import math
__all__ = [
'VGG', 'vgg11', 'vgg11_bn', 'vgg13', 'vgg13_bn', 'vgg16', 'vgg16_bn',
'vgg19_bn', 'vgg19',
]
model_urls = {
'vgg11': 'https://download.pytorch.org/models/vgg11-bbd30ac9.pth',
'vgg13': 'https://download.pytorch.org/models/vgg13-c768596a.pth',
'vgg16': 'https://download.pytorch.org/models/vgg16-397923af.pth',
'vgg19': 'https://download.pytorch.org/models/vgg19-dcbb9e9d.pth',
}
class VGG(nn.Module):
def __init__(self, features, num_classes=1000):
super(VGG, self).__init__()
self.features = features
self.classifier = nn.Sequential(
nn.Linear(512 * 7 * 7, 4096),
nn.ReLU(inplace=True),
nn.Dropout(),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),
nn.Dropout(),
nn.Linear(4096, num_classes),
)
self._initialize_weights()
def forward(self, x):
x = self.features(x)
x = x.view(x.size(0), -1)
x = self.classifier(x)
return x
def _initialize_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
m.weight.data.normal_(0, math.sqrt(2. / n))
if m.bias is not None:
m.bias.data.zero_()
elif isinstance(m, nn.BatchNorm2d):
m.weight.data.fill_(1)
m.bias.data.zero_()
elif isinstance(m, nn.Linear):
n = m.weight.size(1)
m.weight.data.normal_(0, 0.01)
m.bias.data.zero_()
def make_layers(cfg, batch_norm=False):
layers = []
in_channels = 3
for v in cfg:
if v == 'M':
layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
else:
conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
if batch_norm:
layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]
else:
layers += [conv2d, nn.ReLU(inplace=True)]
in_channels = v
return nn.Sequential(*layers)
cfg = {
'A': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
'B': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
'D': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],
'E': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
}
def vgg11(pretrained=False, model_root=None, **kwargs):
"""VGG 11-layer model (configuration "A")"""
model = VGG(make_layers(cfg['A']), **kwargs)
if pretrained:
model.load_state_dict(model_zoo.load_url(model_urls['vgg11'], model_root))
return model
def vgg11_bn(**kwargs):
"""VGG 11-layer model (configuration "A") with batch normalization"""
kwargs.pop('model_root', None)
return VGG(make_layers(cfg['A'], batch_norm=True), **kwargs)
def vgg13(pretrained=False, model_root=None, **kwargs):
"""VGG 13-layer model (configuration "B")"""
model = VGG(make_layers(cfg['B']), **kwargs)
if pretrained:
model.load_state_dict(model_zoo.load_url(model_urls['vgg13'], model_root))
return model
def vgg13_bn(**kwargs):
"""VGG 13-layer model (configuration "B") with batch normalization"""
kwargs.pop('model_root', None)
return VGG(make_layers(cfg['B'], batch_norm=True), **kwargs)
def vgg16(pretrained=False, model_root=None, **kwargs):
"""VGG 16-layer model (configuration "D")"""
model = VGG(make_layers(cfg['D']), **kwargs)
if pretrained:
model.load_state_dict(model_zoo.load_url(model_urls['vgg16'], model_root))
return model
def vgg16_bn(**kwargs):
"""VGG 16-layer model (configuration "D") with batch normalization"""
kwargs.pop('model_root', None)
return VGG(make_layers(cfg['D'], batch_norm=True), **kwargs)
def vgg19(pretrained=False, model_root=None, **kwargs):
"""VGG 19-layer model (configuration "E")"""
model = VGG(make_layers(cfg['E']), **kwargs)
if pretrained:
model.load_state_dict(model_zoo.load_url(model_urls['vgg19'], model_root))
return model
def vgg19_bn(**kwargs):
"""VGG 19-layer model (configuration 'E') with batch normalization"""
kwargs.pop('model_root', None)
return VGG(make_layers(cfg['E'], batch_norm=True), **kwargs)
参考资料:
CNN经典网络模型(三):VGGNet简介及代码实现(PyTorch超详细注释版)_vggnet是哪年发明的-CSDN博客https://blog.csdn.net/qq_43307074/article/details/126027852
【论文必读#4:VGGNet】小卷积核成就一代名模,视觉领域重要里程碑_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1cT411T7uL?spm_id_from=333.788.videopod.sections&vd_source=0dc0c2075537732f2b9a894b24578eed
CNN经典:VGGNet网络详解与PyTorch实现【含完整代码】 - 知乎https://zhuanlan.zhihu.com/p/658741272
深度学习图像处理之VGG网络模型 (超级详细)_vgg模型-CSDN博客https://blog.csdn.net/BIgHAo1/article/details/121105934