VGGNet网络学习

VGGNet(Visual Geometry Group Network)是由牛津大学视觉几何组(Visual Geometry Group)在2014年提出的深度卷积神经网络模型。它在当年的ImageNet大规模视觉识别挑战赛(ILSVRC)中取得了优异的成绩,并因其简洁而有效的设计成为深度学习领域的经典架构之一。

0 概念

0.1 卷积块

卷积块:由n个卷积层组成------就是连续几次卷积操作提取不同信息。
每个卷积块后面紧跟1个池化层

0.2 FC

Full Connection全连接层。

1 网络结构

VGG 探索出来的网络由 5 个卷积块(Block)和 3 个全连接层(FC)组成。

VGG16 和 VGG19 是 VGGNet 系列中最经典的两个模型,它们的核心区别在于中间卷积块的"厚度"。VGG19 在 VGG16 的基础上,在中间三个卷积块中分别多堆叠了一层卷积,使得网络更深。

下表详细对比了每一层的结构差异(加粗部分为 VGG19 比 VGG16 多出的层):

层数差异:

VGG16 包含 13 个卷积层(2+2+3+3+3) + 3 个全连接层 = 16 层;

VGG19 包含 16 个卷积层(2+2+4+4+4) + 3 个全连接层 = 19 层。

参数差异:虽然 VGG19 更深,但两者参数量差距不大(VGG16 约 1.38 亿,VGG19 约 1.47 亿)。这是因为 VGG 的参数主要集中在最后的全连接层(FC6 层占了约 1.02 亿参数),而卷积层只增加了 3 层,对总参数量影响较小。

2 设计逻辑

VGG 的设计遵循"池化一次,通道数翻倍"的原则。每次池化后,特征图尺寸减半,但卷积核数量(通道数)翻倍,以保持计算量的平衡。具体如下:

输入:224×224×3

第一次池化后:112×112×64

第二次池化后:56×56×128

第三次池化后:28×28×256

第四次池化后:14×14×512

第五次池化后:7×7×512

尺寸减半:池化层减少特征图尺寸,降低计算量。

通道翻倍:增加卷积核数量,让网络在更小的空间里提取更丰富的特征信息,弥补因尺寸缩小带来的信息损失。

小细节:

你可能会注意到,最后一次池化后,通道数没有从 512 翻倍到 1024,而是保持 512。这是因为 VGG 作者发现,在当时的硬件条件下,512 通道已经足够提取高层语义特征,再增加通道数对性能提升不大,但计算量会剧增。

VGG11/13/16/19 等多种变体,数字越大通过增加卷积层数,让网络在更深层提取更抽象的特征,理论上表达能力更强,但也更容易过拟合且计算更慢。

3 pytorch代码实现兼容VGG11/13/16/19 等多种变体

c 复制代码
import torch
import torch.nn as nn

# 定义 VGG 配置字典
cfgs = {
    'VGG11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'VGG13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'VGG16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],
    'VGG19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
}

class VGG(nn.Module):
    def __init__(self, vgg_name='VGG16', num_classes=1000, init_weights=True):
        """
        参数:
            vgg_name: 要构建的 VGG 变体名称,如 'VGG16'
            num_classes: 分类类别数,默认 1000
            init_weights: 是否初始化权重
        """
        super(VGG, self).__init__()
        
        # 1. 构建特征提取层
        self.features = self._make_layers(cfgs[vgg_name])
        
        # 2. 构建分类器
        self.classifier = nn.Sequential(
            nn.Linear(512 * 7 * 7, 4096),  # 输入尺寸: 512*7*7
            nn.ReLU(True),
            nn.Dropout(),                  # 默认为 Dropout(p=0.5)
            nn.Linear(4096, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(4096, num_classes),
        )
        
        if init_weights:
            self._initialize_weights()
    
    def _make_layers(self, cfg):
        """
        根据配置列表构建卷积层
        参数:
            cfg: 配置列表,数字表示输出通道数,'M' 表示最大池化
        """
        layers = []
        in_channels = 3  # 输入通道数(RGB图像)
        
        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)
                layers += [conv2d, nn.ReLU(inplace=True)]
                in_channels = v  # 更新输入通道数为当前输出通道数
        
        return nn.Sequential(*layers)
    
    def _initialize_weights(self):
        """初始化网络权重"""
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)
    
    def forward(self, x):
        # 特征提取
        x = self.features(x)
        
        # 展平
        x = torch.flatten(x, 1)  # 保持 batch 维度,展平其他所有维度
        
        # 分类
        x = self.classifier(x)
        return x

# 2. 使用示例
if __name__ == "__main__":
    # 创建 VGG16
    vgg16 = VGG('VGG16', num_classes=1000)
    print("VGG16 结构:")
    print(vgg16)
    
    # 创建 VGG19
    vgg19 = VGG('VGG19', num_classes=1000)
    print("\nVGG19 结构:")
    print(vgg19.features)  # 打印卷积部分的结构对比
    
    # 测试前向传播
    batch_size = 4
    dummy_input = torch.randn(batch_size, 3, 224, 224)
    
    # VGG16 输出
    output_16 = vgg16(dummy_input)
    print(f"\n输入形状: {dummy_input.shape}")
    print(f"VGG16 输出形状: {output_16.shape}")
    
    # VGG19 输出
    output_19 = vgg19(dummy_input)
    print(f"VGG19 输出形状: {output_19.shape}")

这就是实现可扩展性的核心:

cfgs = {

'VGG16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', ...],

