基础知识储备:
VGGNet 是由牛津大学的 Visual Geometry Group (VGG) 提出的一种深度卷积神经网络(CNN)架构,首次发表于2014年的论文《Very Deep Convolutional Networks for Large-Scale Image Recognition》。VGGNet 以其简单而有效的结构著称,并在图像分类和对象识别等任务中取得了优异的性能。
核心特点:
深度网络:VGGNet 的主要特点是它的深度,常见的版本有 VGG-16 和 VGG-19,分别包含 16 层和 19 层带参数的层(卷积层和全连接层)。VGGNet 通过堆叠多层 3×3 的小卷积核,成功构建了更深的网络。
小卷积核:VGGNet 使用非常小的卷积核(3×3),而不是较大的卷积核(如 5×5 或 7×7)。3×3 的卷积核有两个优点:
更少的参数:相比大的卷积核,3×3 的卷积核参数更少,可以有效减少模型的参数量。
更多的非线性:堆叠多个 3×3 卷积层可以增加网络的非线性,从而增强模型的表达能力。
固定大小的输入:VGGNet 要求输入的图像尺寸固定为 224×224 像素。这与早期的网络(如 AlexNet)相比是一个较大的变化,AlexNet 可以处理可变尺寸的输入图像。
通道数的逐步增加:VGGNet 中的卷积层通道数(即特征图的数量)逐步增加,从 64 通道开始,然后是 128、256、512,直到最大的 512 个通道。这种设计模式帮助网络逐步提取更复杂的特征。
最大池化层:每个卷积层之后通常会跟随一个最大池化层(2×2),这有助于减少特征图的尺寸,并引入一定程度的平移不变性。
全连接层:在卷积层之后,VGGNet 包含了三个全连接层,其中最后一个全连接层连接到 softmax 层用于分类任务。
VGGNet 的架构:
VGGNet 常见的架构包括 VGG-16 和 VGG-19,它们的区别在于网络的深度。
VGG-16:包含 16 层带参数的层,具体结构如下:
13 层卷积层(3×3 卷积核,通道数逐步增加)
5 个最大池化层(2×2 池化核)
3 个全连接层(4096 个神经元,4096 个神经元,1000 个神经元用于 ImageNet 数据集的 1000 类分类)
VGG-19:包含 19 层带参数的层,卷积层更多,结构类似于 VGG-16,但更深。
优缺点:
优点:
简单性:VGGNet 的设计非常简单,卷积层只使用 3×3 的卷积核,并且结构高度一致,易于理解和实现。
深度带来的性能:由于网络的深度较大,VGGNet 在图像分类等任务上的表现非常好,尤其在 ImageNet 数据集上取得了非常低的错误率。
迁移学习:VGGNet 预训练的模型在很多计算机视觉任务中被广泛用于迁移学习,例如目标检测、图像分割等。
缺点:
计算成本高:VGGNet 由于深度和大量的卷积核,计算量非常大,尤其是在推理阶段,模型的计算开销较高。
参数量大:VGG-16 和 VGG-19 包含大量的参数,尤其是全连接层的参数,导致模型占用的内存较多。
固定输入尺寸:VGGNet 要求输入图像的尺寸固定为 224×224,这在某些应用场景中不够灵活。
应用:
VGGNet 在计算机视觉领域得到了广泛应用,包括但不限于:
图像分类:在 ImageNet 等大规模图像分类任务上表现出色。
目标检测:VGGNet 被用作很多目标检测算法(如 Faster R-CNN
本demo模仿标准VGG,创建一个简化版的VGG网络。
新建vggNet.py:
import warnings
import torch
import torch.nn as nn
import torch.nn.functional as F
# 忽略警告
warnings.filterwarnings('ignore')
class VGGbase(nn.Module):
def __init__(self, num_classes=10):
super(VGGbase, self).__init__()
self.conv1 = nn.Sequential( # 定义第1个卷积层
# Sequential 是一个容器,它可以包含一系列的神经网络层(layers),并按顺序执行它们。具体来说,
# nn.Sequential( 允许您将多个层定义为一个整体,这个整体可以被视为一个单独的层。
# 当您向神经网络传递数据时,数据会依次通过 Sequential 中定义的每一层。
# 这种方式简化了网络结构的定义和理解,尤其是在构建较为复杂的网络时。
nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1), # 输入通道为3,输出通道为64,卷积核大小为3x3,步长为1,填充为1
nn.BatchNorm2d(64), # 批量归一化
# nn.BatchNorm2d 表示对二维输入进行批量归一化,参数 64 通常代表输入特征的通道数。批量归一化的作用是在神经网络训练过程中,对每一批次的数据进行归一化处理,
# 使得数据的分布更加稳定,有助于加速训练过程、提高模型的泛化能力。
nn.ReLU() # 激活函数
)
self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2) # 最大池化,池化核大小为2x2,步长为2
# 经过第一层卷积后,图像的尺寸为 16x16,通道数为64
self.conv2_1 = nn.Sequential( # 定义第2个卷积层的第一次卷积
nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1), # 输入通道为64,输出通道为128,卷积核大小为3x3,步长为1,填充为1
nn.BatchNorm2d(128), # 批量归一化
nn.ReLU() # 激活函数
)
self.conv2_2 = nn.Sequential( # 定义第2个卷积层的第二次卷积
nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1), # 输入通道为64,输出通道为128,卷积核大小为3x3,步长为1,填充为1
nn.BatchNorm2d(128), # 批量归一化
nn.ReLU() # 激活函数
)
self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2) # 最大池化,池化核大小为2x2,步长为2
# 经过第二层卷积后,图像的尺寸为 8x8,通道数为128
self.conv3_1 = nn.Sequential( # 定义第3个卷积层的第一次卷积
nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1), # 输入通道为64,输出通道为128,卷积核大小为3x3,步长为1,填充为1
nn.BatchNorm2d(256), # 批量归一化
nn.ReLU() # 激活函数
)
self.conv3_2 = nn.Sequential( # 定义第3个卷积层的第二次卷积
nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(256), # 批量归一化
nn.ReLU() # 激活函数
)
self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2)
# 经过第三层卷积后,图像的尺寸为 4x4,通道数为256
self.conv4_1 = nn.Sequential( # 定义第4个卷积层的第一次卷积
nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(512), # 批量归一化
nn.ReLU() # 激活函数
)
self.conv4_2 = nn.Sequential( # 定义第4个卷积层的第二次卷积
nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
nn.BatchNorm2d(512), # 批量归一化
nn.ReLU() # 激活函数
)
self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2) # 最大池化,池化核大小为2x2,步长为2
# 经过第四层卷积后,图像的尺寸为 2x2,通道数为512
self.fc = nn.Linear(512 * 4, num_classes) # 全连接层,输入为512*4,输出为10
def forward(self, x): # 定义前向传播过程
batch_size = x.size(0) # 获取输入的batch_size
x = self.conv1(x) # 第1个卷积层
x = self.pool1(x) # 第1个池化层
x = self.conv2_1(x) # 第2个卷积层
x = self.conv2_2(x) # 第2个卷积层
x = self.pool2(x) # 第2个池化层
x = self.conv3_1(x) # 第3个卷积层
x = self.conv3_2(x) # 第3个卷积层
x = self.pool3(x) # 第3个池化层
x = self.conv4_1(x) # 第4个卷积层
x = self.conv4_2(x) # 第4个卷积层
x = self.pool4(x) # 第4个池化层
x = x.view(batch_size, -1) # 将图片展开成一行,-1表示自动计算这一维的大小
x = self.fc(x) # 全连接层
output = F.log_softmax(x, dim=1) # 对输出进行log_softmax处理
return output
def VGGNet(): # 定义网络结构的应用函数
return VGGbase()