什么是NiN网络?
NiN(Network in Network)是2013年由Lin Min等人提出的一种新型卷积神经网络结构。与传统卷积神经网络相比,NiN在每个卷积层之后引入了1x1卷积层,以增强网络的表达能力和非线性特性。
NiN网络的主要特点
- 1x1卷积层:每个卷积层后增加1x1卷积层,用于对特征通道进行线性组合,增加网络的非线性表达能力。
- 全局平均池化:NiN网络用全局平均池化层代替全连接层,减少参数数量和防止过拟合。
- 更深的网络:通过叠加多个NiN块,形成更深层次的网络结构,提取更复杂的特征。
NiN块结构
一个典型的NiN块包括一个卷积层和两个1x1卷积层:
def nin_block(in_channels, out_channels, kernel_size, strides, padding):
return nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size, strides, padding),
nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU())
实验与分析
实验背景
根据《动手学深度学习7.3》练习2的问题,研究为什么NiN块中有两个1x1卷积层,并分析删除其中一个卷积层后的影响。
实验设计
- 原始NiN块:包括两个1x1卷积层。
- 修改后的NiN块:删除一个1x1卷积层,只保留一个。
def nin_block(in_channels, out_channels, kernel_size, strides, padding):
return nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size, strides, padding),
nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU())
同时加入简单的调参实验,修改学习率和批量大小,结果如下:
配置 | 学习率 | 批量大小 | 训练精度 | 测试精度 | 训练损失 | 训练速度(examples/sec |
两个1x1卷积层 | 0.1 | 64 | 0.885 | 0.889 | 0.312 | 1228.7 |
一个1x1卷积层 | 0.1 | 64 | 0.283 | 0.292 | 1.910 | 1530.3 |
两个1x1卷积层 | 0.1 | 128 | 0.814 | 0.820 | 0.503 | 1460.4 |
两个1x1卷积层 | 0.01 | 128 | 0.527 | 0.479 | 1.260 | 1472.5 |
实验分析
-
表达能力:
- 两个1x1卷积层:增加了网络的表达能力,使其能够提取和组合更多复杂的特征,得到较高的训练和测试精度。
- 删除一个1x1卷积层:降低了网络的表达能力,模型无法有效提取复杂特征,训练和测试精度显著下降。
-
训练损失:
- 两个1x1卷积层:较低的训练损失表明模型能够更好地拟合训练数据。
- 删除一个1x1卷积层:较高的训练损失表明模型欠拟合,无法有效学习训练数据中的模式。
-
学习率和批量大小对比:
- 学习率为0.1时,训练和测试精度较高,尤其是批量大小为64时性能最好。
- 学习率为0.01时,训练和测试精度显著下降,表明学习率过低可能导致模型收敛速度慢,难以达到较好的效果。
-
训练速度:
- 删除一个1x1卷积层后由于计算量减少,训练速度略有提升,但代价是性能显著下降。
理论研讨与总结
- 1x1卷积层的作用:1x1卷积层的主要作用是对输入特征进行通道间的线性组合,增加网络的非线性表达能力。这使得网络在特征提取过程中更加灵活,能够捕捉到更复杂的模式。
- 删除一个1x1卷积层的影响:删除一个1x1卷积层后,网络的表达能力下降,导致模型在训练和测试数据上的表现显著变差。这表明1x1卷积层在NiN块中的重要性。
通过实验结果可以看出,1x1卷积层在NiN块中起到了关键作用。删除其中一个1x1卷积层会显著降低模型的表达能力,从而影响模型的性能。NiN网络通过增加1x1卷积层,增强了网络的非线性和表达能力,使其能够更好地提取和组合复杂的特征,从而提高模型的准确性和泛化能力。这一实验进一步验证了1x1卷积层在现代卷积神经网络设计中的重要性。
调参实验结果表明,合理选择学习率和批量大小对模型性能的影响也非常重要。较高的学习率(如0.1)在本次实验中表现较好,而较低的学习率(如0.01)则导致模型难以有效训练。批量大小从128减少到64显著提高了训练和测试精度,表明在本次实验中较小的批量大小有助于模型性能的提升。通过合理调参,可以进一步提升模型的性能。
基线实验代码
import torch
from torch import nn
from d2l import torch as d2l
import os
import torchvision
data_dir = '自行设置地址'
os.makedirs(data_dir, exist_ok=True)
def load_data_fashion_mnist(batch_size, resize=None, root=data_dir):
trans = [torchvision.transforms.ToTensor()]
if resize:
trans.insert(0, torchvision.transforms.Resize(resize))
trans = torchvision.transforms.Compose(trans)
mnist_train = torchvision.datasets.FashionMNIST(
root=root, train=True, transform=trans, download=True)
mnist_test = torchvision.datasets.FashionMNIST(
root=root, train=False, transform=trans, download=True)
return (torch.utils.data.DataLoader(mnist_train, batch_size, shuffle=True,
num_workers=d2l.get_dataloader_workers()),
torch.utils.data.DataLoader(mnist_test, batch_size, shuffle=False,
num_workers=d2l.get_dataloader_workers()))
# NiN块
def nin_block(in_channels, out_channels, kernel_size, strides, padding):
return nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size, strides, padding),
nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1), nn.ReLU())
# NiN模型
net = nn.Sequential(
nin_block(1, 96, kernel_size=11, strides=4, padding=0),
nn.MaxPool2d(3, stride=2),
nin_block(96, 256, kernel_size=5, strides=1, padding=2),
nn.MaxPool2d(3, stride=2),
nin_block(256, 384, kernel_size=3, strides=1, padding=1),
nn.MaxPool2d(3, stride=2),
nn.Dropout(0.5),
# 标签类别数是10
nin_block(384, 10, kernel_size=3, strides=1, padding=1),
nn.AdaptiveAvgPool2d((1, 1)),
# 将四维的输出转成二维的输出,其形状为(批量大小,10)
nn.Flatten())
X = torch.rand(size=(1, 1, 224, 224))
for layer in net:
X = layer(X)
print(layer.__class__.__name__,'output shape:\t', X.shape)
lr, num_epochs, batch_size = 0.1, 10, 128
train_iter, test_iter = load_data_fashion_mnist(batch_size, resize=224)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())