一、论文解读
1.1、基本信息
-
作者:Karen Simonyan 和 Andrew Zisserman(牛津大学 Visual Geometry Group)
-
发表:ILSVRC 2014 参赛论文,最终版本为 ICLR 2015 会议论文
-
核心贡献:通过堆叠小卷积核(3×3)构建更深的卷积网络(VGG),显著提升了大规模图像分类与定位任务的性能。
1.2、论文概述
主要研究了卷积神经网络(ConvNet)的深度对其在大规模图像识别任务中准确率的影响。 他们的主要贡献在于,通过使用非常小的 (3x3) 卷积滤波器构建不同深度的网络,并对其进行详尽的评估,结果表明,将网络深度增加到 16-19 层可以显著提高性能。 基于这些发现,他们的团队在 2014 年的 ImageNet 挑战赛中,分别在定位和分类任务中获得了第一和第二名。 此外,论文还展示了这些网络学到的图像特征具有很好的泛化能力,在其他数据集上也能达到当前最优的结果。 为了促进计算机视觉领域对深度视觉特征的进一步研究,作者公开了他们表现最好的两个 ConvNet 模型。
1.3、主要贡献
-
深度是关键: 论文的主要贡献是证明了网络深度对图像识别准确率的重要性。 作者们发现,更深的网络结构(最多 19 个权重层)比浅层网络表现更好。
-
小卷积核的优势: 论文中一个关键的设计选择是使用非常小的 3x3 卷积核。 多个连续的 3x3 卷积层可以获得与更大卷积核相同的感受野,但参数更少,并且引入了更多的非线性激活函数。
-
网络结构设计: 论文中提出了一系列具有相似结构但深度不同的 ConvNet。 这些网络结构都遵循一个通用的设计,即多层卷积层后接全连接层。
-
实验结果: 论文在 ILSVRC-2012 数据集上进行了大量的实验。 实验结果清楚地展示了网络深度和模型性能之间的正相关性。
1.4、主要内容
1.4.1、核心思想
-
深度的重要性:通过实验证明,增加网络深度(16-19 层)能显著提升模型性能。
-
小卷积核的优势:使用 3×3 卷积核堆叠替代大卷积核(如 5×5 或 7×7),在保持相同感受野的同时减少参数数量,增强非线性表达能力。感受野计算:
-
两个 3×3 卷积层等效于 5×5 感受野,三个 3×3 等效于 7×7。
-
1.4.2、网络结构(VGG 配置)
-
通用架构:
-
输入:固定尺寸 224×224 RGB 图像,仅做均值归一化。
-
卷积层:均使用 3×3 卷积核,步长 1,填充 1(保持空间分辨率)。
-
池化层:5 个最大池化层(2×2 窗口,步长 2)。
-
全连接层:3 层(前两层 4096 通道,最后一层 1000 通道,对应 ILSVRC 1000 类分类)。
-
-
具体配置(表 1):
-
A 到 E:深度从 11 层(8 卷积 + 3 全连接)到 19 层(16 卷积 + 3 全连接)。
-
关键差异:
-
配置 C 引入 1×1 卷积层(增加非线性,不影响感受野)。
-
配置 D 和 E 进一步增加卷积层数,达到最佳性能。
-
-
1.4.3、训练与评估
-
训练策略:
-
数据增强:随机裁剪、水平翻转、多尺度训练(S ∈ [256, 512])。
-
参数初始化:浅层网络(如配置 A)随机初始化,深层网络复用浅层权重。
-
优化:动量 SGD(学习率初始为 10−210−2,随验证集性能调整)。
-
-
测试策略:
-
密集评估:将全连接层转为卷积层,直接在整张图像上滑动计算。
-
多裁剪评估:从图像中提取多个区域预测,结果平均。
-
多尺度融合:不同缩放比例的结果集成,提升鲁棒性。
-
1.4.4、实验结果
-
ILSVRC-2012 分类任务:
-
最佳单模型(配置 E,19 层)的 Top-5 错误率为 7.1%。
-
多模型融合后,Top-5 错误率降至 6.8%,优于同期 GoogLeNet(6.7%)。
-
-
定位任务:
-
使用配置 D(16 层),通过回归预测边界框,Top-5 定位错误率 25.3%,赢得 ILSVRC 2014 定位冠军。
-
-
泛化能力:
-
PASCAL VOC:mAP 达 89.7%(VOC-2007)和 89.3%(VOC-2012)。
-
Caltech-256:平均分类准确率 86.2%,显著优于浅层模型。
-
1.5、创新点与影响
-
深度优先:首次系统性地验证了深度对卷积网络性能的关键作用。
-
小卷积核设计:成为后续模型(如 ResNet)的基础设计范式。
-
开源模型:公开了 VGG16 和 VGG19 的预训练权重,推动社区研究。
1.6、重要意义
这篇论文在计算机视觉领域产生了深远的影响。 它确立了网络深度在提高图像识别性能方面的重要作用。 VGGNet 结构成为了一个广泛应用的基准模型,其设计思想也为后续的深度学习研究奠定了基础。
二、VggNet
2.1、网络的背景
VggNet以牛津大学视觉几何小组命名,并在2014年ILSVRC竞赛的定位任务的第一名 和分类任务的第二名,由Karen Simonyan和Andrew Zisserman在论文Very Deep Convolutional Networks for Large-Scale Image Recognition中提出。
VGGNet的设计灵感来源于前馈神经网络中深层网络可以学习到更多的高级特征,从而提高识别准确率。VGGNet的特点是在训练过程中采用小的卷积核和池化层,并通过堆叠多个卷积层来增加网络的深度,从而实现高精度的图像识别。并且VGGNet网络共有6个配置,包括11层,13层,16层,19层,以及是否使用LRN局部响应归一化操作等,在日常使用过程中一般使用16层。
论文地址:
https://arxiv.org/abs/1409.1556
2.2、网络的创新
2.2.1、通过堆叠3x3卷积核代替大尺度卷积核
VGGNet的亮点在于它通过堆叠多个卷积层,以小的卷积核和池化层的方式来增加网 络深度,从而实现高精度的图像识别。这种方法可以有效地捕获图像中的高级特征, 并通过不断拟合训练数据来提高识别准确率。
2.2.2、感受野
感受野(Receptive Field),指的是神经网络中神经元“看到的”输入区域,在卷积神 经网络中,feature map上某个元素的计算受输入图像上某个区域的影响,这个区域 即该元素的感受野。
卷积神经网络中,越深层的神经元看到的输入区域越大,如下图所示,卷积核kernel size 均为3×3,stride均为1,绿色标记的是Layer2每个神经元看到的区域,黄色标记 的是Layer3 看到的区域,具体地,Layer2每个神经元可看到Layer1上3×3 大小的区 域,Layer3 每个神经元看到Layer2 上3×3 大小的区域,该区域可以又看到Layer1上 5×5 大小的区域。
所以,感受野是个相对概念,某层feature map上的元素看到前面不同层上的区域范 围是不同的,通常在不特殊指定的情况下,感受野指的是看到输入图像上的区域。
2.2.3、通过堆叠3x3卷积核代替大尺度卷积核
根据感受野的计算公式公式,Layer3的一个1x1的区域,可以计算出:
对应着Layer2的(1-1)x1+3=3,即3x3的感受野;
对应着Layer1的(3-1)x1+3=5,即5x5的感受野;
假如在Layer1前面还有一个Layer0,那么对应着Layer0的(5-1)x1+3=7,即7x7的感 受野。
根据这个规律,可以得知,三层3x3的卷积核,就可以和一层7x7的卷积核的感受野 是一致的。
VGGNet论文中提到堆叠两个3x3的卷积核可以替代5x5的卷积核,堆叠三个3x3的卷 积核可以替代7x7的卷积核,那么通过多个小的感受野的堆叠,替代大的感受野是为 了减少网络训练时参数的数量。
2.3、网络的问题
尽管VggNet在许多方面都表现优秀,但它也有一些缺陷:
1. 该网络架构非常大,并且需要大量的计算资源来训练。这意味着,如果你想在较 小的设备上使用VggNet,比如移动设备或个人电脑,会发现它非常慢,并且可能 无法获得足够的性能。
2. 由于VggNet网络架构非常深,它可能会导致梯度消失或爆炸的问题。这是由于在 非常深的神经网络中,梯度在传播过程中可能会变得非常小或非常大,从而导致 模型无法正常训练。
因此,VggNet网络架构虽然在许多方面都非常优秀,但是要注意这些缺点可能导致的问题。
2.4、 网络的结构
卷积的stride=1,padding=1;
池化的maxpool的size=2,stride=2。
2.3、设计思路
import torch
import torch.nn as nn
from torchsummary import summary
class VggNet(nn.Module):
def __init__(self, num_classifier=1000):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 64, 3, 1, 1), # -> 224x224x64
nn.ReLU(inplace=True),
nn.Conv2d(64, 64, 3, 1, 1), # -> 224x224x64
nn.ReLU(inplace=True),
nn.MaxPool2d(2, 2), # -> 112x112x64
nn.Conv2d(64, 128, 3, 1), # -> 110x110x128
nn.ReLU(inplace=True),
nn.Conv2d(128, 128, 3, 1), # -> 108x108x128
nn.ReLU(inplace=True),
nn.MaxPool2d(2, 2), # -> 54x54x128
nn.Conv2d(128, 256, 3, 1), # -> 52x52x256
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, 3, 1), # -> 50x50x256
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, 3, 1), # -> 48x48x256
nn.ReLU(inplace=True),
nn.MaxPool2d(2, 2), # -> 24x24x256
nn.Conv2d(256, 512, 3, 1), # -> 22x22x512
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, 3, 1), # -> 20x20x512
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, 3, 1), # -> 18x18x512
nn.ReLU(inplace=True),
nn.MaxPool2d(2, 2), # -> 9x9x512
nn.Conv2d(512, 512, 3, 1), # -> 7x7x512
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, 3, 1), # -> 5x5x512
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, 3, 1), # -> 3x3x512
nn.ReLU(inplace=True),
nn.MaxPool2d(2, 2) # -> 1x1x512
)
self.fc = nn.Sequential(
nn.Linear(512 * 1 * 1, 4096), # 512 * 1 * 1
nn.ReLU(inplace=True),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),
nn.Linear(4096, num_classifier) # 输出类别数
)
def forward(self, x):
x = self.features(x)
x = torch.flatten(x, 1)
x = self.fc(x)
return x
if __name__ == '__main__':
model = VggNet()
print(summary(model, (3, 224, 224)))
----------------------------------------------------------------
Layer (type) Output Shape Param #
================================================================
Conv2d-1 [-1, 64, 224, 224] 1,792
ReLU-2 [-1, 64, 224, 224] 0
Conv2d-3 [-1, 64, 224, 224] 36,928
ReLU-4 [-1, 64, 224, 224] 0
MaxPool2d-5 [-1, 64, 112, 112] 0
Conv2d-6 [-1, 128, 110, 110] 73,856
ReLU-7 [-1, 128, 110, 110] 0
Conv2d-8 [-1, 128, 108, 108] 147,584
ReLU-9 [-1, 128, 108, 108] 0
MaxPool2d-10 [-1, 128, 54, 54] 0
Conv2d-11 [-1, 256, 52, 52] 295,168
ReLU-12 [-1, 256, 52, 52] 0
Conv2d-13 [-1, 256, 50, 50] 590,080
ReLU-14 [-1, 256, 50, 50] 0
Conv2d-15 [-1, 256, 48, 48] 590,080
ReLU-16 [-1, 256, 48, 48] 0
MaxPool2d-17 [-1, 256, 24, 24] 0
Conv2d-18 [-1, 512, 22, 22] 1,180,160
ReLU-19 [-1, 512, 22, 22] 0
Conv2d-20 [-1, 512, 20, 20] 2,359,808
ReLU-21 [-1, 512, 20, 20] 0
Conv2d-22 [-1, 512, 18, 18] 2,359,808
ReLU-23 [-1, 512, 18, 18] 0
MaxPool2d-24 [-1, 512, 9, 9] 0
Conv2d-25 [-1, 512, 7, 7] 2,359,808
ReLU-26 [-1, 512, 7, 7] 0
Conv2d-27 [-1, 512, 5, 5] 2,359,808
ReLU-28 [-1, 512, 5, 5] 0
Conv2d-29 [-1, 512, 3, 3] 2,359,808
ReLU-30 [-1, 512, 3, 3] 0
MaxPool2d-31 [-1, 512, 1, 1] 0
Linear-32 [-1, 4096] 2,101,248
ReLU-33 [-1, 4096] 0
Linear-34 [-1, 4096] 16,781,312
ReLU-35 [-1, 4096] 0
Linear-36 [-1, 1000] 4,097,000
================================================================
Total params: 37,694,248
Trainable params: 37,694,248
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.57
Forward/backward pass size (MB): 194.38
Params size (MB): 143.79
Estimated Total Size (MB): 338.75
----------------------------------------------------------------