NiN——Network in Network
LeNet、AlexNet和VGG设计上的共同之处是:先由卷积层构成的模块充分抽取空间特征,再以由全连接层构成的模块来输出分类结果。而AlexNet和VGG对LeNet的改进在于如何对这两个模块进行加宽(增加通道数)和加深。
而NiN提供了另外一个思路:串联多个卷积层和“全连接”层构成的小网络来构建一个深层网络。
这里的全连接层是有引号的,因为卷积层的输入通常是四维数组(样本,通道,高,宽),而全连接层的输出则是二维数组(样本, 特征),所以想在全连接层后再接上卷积层,则需要将全连接层的输出变换为四维。
因此,NiN使用1x1的卷积层来充当全连接层。其中空间维度(高和宽)上的每个元素相当于样本,通道相当于特征。其和AlexNet和VGG等网络再结构上的区别如下图所示(只是局部图):
![](https://img-blog.csdnimg.cn/20191013161520815.png)
NiN-Block:
import d2lzh as d2l
from mxnet import gluon, init, nd
from mxnet.gluon import nn
def nin_block(num_channels, kernel_size, strides, padding):
blk = nn.Sequential()
blk.add(nn.Conv2D(num_channels, kernel_size,
strides, padding, activation='relu'),
nn.Conv2D(num_channels, kernel_size=1, activation='relu'),
nn.Conv2D(num_channels, kernel_size=1, activation='relu'))
return blk
NiN模型(通过NiN-Block构建):
net = nn.Sequential()
net.add(nin_block(96, kernel_size=11, strides=4, padding=0),
nn.MaxPool2D(pool_size=3, strides=2),
nin_block(256, kernel_size=5, strides=1, padding=2),
nn.MaxPool2D(pool_size=3, strides=2),
nin_block(384, kernel_size=3, strides=1, padding=1),
nn.MaxPool2D(pool_size=3, strides=2), nn.Dropout(0.5),
# 标签类别数是10
nin_block(10, kernel_size=3, strides=1, padding=1),
# 全局平均池化层将窗口形状自动设置成输入的高和宽
nn.GlobalAvgPool2D(),
# 将四维的输出转成二维的输出,其形状为(批量大小, 10)
nn.Flatten())
# 查看模型的形状
X = nd.random.uniform(shape=(1, 1, 224, 224))
net.initialize()
for layer in net:
X = layer(X)
print(layer.name, 'output shape:\t', X.shape)
模型训练(又到了我的电脑跑不动的训练时刻 /哭哭):
lr, num_epochs, batch_size, ctx = 0.1, 5, 128, d2l.try_gpu()
net.initialize(force_reinit=True, ctx=ctx, init=init.Xavier())
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': lr})
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
d2l.train_ch5(net, train_iter, test_iter, batch_size, trainer, ctx,
num_epochs)
参考资料:
动手学深度学习——阿斯顿张、李沐