一.前提知识
多层感知机:由一个输入层,一个或多个隐藏层和一个输出层组成。(至少有一个隐藏层,即至少3层)
全连接层:是MLP的一种特殊情况,每个节点都与前一层的所有节点连接,全连接层可以解决线性可分问题,无法学习到非线性特征。(只有输入和输出层)
二.NiN模型特点
NiN与过去模型的区别:AlexNet和VGG对LeNet的改进在于如何扩大
和加深
这两个模块。他们都使用了全连接层
,使用全连接层就可能完全放弃表征的空间结构。
NiN放弃了使用全连接层
,而是使用两个1x1卷积层
(将空间维度中的每个像素视为单个样本,将通道维度视为不同特征。),相当于在每个像素的通道
上分别使用多层感知机
。
优点:NiN去除了全连接层,可以减少过拟合,同时显著减少NiN的参数数量
三.模型架构
四.代码
import torch
from torch import nn
from d2l import torch as d2l
import time
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(),
# 两个带有ReLU激活函数的 1x1卷积层
nn.Conv2d(out_channels,out_channels,kernel_size=1),nn.ReLU(),
nn.Conv2d(out_channels,out_channels,kernel_size=1),nn.ReLU()
)
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)),
# 将(样本,通道,w,h) = (批量,10,1,1),四维的输出转成2维的输出,其形状为(批量大小,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)
Sequential output shape: torch.Size([1, 96, 54, 54])
MaxPool2d output shape: torch.Size([1, 96, 26, 26])
Sequential output shape: torch.Size([1, 256, 26, 26])
MaxPool2d output shape: torch.Size([1, 256, 12, 12])
Sequential output shape: torch.Size([1, 384, 12, 12])
MaxPool2d output shape: torch.Size([1, 384, 5, 5])
Dropout output shape: torch.Size([1, 384, 5, 5])
Sequential output shape: torch.Size([1, 10, 5, 5])
AdaptiveAvgPool2d output shape: torch.Size([1, 10, 1, 1])
Flatten output shape: torch.Size([1, 10])
六.不同参数训练结果
学习率是0.1的情况
# 训练模型
lr,num_epochs,batch_size = 0.1,10,128
train_iter,test_iter = d2l.load_data_fashion_mnist(batch_size,resize=224)
d2l.train_ch6(net,train_iter,test_iter,num_epochs,lr,d2l.try_gpu())
学习率是0.05的情况(提升了6个点)
'''开始计时'''
start_time = time.time()
# 训练模型
lr,num_epochs,batch_size = 0.05,10,128
train_iter,test_iter = d2l.load_data_fashion_mnist(batch_size,resize=224)
d2l.train_ch6(net,train_iter,test_iter,num_epochs,lr,d2l.try_gpu())
'''计时结束'''
end_time = time.time()
run_time = end_time - start_time
# 将输出的秒数保留两位小数
print(f'{round(run_time,2)}s')
学习率为0.01,批次等于30的情况(反而下降了)
思考
为什么NiN块中有两个1x1卷积层?
从NiN替换掉全连接层,使用多层感知机角度来说:
因为1个1x1卷基层相当于全连接层,两个1x1卷积层使输入和输出层中间有了隐藏层,才相当于多层感知机。