# VGG Nin
def vgg_block(num_convs, in_channels, out_channels): # num_convs 是卷积层的数量,指定了该卷积块中包含多少个卷积层,in_channels 是输入通道数,指定了输入数据的通道数。out_channels 是输出通道数,指定了输出数据的通道数。
layers = [] # 创建一个空列表,用于存储卷积块中的不同层。
for _ in range(num_convs):
layers.append(nn.Conv2d(in_channels, out_channels,
kernel_size=3, padding=1))
layers.append(nn.ReLU())
in_channels = out_channels # 在每次循环结束后,将 in_channels 更新为 out_channels,以便下一个卷积层使用正确的输入通道数。
layers.append(nn.MaxPool2d(kernel_size=2,stride=2)) # 最后,向 layers 列表中添加一个最大池化层
return nn.Sequential(*layers) # 最后,将创建的卷积块的各个层打包成一个 nn.Sequential 容器,以便将其作为一个整体使用。
与AlexNet、LeNet一样,VGG网络可以分为两部分:第一部分主要由卷积层和池化层组成,第二部分由全连接层组成。
下面的代码实现了VGG-11。
def vgg(conv_arch): #conv_arch 是一个包含卷积块配置的列表。每个元素都是一个元组,包含两个值:
#num_convs 是卷积块中的卷积层数量。
#out_channels 是卷积块的输出通道数。
conv_blks = [] # 创建一个空列表 conv_blks,用于存储VGG网络中的卷积块。
in_channels = 1 # 初始化输入通道数为1,这适用于灰度图像输入。
# 卷积层部分
for (num_convs, out_channels) in conv_arch:
conv_blks.append(vgg_block(num_convs, in_channels, out_channels)) # 调用 vgg_block 函数,根据卷积块配置创建一个卷积块,并将其添加到 conv_blks 列表中。
in_channels = out_channels # 更新 in_channels 为当前卷积块的输出通道数,以便将其作为下一个卷积块的输入通道数。
return nn.Sequential(
*conv_blks, nn.Flatten(), # 卷积层输出的特征图展平成一维向量。
# 全连接层部分
nn.Linear(out_channels * 7 * 7, 4096), nn.ReLU(), nn.Dropout(0.5), # 一个具有4096个隐藏单元的全连接层。
nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(0.5),
nn.Linear(4096, 10)) # 表示输出层,输出10个类别的分类结果。
net = vgg(conv_arch)
import torch
from torch import nn
from d2l import torch as d2l
def nin_block(in_channels, out_channels, kernel_size, strides, padding):
return nn.Sequential( # 创建了一个 nn.Sequential 容器,其中包含了一系列的卷积层和ReLU激活函数。
nn.Conv2d(in_channels, out_channels, kernel_size, strides, padding), # 卷积层
nn.ReLU(), # Relu激活函数
nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU(), # 卷积核大小为1的卷积层+激活函数
nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU()) # 卷积核大小为1的卷积层+激活函数
NiN和AlexNet之间的一个显著区别是NiN完全取消了全连接层。NiN设计的一个优点是,它显著减少了模型所需参数的数量。然而,在实践中,这种设计有时会增加训练模型的时间。
Nin模型
net = nn.Sequential(
nin_block(1, 96, kernel_size=11, strides=4, padding=0), # 第一层NiN块,输入通道数为1,输出通道数为96,卷积核大小为11x11,步幅为4,没有填充。
nn.MaxPool2d(3, stride=2), # 第一个最大池化层,池化窗口大小为3x3,步幅为2。它用于降低特征图的空间维度。
nin_block(96, 256, kernel_size=5, strides=1, padding=2), # 第二层NiN块,输入通道数为96,输出通道数为256,卷积核大小为5x5,步幅为1,填充为2
nn.MaxPool2d(3, stride=2), # 第二个最大池化层,池化窗口大小为3x3,步幅为2。
nin_block(256, 384, kernel_size=3, strides=1, padding=1),
nn.MaxPool2d(3, stride=2),
nn.Dropout(0.5), # Dropout层,用于随机丢弃一部分神经元,以减少过拟合。
# 标签类别数是10
nin_block(384, 10, kernel_size=3, strides=1, padding=1),
nn.AdaptiveAvgPool2d((1, 1)), # 自适应平均池化层,用于将特征图的大小调整为1x1。
# 将四维的输出转成二维的输出,其形状为(批量大小,10)
nn.Flatten()) # 将四维的输出展平成二维的输出,其形状为(批量大小,10),其中10是标签类别数。