资讯动态

VGGNet论文精读:小卷积核堆叠与深度网络设计原理

发布时间:2026/10/15 1:47:52 来源:尧图企业网站定制
1. 为什么我要啃这篇二十多年前的论文如果你现在打开任何一个深度学习框架的模型库翻到图像分类那一栏大概率会先看到ResNet、EfficientNet、ConvNeXt这些名字。VGGNet它可能被折叠在一个叫经典模型或者legacy的分类里点开之后只有一行冷冰冰的vgg16(pretrainedTrue)。很多人跑完一遍预训练权重拿到个还不错的准确率就再也没看过它第二眼。但我想说的是如果你真的想把卷积神经网络这件事搞明白VGGNet这篇论文值得你花一个下午逐段啃完。不是因为它性能最强——它早就不是了也不是因为它设计最优雅——16层堆叠其实挺笨的。而是因为它把一个核心问题回答得极其干净当网络深度从十几层增加到十九层图像识别到底发生了什么变化这篇论文的全称是《用于大规模图像识别的深度卷积网络》英文原名里那个Very Deep是关键词。在它之前大家用的网络普遍只有七八层AlexNet是8层ZFNet也是8层左右。VGG团队直接把深度拉到了16到19层并且用了一个极其统一的架构所有卷积层都是3×3的小卷积核所有池化都是2×2的最大池化通道数从64开始每经过一次池化就翻倍。就这么简单的一套规则在当年的ImageNet挑战赛上拿到了定位任务第一名、分类任务第二名的成绩。我写这篇博文的目的很明确把这篇论文的核心内容用纯中文完整地讲一遍不是那种摘要式的论文笔记而是把它的实验设计、架构细节、训练技巧、消融实验的结论都摊开来说。同时我会补充一些论文里没写、但实际复现时一定会遇到的问题比如权重初始化到底怎么选、数据增强的尺度怎么定、多尺度测试为什么有效。适合谁看刚入门计算机视觉、想搞懂经典网络设计思路的学生工作中需要用到VGG作为骨干网络做特征提取的工程师以及任何对为什么小卷积核能堆出大感受野这个问题感兴趣的人。2. 论文要解决的核心问题深度到底能带来什么2.1 从AlexNet到VGG一场关于深度的赌注2012年AlexNet横空出世之后卷积神经网络在图像识别领域的地位基本确立了。但接下来几年大家的改进方向比较分散有人改激活函数有人改池化方式有人搞数据增强有人调学习率策略。VGG团队的选择非常聚焦——他们就想搞清楚一件事如果把网络做得更深性能会不会持续提升这个问题在当时并不是理所当然的。因为深度增加会带来两个直接麻烦一是梯度消失或爆炸二是计算量暴涨。2014年之前Batch Normalization还没出来BN是2015年的工作残差连接也没有ResNet是2015年底。所以VGG团队是在没有这些深度训练神器的条件下硬生生把网络堆到了19层。他们靠的是什么后面会详细讲核心是合理的权重初始化和小卷积核的堆叠策略。论文里有一句话我印象很深大意是他们不是要追求某个特定数据集上的最优结果而是想建立一个受控的实验环境系统地评估深度这个单一变量对性能的影响。这种研究思路本身就值得学习——把其他因素固定住只改一个变量看结果怎么变。2.2 小卷积核的数学账为什么3×3能替代5×5和7×7这是VGG论文里最核心的技术论点也是面试里经常被问到的问题。我先给结论两个3×3卷积层的堆叠感受野等于一个5×5卷积层三个3×3卷积层的堆叠感受野等于一个7×7卷积层。感受野的计算公式是上一层感受野为$R_{n-1}$当前层卷积核大小为$k$步长为$s$则当前层感受野$R_n R_{n-1} (k-1) \times \prod_{i1}^{n-1} s_i$。在VGG的设计里所有卷积步长都是1所以每加一个3×3卷积层感受野就增加2。两个3×3堆叠$1 2 2 5$三个3×3堆叠$1 2 2 2 7$。数学上完全等价。但等价只是感受野大小相同真正的好处在于两点。第一参数数量大幅减少。假设输入输出通道数都是$C$一个7×7卷积层的参数量是$7 \times 7 \times C \times C 49C^2$三个3×3卷积层的参数量是$3 \times (3 \times 3 \times C \times C) 27C^2$。少了将近一半。第二非线性表达能力更强。每个卷积层后面都跟着ReLU激活函数三个3×3层意味着有三次非线性变换而一个7×7层只有一次。更多的非线性让网络能拟合更复杂的函数。这里有个容易搞混的点感受野等价的前提是通道数不变、步长为1、没有空洞卷积。实际实现时如果中间加了池化或者步长不为1感受野的计算就要重新来。我在复现时习惯用工具函数逐层打印感受野避免凭感觉估算。2.3 论文的实验设计逻辑控制变量法的教科书示范VGG论文的实验部分写得非常规范基本就是控制变量法的模板。他们从网络A11层开始逐步加深到网络E19层每次加深的方式都是插入新的卷积层其他超参数尽量保持一致。然后对比不同深度在ImageNet上的top-1和top-5错误率。结果很清晰从11层到16层错误率持续下降从16层到19层提升幅度变小但仍有改善。这说明深度确实有用但存在边际递减效应。另外他们还做了几个变体实验比如用1×1卷积代替部分3×3卷积网络B和C发现1×1卷积能增加非线性但不改变感受野对性能有小幅帮助。还有用5×5卷积替换部分3×3的版本结果反而变差了进一步验证了小卷积核堆叠的优势。这些实验结论在今天看来可能不算惊艳但在当时是非常有说服力的。它给后续的ResNet、DenseNet等工作铺平了道路——大家开始相信深度是提升性能的关键维度问题只是怎么把更深的网络训练好。3. 架构细节拆解从输入到输出的完整链路3.1 卷积层配置表五套方案的对比论文里给出了从A到E共六套配置A、A-LRN、B、C、D、E其中D和E就是后来大家熟知的VGG16和VGG19。我把它们的核心差异整理成表格方便对照。配置名称总层数卷积层分布关键特征A118个卷积3个全连接基础版本全部3×3卷积A-LRN11同A但第一层后加LRN验证局部响应归一化是否有效B1310个卷积3个全连接在A基础上增加两个3×3卷积C1613个卷积3个全连接部分层用1×1卷积替代3×3DVGG161613个卷积3个全连接全部3×3卷积经典版本EVGG191916个卷积3个全连接在D基础上再增加三个卷积层从表格能看出来VGG的架构设计非常规整。所有卷积层都是3×3步长1padding为1保持空间尺寸不变所有最大池化都是2×2步长2。通道数从64开始每经过一次池化翻倍64→128→256→512→512。最后接三个全连接层前两个各4096维最后一个1000维对应ImageNet的类别数。实际复现时有个细节要注意论文里全连接层的参数量占了整个网络的绝大部分。VGG16的总参数量约1.38亿其中全连接层就占了约1.24亿。这也是后来大家用全局平均池化替代全连接层的原因之一。3.2 输入处理与数据增强尺度抖动的具体做法VGG的输入是224×224的RGB图像。但论文里用了一个很重要的数据增强技巧叫尺度抖动。具体做法是先把原始图像缩放到一个随机尺寸短边在256到512之间随机选然后从中随机裁剪224×224的区域。这样每张图在每个epoch看到的尺度都不一样相当于让网络学习尺度不变性。测试的时候他们用了两种方式一种是固定尺度把图像短边缩放到256或384然后取中心224×224区域另一种是多尺度测试把图像缩放到多个尺度分别预测后取平均。实验结果显示多尺度测试能带来明显的性能提升。我在实际项目里试过类似的做法但要注意一点尺度抖动的范围不能太大否则小目标会被裁没大目标又会被过度放大。256到512这个范围是论文里调出来的如果你的数据集目标尺寸分布不同需要重新调整。另外随机裁剪的时候如果目标恰好落在边缘可能被裁掉一半这时候可以考虑用随机缩放随机长宽比抖动来替代效果更稳。3.3 全连接层的设计考量为什么是4096维论文里三个全连接层的维度分别是4096、4096、1000。为什么选4096论文没有给出明确的推导但从实验来看这个维度足够大能容纳从卷积层提取的高维特征同时又不至于让参数量爆炸到无法训练。从特征提取的角度理解卷积层输出的特征图经过展平后是一个7×7×51225088维的向量第一个全连接层把它映射到4096维相当于做了一个大规模的特征压缩和重组。第二个全连接层继续在4096维空间里做非线性变换。最后一个全连接层映射到类别数。实际使用中很多人会把VGG的全连接层去掉只保留卷积部分作为特征提取器。这时候输出的就是7×7×512的特征图可以接自己的分类头或者用于其他任务。这种用法在迁移学习里非常常见尤其是当你的数据集和ImageNet差异较大时冻结卷积层、只训练分类头往往能取得不错的效果。4. 训练策略与权重初始化没有BN时代怎么训深层网络4.1 权重初始化的门道为什么不能全零也不能太大在没有Batch Normalization的年代权重初始化是训练深层网络的第一道坎。如果权重全初始化为0所有神经元的输出都一样反向传播时梯度也相同网络永远学不到东西。如果权重初始化太大前向传播时激活值会逐层放大最后爆炸初始化太小激活值逐层缩小最后消失。VGG论文里用的初始化策略是从均值为0、方差为0.01的正态分布中采样。偏置项全部初始化为0。这个策略在当时的条件下算是比较合理的但它并不是万能的。后来He等人提出的Kaiming初始化也叫He初始化根据每层的输入通道数动态调整方差效果更好。如果你现在复现VGG我建议直接用Kaiming初始化收敛速度和最终精度都会更好。有个坑我踩过用PyTorch的默认初始化跑VGG16前几个epoch的loss几乎不降后来换成Kaiming初始化才正常。原因是PyTorch对卷积层的默认初始化方差偏小深层网络的信号传不下去。4.2 训练超参数学习率、动量与权重衰减论文里给出的训练超参数如下学习率初始为0.01当验证集准确率不再提升时除以10动量0.9权重衰减5×10⁻⁴batch size为256总共训练74个epoch。这些参数在当年是经过大量实验调出来的放到今天仍然有参考价值。学习率0.01配合动量0.9在SGD优化器下是比较激进的设置。如果直接套用到自己的数据集上可能会遇到loss震荡甚至发散。我的经验是先用0.001跑几个epoch看看loss曲线如果下降平稳再逐步加大。权重衰减5×10⁻⁴主要是为了防止全连接层过拟合因为全连接层参数量太大了。如果你去掉了全连接层权重衰减可以适当减小。另外论文里提到了dropout只在前两个全连接层后面加概率0.5。卷积层后面没有加dropout因为卷积层的参数共享机制本身就有一定的正则化效果。这个设计后来被广泛沿用直到Batch Normalization出现后才有所改变。4.3 多尺度训练与测试的实操细节多尺度训练的核心思想是让网络看到不同尺度的同一张图从而学习到尺度不变的特征。具体实现时每个batch里的每张图都独立随机选一个尺度然后裁剪224×224。这样做的好处是增加了数据的多样性坏处是同一个batch里不同样本的尺度不同BN层的统计量会有些波动不过VGG没用BN所以问题不大。多尺度测试的做法是把测试图缩放到多个尺度比如256、384、512每个尺度取中心裁剪或者全卷积方式预测最后把所有尺度的预测结果平均。论文里报告说多尺度测试比单尺度测试的top-5错误率低了约1.5个百分点。我在实际项目里用过类似的多尺度测试但发现如果尺度跨度太大小尺度的预测和大尺度的预测差异会很大平均之后反而可能拉低效果。建议尺度选择在训练时见过的范围内比如训练用了256到512测试就用320、384、448三个尺度不要跳到640。5. 消融实验的结论哪些设计真正有用5.1 深度的影响从11层到19层的性能曲线论文里最核心的消融实验就是对比不同深度的网络。从网络A11层到网络E19层top-5错误率从10.4%降到了8.0%左右单尺度测试。这个提升幅度在ImageNet上算是相当显著了。但要注意从16层到19层的提升只有0.3个百分点左右说明深度的收益在递减。这个结论对后续研究的影响很大。ResNet之所以能堆到上百层是因为它解决了深层网络的退化问题。而VGG的实验已经暗示了如果没有好的训练技巧单纯增加深度到某个点之后就不划算了。所以后来大家不再盲目堆深度而是开始关注更聪明的架构设计。5.2 LRN为什么被弃用一个被时代淘汰的设计网络A-LRN在第一个卷积层后面加了局部响应归一化这是从AlexNet继承过来的设计。但实验结果显示LRN带来的提升微乎其微甚至在某些设置下还有负面影响。所以VGG后续的配置里都去掉了LRN。LRN被弃用的根本原因是它和后来的Batch Normalization功能重叠但效果差很多。LRN是在通道维度上做归一化而BN是在batch维度上做归一化后者对训练稳定性的帮助大得多。现在几乎没有人会在新网络里用LRN了但了解这段历史有助于理解归一化技术的发展脉络。5.3 1×1卷积的作用增加非线性而不改变感受野网络C里用了一些1×1卷积。1×1卷积的感受野就是1×1它不改变特征图的空间尺寸也不增加感受野但它能做两件事一是改变通道数升维或降维二是在通道维度上做非线性变换。论文里的实验显示1×1卷积对性能有小幅提升但不如直接堆3×3卷积来得明显。这个结论后来在GoogLeNet和ResNet里被进一步发展。GoogLeNet用1×1卷积做降维大幅减少了计算量ResNet用1×1卷积做瓶颈结构让深层网络的参数量可控。所以VGG论文里的这个实验虽然简单但启发了后续很多工作。6. 复现VGG时最容易踩的五个坑6.1 显存不够用全连接层是罪魁祸首VGG16的全连接层参数量约1.24亿占整个网络的90%以上。训练时这些参数都要存在显存里加上梯度、优化器状态显存占用非常夸张。如果你只有一张8GB显存的卡batch size可能只能设到16甚至8。解决办法有几个一是把全连接层换成全局平均池化参数量直接降到零二是用梯度累积模拟大batch三是混合精度训练能省将近一半显存。我一般推荐第一种因为全局平均池化在很多任务上效果并不差而且模型文件小很多部署也方便。6.2 输入尺寸不匹配224不是随便定的VGG的输入是224×224这个尺寸不是随便选的。经过5次2×2池化后224÷327特征图变成7×7正好能接全连接层。如果你把输入改成256×256经过5次池化后是8×8全连接层的输入维度就对不上了。当然你可以调整全连接层的输入维度但那样预训练权重就用不了了。所以如果你要用VGG的预训练权重输入尺寸必须保持224×224。如果任务需要更大的输入可以考虑去掉全连接层用全卷积的方式处理任意尺寸的输入。6.3 学习率设太大loss直接飞掉前面提到论文用的初始学习率是0.01。但那是配合特定的初始化和数据增强策略的。如果你用自己的数据集直接上0.01大概率会看到loss变成NaN。我的建议是从0.001开始观察前几个epoch的loss曲线如果下降太慢再逐步加大。另外要注意学习率衰减的时机。论文里是验证集准确率不再提升时除以10。实际实现时可以用ReduceLROnPlateau回调设置patience为3到5个epochfactor为0.1。这样比手动调更省心。6.4 数据增强过度把目标裁没了随机裁剪是常用的数据增强手段但如果裁剪比例控制不好很容易把目标裁掉。比如一张图里目标只占左上角一小块随机裁剪到中心区域时目标就没了。这时候网络学到的就是错误的标签对应关系。解决办法是先用目标检测或者显著性检测确定目标位置再做裁剪。如果不想那么麻烦可以减小裁剪的随机性比如只在图像中心区域做小范围抖动。或者用RandAugment这类自动增强策略它会根据数据集特点自动选择增强操作和强度。6.5 预训练权重加载失败key不匹配的排查思路用PyTorch加载VGG预训练权重时最常见的报错是key不匹配。比如你修改了分类头的输出维度最后一层的权重形状就对不上了。这时候需要手动过滤掉不匹配的key只加载卷积层的权重。具体做法是先加载整个state_dict然后遍历自己的模型只保留名字和形状都匹配的权重。PyTorch的load_state_dict有个strictFalse参数可以忽略不匹配的key但这样会静默跳过错误有时候反而不好排查。我习惯先打印两边的key列表对比差异确认哪些层需要重新初始化。7. 从VGG延伸出去它给后续研究留下了什么7.1 特征提取的通用性为什么VGG至今还在用虽然VGG在分类任务上早就被超越了但它的卷积层特征至今仍然被广泛使用。在风格迁移、图像超分辨率、感知损失等任务里VGG的特征图经常被用来计算内容损失和风格损失。原因是VGG的卷积层学到的特征比较通用浅层捕捉纹理和边缘深层捕捉语义信息这种层次化的特征表达在很多任务里都有用。我做过一个图像风格迁移的小项目用的就是VGG19的卷积层特征。把内容图和风格图分别送进网络提取中间层的特征图然后计算内容损失和风格损失。效果比用其他网络好因为VGG的特征图空间分辨率保持得比较好风格纹理的细节能保留下来。7.2 对ResNet的启发深度不是问题退化才是VGG的实验已经发现深度增加到一定程度后性能提升变缓。ResNet的作者进一步发现如果只是简单堆叠卷积层深层网络的训练误差反而比浅层网络大这叫退化问题。ResNet通过残差连接解决了这个问题让网络可以堆到上百层甚至上千层。所以VGG和ResNet的关系不是替代而是递进。VGG证明了深度有用ResNet解决了深度带来的训练困难。理解了这个脉络你再看其他网络架构的演进就会清晰很多。7.3 现代架构里的VGG影子3×3卷积仍然是主流虽然现在的新网络用了各种花哨的设计比如分组卷积、深度可分离卷积、注意力机制但3×3卷积仍然是基本组件。EfficientNet的MBConv模块里用的是3×3深度可分离卷积ConvNeXt用的是7×7深度可分离卷积但设计思路和VGG一脉相承。可以说VGG确立的小卷积核堆叠原则已经成了卷积神经网络设计的默认选项。我在实际工作中选骨干网络时如果任务对精度要求不是极致VGG16仍然是一个稳妥的选择。它的结构简单预训练权重容易获取特征提取效果稳定。尤其是在数据量不大的场景下VGG的过拟合风险反而比一些复杂网络低因为它的参数量虽然大但卷积层的参数共享机制提供了天然的正则化。8. 我个人的复现体会与实用建议最后分享几个我在复现VGG过程中总结的实用建议都是文档里不会写的。第一不要一上来就训完整网络。先用一个小数据集比如CIFAR-10的子集跑通流程确认数据加载、前向传播、反向传播、权重更新都没问题再上完整数据集。这样可以快速定位是代码bug还是超参数问题。第二保存训练过程中的中间检查点。VGG训练很慢如果跑到一半崩了没有检查点就得重来。我一般每5个epoch保存一次同时记录验证集准确率方便后续分析。第三可视化卷积核和特征图。把第一层卷积核画出来能看到边缘检测器把中间层的特征图画出来能看到网络关注的是哪些区域。这对理解网络行为很有帮助也能帮你判断网络有没有学到有用的特征。第四多尺度测试不一定总是更好。论文里说多尺度测试有提升但那是在特定数据集和特定尺度范围下。如果你的数据集目标尺度比较统一多尺度测试可能反而引入噪声。建议先在验证集上对比单尺度和多尺度的效果再决定用哪种。第五迁移学习时冻结层数的选择。用VGG做迁移学习时冻结前几层还是冻结所有卷积层取决于你的数据集和ImageNet的相似度。如果相似度高冻结所有卷积层只训分类头就够了如果相似度低可以解冻后面几个卷积块一起训。我一般从冻结所有卷积层开始如果效果不好再逐步解冻。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