LeNet
卷积神经网络
net = nn.Sequential()
net.add(
nn.Conv2D(channels=6, kernel_size=5, activation='sigmoid'),
nn.MaxPool2D(pool_size=2, strides=2),
nn.Conv2D(channels=16, kernel_size=5, activation='sigmoid'),
nn.MaxPool2D(pool_size=2, strides=2),
# Dense 会默认将(批量大小,通道,高,宽)形状的输入转换成
#(批量大小,通道 * 高 * 宽)形状的输入。
nn.Dense(120, activation='sigmoid'),
nn.Dense(84, activation='sigmoid'),
nn.Dense(10)
)
尝试基于 LeNet 构造更复杂的网络来改善精度。例如,调整卷积窗口大小、输出通道数、激活函数和全连接层输出个数。在优化方面,可以尝试使用不同的学习率、初始化方法以及增加迭代周期。
AlexNet
深度卷积神经网络
AlextNet 与 LeNet 的设计理念非常相似。但也有显著的区别。
- 第一,与相对较小的 LeNet 相比,AlexNet 包含 8 层变换,其中有五层卷积和两层全连接隐含层,以及一个全连接输出层。
第一层中的卷积窗口形状是 11×11。因为 ImageNet 中绝大多数图像的高和宽均比 MNIST 图像的高和宽大十倍以上,ImageNet 图像的物体占用更多的像素,所以需要更大的卷积窗口来捕获物体。第二层中的卷积窗口形状减小到 5×5,之后全采用 3×3。此外,第一、第二和第五个卷积层之后都使用了窗口形状为 3×3、步幅为 2 的最大池化层。而且,AlexNet 使用的卷积通道数也数十倍大于 LeNet 中的卷积通道数。
紧接着最后一个卷积层的是两个输出个数为 4096 的全连接层。这两个巨大的全连接层带来将近 1GB 的模型参数。由于早期 GPU 显存的限制,最早的 AlexNet 使用双数据流的设计使得一个 GPU 只需要处理一半模型。幸运的是 GPU 内存在过去几年得到了长足的发展,通常我们不再需要这样的特别设计了。
第二,AlextNet 将 sigmoid 激活函数改成了更加简单的 ReLU 激活函数。ReLU 激活函数的计算更简单,同时在不同的参数初始化方法下使模型更容易训练。
第三,通过丢弃法(参见“丢弃法”一节)来控制全连接层的模型复杂度。
第四,引入了大量的图像增广,例如翻转、裁剪和颜色变化,进一步扩大数据集来缓解过拟合。我们将在后面的“图像增广”一节详细介绍这些方法。
net = nn.Sequential()
net.add(
# 使用较大的 11 x 11 窗口来捕获物体。同时使用步幅 4 来较大减小输出高宽。
# 这里使用的输入通道数比 LeNet 也要大很多。
nn.Conv2D(96, kernel_size=11, strides=4, activation='relu'),
nn.MaxPool2D(pool_size=3, strides=2),
# 减小卷积窗口,使用填充为 2 来使得输入输出高宽一致,且增大输出通道数。
nn.Conv2D(256, kernel_size=5, padding=2, activation='relu'),
nn.MaxPool2D(pool_size=3, strides=2),
# 连续三个卷积层,且使用更小的卷积窗口。除了最后的卷积层外,进一步增大了输出通道数。
# 前两个卷积层后不使用池化层来减小输入的高宽。
nn.Conv2D(384, kernel_size=3, padding=1, activation='relu'),
nn.Conv2D(384, kernel_size=3, padding=1, activation='relu'),
nn.Conv2D(256, kernel_size=3, padding=1, activation='relu'),
nn.MaxPool2D(pool_size=3, strides=2),
# 使用比 LeNet 输出个数大数倍的全连接层。使用丢弃层来控制复杂度。
nn.Dense(4096, activation="relu"), nn.Dropout(0.5),
nn.Dense(4096, activation="relu"), nn.Dropout(0.5),
# 输出层。我们这里使用 Fashion-MNIST,所以用类别数 10,而非论文中的 1000。
nn.Dense(10)
)
AlexNet 跟 LeNet 结构类似,但使用了更多的卷积层和更大的参数空间来拟合大规模数据集 ImageNet。它是浅层神经网络和深度神经网络的分界线。虽然看上去 AlexNet 的实现比 LeNet 也就多了几行而已,但这个观念上的转变和真正优秀实验结果的产生,学术界为之整整花了 20 年
VGG
使用重复元素的网络
VGG 块
VGG 块的组成规律是:连续使用数个相同的填充为 1、窗口形状为 3×3 的卷积层后接上一个步幅为 2、窗口形状为 2×2 的最大池化层。卷积层保持输入的高和宽不变,而池化层则对其减半。我们使用vgg_block函数来实现这个基础的 VGG 块,它可以指定卷积层的数量num_convs和输出通道数num_channels。
def vgg_block(num_convs, num_channels):
blk = nn.Sequential()
for _ in range(num_convs):
blk.add(nn.Conv2D(
num_channels, kernel_size=3, padding=1, activation='relu'))
blk.add(nn.MaxPool2D(pool_size=2, strides=2))
return blk
VGG 网络
VGG 网络同 AlexNet 和 LeNet 一样是由卷积层模块后接全连接层模块构成。卷积层模块串联数个vgg_block,其超参数由变量conv_arch定义。该变量指定了每个 VGG 块里卷积层个数和输出通道数。全连接模块则跟 AlexNet 中的一样。
现在我们构造一个 VGG 网络。它有 5 个卷积块,前两块使用单卷积层,而后三块使用双卷积层。第一块的输出通道是 64,之后每次对输出通道数翻倍,直到变为 512。因为这个网络使用了 8 个卷积层和 3 个全连接层,所以经常被称为 VGG-11。