'VGG19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', ...],

}

数字表示卷积层的输出通道数

'M' 表示最大池化层

只需修改配置列表就能创建不同的 VGG 变体

特征提取器构建( _make_layers 方法):

遍历配置列表,遇到数字就创建卷积层

每个卷积层后面自动跟随 ReLU 激活函数

遇到 'M' 就创建池化层

自动更新输入通道数

输入图片:224×224

经过 5 次池化后:224/(2^5) = 7

最后一层卷积通道数:512

所以展平后维度:512 × 7 × 7 = 25088

扩展使用示例

c 复制代码
# 1. 创建各种 VGG 变体
vgg11 = VGG('VGG11', num_classes=10)  # 用于 CIFAR-10
vgg13 = VGG('VGG13', num_classes=100)  # 用于 CIFAR-100
vgg16 = VGG('VGG16', num_classes=1000)  # ImageNet
vgg19 = VGG('VGG19', num_classes=1000)

# 2. 加载预训练权重(需要安装 torchvision)
from torchvision import models
pretrained_vgg16 = models.vgg16(pretrained=True)
pretrained_vgg19 = models.vgg19(pretrained=True)

# 3. 自定义分类头(迁移学习)
def get_custom_vgg(num_classes=10):
    model = VGG('VGG16', num_classes=num_classes)
    
    # 冻结卷积层(只训练分类器)
    for param in model.features.parameters():
        param.requires_grad = False
    
    return model

custom_model = get_custom_vgg(num_classes=10)

4 探索出来的经验和理论

VGGNet 最核心的探索成果,是确立了"深度"在卷积神经网络中的决定性作用,并总结出了一套"小卷积核 + 模块化"的经典设计范式。这些经验至今仍是深度学习架构设计的基石。

4.1 核心理论:深度决定性能

VGGNet 通过严谨的对比实验,证明了网络深度(层数)是提升模型性能的关键因素。

实验验证:VGG 团队设计了从 11 层到 19 层的多个变体,发现随着层数增加,模型在 ImageNet 上的错误率显著下降。这直接推翻了当时"网络太深难以训练"的普遍认知,为后续 ResNet、DenseNet 等超深网络的发展铺平了道路。

4.2 设计经验:小卷积核的威力

VGGNet 确立了 "用多个小卷积核替代大卷积核" 的设计原则。

3×3 卷积核:VGG 发现,两个 3×3 卷积层的感受野等同于一个 5×5 卷积层,三个 3×3 卷积层的感受野等同于一个 7×7 卷积层。

优势:这种设计不仅减少了参数量(计算量更小),还引入了更多的非线性激活函数(ReLU),让网络具备了更强的特征提取能力。

4.3 架构范式:模块化与通道翻倍

VGGNet 建立了"卷积块 + 池化层"交替的经典架构模式。

模块化设计:将网络划分为多个卷积块(Block),每个块内包含 2-4 个卷积层,块与块之间用池化层连接。这种结构清晰、易于理解和实现。

通道翻倍:每次池化后(特征图尺寸减半),下一个卷积块的通道数翻倍。这种设计平衡了计算量,确保了网络在深层依然能保留足够的信息。

4.4 工程启示:简洁与可复现

VGGNet 证明了简洁的设计往往最有效。

结构极简:整个网络只使用了 3×3 卷积和 2×2 池化两种操作,没有任何复杂的技巧。

可复现性:由于其结构规整,代码实现非常容易,这极大地促进了深度学习在工业界的普及和应用。

5 当代价值

尽管在 ImageNet 准确率上已被更先进的网络超越,但 VGGNet 仍具有不可替代的价值:

教学价值:几乎所有深度学习课程都从 VGG 开始讲解 CNN 设计。

研究基线:新方法常以 VGG 为基线进行对比。

艺术应用:在风格迁移、深度学习艺术中,VGG 的特征图仍是首选。

边缘部署:其规整结构在某些硬件上仍比复杂网络更高效。

6 实验科学的思考

再一次加深了对于深度学习网络结构的实验科学的倾向!!!

没有理论依据,都是马后炮的思考!

目前感觉还处于盲人摸象阶段!!

相关推荐
hhzz1 小时前
使用Python对MySQL进行数据分析
python·mysql·数据分析
肾透侧视攻城狮1 小时前
《避坑指南与性能提升:TensorFlow图像分类项目核心实践全汇总》
人工智能·深度学习·tensorflow·模型结构可视化·编译模型·提高模型性能的方法·图像分类项目
52Hz1181 小时前
力扣39.组合总和、22.括号生成、79.单词搜索
python·leetcode
大鹏说大话1 小时前
从“能聊“到“能干“:Agentic AI的技术跃迁与商业重构
人工智能
是小蟹呀^1 小时前
【论文阅读13】AdaFace:低画质人脸识别的破局之作,用“特征范数”重塑损失函数!
论文阅读·深度学习·分类·adaface
Chasing Aurora1 小时前
vscode连接 服务器进行 深度学习
linux·ide·vscode·深度学习·研究生·解压缩·连接服务器
哈里谢顿1 小时前
从零开始编写一个完整的Python HTTP REST API服务
python
BackCatK Chen1 小时前
无方向盘、无踏板!特斯拉Cybercab下线:自动驾驶的终极形态来了?
图像处理·人工智能·机器学习·自动驾驶·视觉检测·能源·制造
SmartBrain1 小时前
战略洞察:小米AI转型与科技突破
人工智能·科技