别再死记硬背VGG结构了!手把手带你用PyTorch复现VGG16/19(附代码与权重加载)

张开发
2026/4/21 9:55:31 15 分钟阅读

分享文章

别再死记硬背VGG结构了!手把手带你用PyTorch复现VGG16/19(附代码与权重加载)
从零构建VGG网络PyTorch实战指南与设计哲学解析在深度学习领域VGG网络以其简洁优雅的架构设计成为计算机视觉任务的经典基准模型。不同于死记硬背网络结构参数本文将带您深入理解VGG的设计精髓并手把手实现一个完整的PyTorch版本。无论您是希望夯实基础还是准备面试这次代码级的探索都将让您获得远超论文表面的实战认知。1. 环境准备与核心设计理念开始编码前我们需要明确VGG的两个革命性贡献小卷积核堆叠策略和深度对性能的影响。2014年牛津大学Visual Geometry Group提出的这种架构在ILSVRC竞赛中证明了深度的重要性。先配置基础环境import torch import torch.nn as nn import torchvision print(fPyTorch版本: {torch.__version__})VGG的核心设计选择全部使用3×3卷积核步长1padding1每经过池化层通道数翻倍64→128→256→512最大池化统一采用2×2窗口步长2全连接层固定为4096→4096→1000的结构提示现代实现中通常会加入BatchNorm层加速收敛但原始VGG并未使用2. 模块化构建VGG网络2.1 卷积块生成器VGG的重复结构非常适合模块化设计。我们先实现一个生成卷积块的工厂函数def make_layers(in_channels, cfg, batch_normFalse): layers [] for v in cfg: if v M: layers [nn.MaxPool2d(kernel_size2, stride2)] else: conv2d nn.Conv2d(in_channels, v, kernel_size3, padding1) layers [conv2d, nn.ReLU(inplaceTrue)] if batch_norm: layers [nn.BatchNorm2d(v)] in_channels v return nn.Sequential(*layers)2.2 完整网络架构基于上述函数我们可以轻松实现不同版本的VGGclass VGG(nn.Module): def __init__(self, features, num_classes1000, init_weightsTrue): super().__init__() self.features features self.avgpool nn.AdaptiveAvgPool2d((7, 7)) self.classifier nn.Sequential( nn.Linear(512*7*7, 4096), nn.ReLU(True), nn.Dropout(), nn.Linear(4096, 4096), nn.ReLU(True), nn.Dropout(), nn.Linear(4096, num_classes), ) def forward(self, x): x self.features(x) x self.avgpool(x) x torch.flatten(x, 1) x self.classifier(x) return x不同配置的架构参数配置名称卷积层结构总层数VGG11[64,M,128,M,256,256,M,512,512,M,512,512,M]11VGG16[64,64,M,128,128,M,256,256,256,M,512,512,512,M,512,512,512,M]16VGG19在VGG16基础上增加三个卷积层193. 预训练权重加载与应用3.1 官方权重加载PyTorch官方提供了预训练好的VGG权重# 加载预训练模型 model torchvision.models.vgg16(pretrainedTrue) # 冻结特征提取层 for param in model.features.parameters(): param.requires_grad False # 修改最后一层适配新任务 model.classifier[6] nn.Linear(4096, 10) # 假设新任务有10类3.2 自定义权重的保存与加载训练好的模型需要正确保存和加载# 保存整个模型 torch.save(model.state_dict(), vgg_custom.pth) # 加载时需先实例化相同结构的模型 loaded_model VGG(make_layers(3, [64,64,M,128,128,M,256,256,256,M,512,512,512,M,512,512,512,M])) loaded_model.load_state_dict(torch.load(vgg_custom.pth))4. 实战猫狗分类任务4.1 数据准备与增强使用torchvision提供的工具快速构建数据管道from torchvision import transforms train_transform transforms.Compose([ transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) train_data torchvision.datasets.ImageFolder( path/to/train, transformtrain_transform )4.2 训练流程关键代码实现一个完整的训练循环def train_model(model, dataloaders, criterion, optimizer, num_epochs25): for epoch in range(num_epochs): for phase in [train, val]: if phase train: model.train() else: model.eval() running_loss 0.0 running_corrects 0 for inputs, labels in dataloaders[phase]: optimizer.zero_grad() with torch.set_grad_enabled(phase train): outputs model(inputs) loss criterion(outputs, labels) if phase train: loss.backward() optimizer.step() running_loss loss.item() * inputs.size(0) running_corrects torch.sum(outputs.argmax(1) labels) epoch_loss running_loss / len(dataloaders[phase].dataset) epoch_acc running_corrects.double() / len(dataloaders[phase].dataset) print(f{phase} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f})5. VGG的现代改进与优化虽然原始VGG现在看起来有些过时但其设计理念仍影响着现代网络架构内存优化用1×1卷积降维类似Inception思想计算加速将全连接层转换为卷积层FCN现代技巧加入BatchNorm和LeakyReLU改进后的特征提取部分示例class ImprovedVGGBlock(nn.Module): def __init__(self, in_channels, out_channels): super().__init__() self.conv nn.Sequential( nn.Conv2d(in_channels, out_channels, 3, padding1), nn.BatchNorm2d(out_channels), nn.LeakyReLU(0.1), nn.Conv2d(out_channels, out_channels, 3, padding1), nn.BatchNorm2d(out_channels), nn.LeakyReLU(0.1), ) def forward(self, x): return self.conv(x)在实际项目中VGG仍然有其独特优势架构简单易于理解特征提取能力稳定适合作为基准模型或迁移学习的起点。我在多个工业级图像分类项目中发现当数据量不大时适当改进的VGG模型往往能达到与更复杂模型相近的效果但训练成本和部署难度却低得多。

更多文章