
本文将深入解析NiN(Network in Network)这一经典的卷积网络架构,并通过TensorFlow框架,在Fashion-MNIST数据集上完成一个服饰图像分类的实战项目。你将了解到NiN如何利用1×1卷积与全局平均池化来优化传统CNN的结构。
CNN结构的演进与NiN的提出
在卷积神经网络(CNN)的发展历程中,VGG等模型通过堆叠卷积层来加深网络,以提取更复杂、更抽象的特征。然而,传统的CNN架构在卷积层之后,通常会连接一个或多个全连接层,最终通过Softmax函数输出分类结果。这种结构存在一些固有的缺点。
传统CNN的局限性
- 参数量庞大:全连接层的神经元需要与上一层所有的特征图进行连接,这导致了巨大的参数量。例如,若上一层输出为
7x7x512的特征图,那么一个仅包含1024个神经元的全连接层,其参数量就将高达7*7*512*1024,极易引发过拟合。
- 空间信息丢弃:在进入全连接层前,特征图通常需要被展平(Flatten)成一维向量,这彻底破坏了特征图原有的空间结构信息。
- 可解释性弱:全连接层如同一个“黑盒”,难以直观理解其学习到的特征与输入图像的空间对应关系。
NiN网络的创新思路
NiN网络的核心思想是用“微型网络”(即多层感知机MLP)结构来局部替代传统的线性卷积层,并使用全局平均池化(Global Average Pooling)层来彻底取代全连接层。这一思想深刻影响了后续如GoogLeNet等网络的设计。
其中,起到关键作用的便是1×1卷积。在人工智能领域的卷积神经网络设计中,1×1卷积是一种巧妙的“通道融合”与“降维/升维”工具。它可以跨通道集成信息,在不改变特征图空间尺寸的前提下,灵活地调整通道数,从而构建更复杂、非线性的特征组合。
NiN块:网络中的“网络”
NiN块是NiN网络的基本组成单元。一个标准的NiN块由多层卷积层堆叠而成,其经典结构为:
- 第一层:普通卷积层(如
11x11, 5x5等)
- 后续层(通常为2层):
1x1卷积层
这相当于在每个局部感受野后,插入了一个微型的全连接网络(MLP),增强了模型的非线性表示能力。
NiN模型架构
一个完整的NiN模型通常交替堆叠多个NiN块和步幅为2的最大池化层,以逐步缩小特征图尺寸、增加通道数。其最大的特点在于网络的末端:
- 最后一个NiN块输出的特征图通道数,直接设置为目标分类的类别数。
- 对该特征图执行全局平均池化:对每个通道的特征图,计算所有像素点的平均值。由于通道数等于类别数,因此每个通道的平均值就直接代表了对应类别的置信度。
- 将这些平均值直接送入Softmax层得到最终分类概率。
这样做的好处是:
- 极大减少参数:完全移除了全连接层,参数数量大幅下降,有效缓解过拟合。
- 保留空间信息:输出与输入图像在空间上有一定的对应关系,增强了模型的解释性。
- 更自然的正则化:全局平均池化本身对输入的空间变换具有更强的鲁棒性。
使用TensorFlow实现NiN进行服饰分类
下面我们将使用TensorFlow和Keras接口,构建一个NiN网络,并在经典的计算机视觉入门数据集Fashion-MNIST上进行训练和评估。
首先,确保你的TensorFlow环境就绪。
import tensorflow as tf
print("TensorFlow version:", tf.__version__)
TensorFlow version: 2.x.x
定义NiN模型
我们使用Keras的Sequential API来构建模型。每个NiN块我们采用“卷积层 + 两个1×1卷积层”的结构。
from tensorflow.keras import layers, models
def nin_block(num_channels, kernel_size, strides, padding):
blk = models.Sequential()
blk.add(layers.Conv2D(num_channels, kernel_size, strides=strides, padding=padding, activation='relu'))
blk.add(layers.Conv2D(num_channels, kernel_size=1, activation='relu'))
blk.add(layers.Conv2D(num_channels, kernel_size=1, activation='relu'))
return blk
model = models.Sequential([
# 第一个NiN块, 使用较大卷积核捕获初始特征
nin_block(96, kernel_size=11, strides=4, padding='valid'),
layers.MaxPool2D(pool_size=3, strides=2),
layers.Dropout(0.5), # 添加Dropout防止过拟合
# 第二个NiN块, 减少卷积核尺寸
nin_block(256, kernel_size=5, strides=1, padding='same'),
layers.MaxPool2D(pool_size=3, strides=2),
layers.Dropout(0.5),
# 第三个NiN块, 进一步增加通道数
nin_block(384, kernel_size=3, strides=1, padding='same'),
layers.MaxPool2D(pool_size=3, strides=2),
# 第四个NiN块, 输出通道数置为类别数10
nin_block(10, kernel_size=3, strides=1, padding='same'),
# 全局平均池化层, 替代全连接层
layers.GlobalAveragePooling2D(),
# 将10个通道的平均值转换为10个类别的概率分布
layers.Activation('softmax')
])
model.build(input_shape=(None, 224, 224, 3)) # 构建模型, 指定输入尺寸
model.summary()
读取与预处理Fashion-MNIST数据集
Fashion-MNIST图像尺寸为28x28,而我们的网络初始输入期望较大(如224x224)。为了简单演示,我们这里调整网络第一层参数,并直接使用28x28的输入。在实际复杂图像任务中,需要调整输入尺寸或网络结构。
from tensorflow.keras.datasets import fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
# 数据归一化并增加通道维度
train_images = train_images.reshape((60000, 28, 28, 1)).astype('float32') / 255
test_images = test_images.reshape((10000, 28, 28, 1)).astype('float32') / 255
# 修改模型第一层, 适配28x28的输入
# 此处为演示, 简化了网络第一层的卷积核和步幅
model = models.Sequential([
nin_block(96, kernel_size=3, strides=1, padding='same'), # 调整以适应小图片
layers.MaxPool2D(pool_size=3, strides=2),
nin_block(256, kernel_size=3, strides=1, padding='same'),
layers.MaxPool2D(pool_size=3, strides=2),
nin_block(384, kernel_size=3, strides=1, padding='same'),
layers.MaxPool2D(pool_size=3, strides=2),
nin_block(10, kernel_size=3, strides=1, padding='same'),
layers.GlobalAveragePooling2D(),
layers.Activation('softmax')
])
编译与训练模型
我们使用Adam优化器和稀疏分类交叉熵损失函数来编译模型。
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 开始训练
history = model.fit(train_images, train_labels,
epochs=10,
batch_size=64,
validation_split=0.2) # 使用20%训练数据作为验证集
评估与可视化结果
训练完成后,在测试集上评估模型的最终性能。
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
print(f'\n测试准确率:{test_acc:.4f}')
小结
通过本次实战,我们实现了NiN网络的核心思想:
- 构建NiN块:利用
1×1卷积增强非线性,模拟微型MLP。
- 摒弃全连接层:通过将末层特征图通道数设为类别数,并接续全局平均池化层,直接得到分类结果。这一设计在减少参数、防止过拟合的同时,提升了模型的可解释性,是深度学习模型设计中的一个重要思路。
- 应用于Fashion-MNIST:尽管原始NiN是为更大尺寸图像设计,我们通过调整使其能在此数据集上运行,验证了其基础架构的有效性。
NiN虽然参数量少,但在当时达到了 competitive 的性能,其提出的1×1卷积与全局平均池化思想,为后续更高效的网络架构(如ResNet、SqueezeNet等)奠定了重要基础。