(四)卷积神经网络 -- 5 LeNet

5. 卷积神经网络(LeNet)

构造一个含单隐藏层的多层感知机模型来对Fashion-MNIST数据集中的图像进行分类(每张图像高和宽均是28像素,将图像中的像素逐行展开,得到长度为784的向量,并输入全连接层中),这种分类方法存在一定的局限性,包括:
(1) 图像在同一列邻近的像素在该向量中可能相距较远,它们构成的模式可能难以被模型识别。
(2) 对于大尺寸的输入图像,使用全连接层容易导致模型过大,带来过于复杂的模型和过高的存储开销。

假设输入是高和宽均为 1 , 000 1,000 1,000像素的彩色照片(含3个通道),即使全连接层输出个数仍是256,该层权重参数的形状也是 3 , 000 , 000 × 256 3,000,000\times 256 3,000,000×256,占用了约3 GB的内存或显存。

卷积层尝试解决上述两个问题:
一方面,卷积层保留输入形状,使图像的像素在高和宽两个方向上的相关性均可能被有效识别;
另一方面,卷积层通过滑动窗口将同一卷积核与不同位置的输入重复计算,从而避免参数尺寸过大。

卷积神经网络是含卷积层的网络。
本节将介绍一个早期用来识别手写数字图像的卷积神经网络:LeNet,其名字来源于LeNet论文的第一作者Yann LeCun。

LeNet展示了通过梯度下降训练卷积神经网络,可以达到当时手写数字识别最先进的结果。
这个奠基性的工作,第一次将卷积神经网络推上舞台,为世人所知。


5.1 LeNet模型

5.1.1 概念

LeNet分为卷积层块和全连接层块两个部分,分别介绍如下:

(1) 卷积层块
卷积层块中的基本单位是:卷积层后接最大池化层。
卷积层用来识别图像中的空间模式,如线条和物体局部;之后的最大池化层则用来降低卷积层对位置的敏感性。

卷积层块由上述两个基本单位重复堆叠构成:
每个卷积层都使用 5 × 5 5\times 5 5×5的窗口,并在输出上使用sigmoid激活函数。
第一个卷积层输出通道数为6,第二个卷积层输出通道数则增加到16。(这是因为第二个卷积层比第一个卷积层的输入的高和宽要小,所以增加输出通道使两个卷积层的参数尺寸类似。)
两个最大池化层的窗口形状均为 2 × 2 2\times 2 2×2,且步幅为2。(由于池化窗口与步幅形状相同,池化窗口在输入上每次滑动所覆盖的区域互不重叠。)

卷积层块的输出形状为(批量大小, 通道, 高, 宽)。

(2) 全连接层块
当卷积层块的输出传入全连接层块时,全连接层块会将小批量中每个样本变平(flatten)。
即,全连接层的输入形状将变成二维。其中,第一维是小批量中的样本,第二维是每个样本变平后的向量表示,且向量长度为通道、高和宽的乘积。

全连接层块含3个全连接层,输出个数分别为120、84和10。其中,10为输出的类别个数。


5.1.2 代码示例

import tensorflow as tf
print(tf.__version__)
2.0.0

通过Sequential类来实现LeNet模型:

"""
tf.keras.layers.Conv2D:
    filters: Integer, the dimensionality of the output space.
    input_shape:
        When using this layer as the first layer in a model, 
        provide the keyword argument `input_shape` (tuple of integers, does not include the sample axis)
        e.g. `input_shape=(128, 128, 3)` for 128x128 RGB pictures in `data_format="channels_last"`.

"""

net = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(filters=6, kernel_size=5, activation='sigmoid', input_shape=(28, 28, 1)),
    tf.keras.layers.MaxPool2D(pool_size=2, strides=2),
    tf.keras.layers.Conv2D(filters=16, kernel_size=5, activation='sigmoid'),
    tf.keras.layers.MaxPool2D(pool_size=2, strides=2),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(units=120, activation='sigmoid'),
    tf.keras.layers.Dense(units=84, activation='sigmoid'),
    tf.keras.layers.Dense(units=10, activation='sigmoid')
])

构造一个高和宽均为28的单通道数据样本,并逐层进行前向计算来查看每个层的输出形状:

# data_format="channels_last"
X = tf.random.uniform(shape=(1,28,28,1))

for layer in net.layers:
    X = layer(X)
    print(layer.name, 'output shape: ', X.shape)

输出:

conv2d output shape:  (1, 24, 24, 6)
max_pooling2d output shape:  (1, 12, 12, 6)
conv2d_1 output shape:  (1, 8, 8, 16)
max_pooling2d_1 output shape:  (1, 4, 4, 16)
flatten output shape:  (1, 256)
dense output shape:  (1, 120)
dense_1 output shape:  (1, 84)
dense_2 output shape:  (1, 10)

由此可见,
卷积层块中,输入的高和宽在逐层减小(卷积层由于使用高和宽均为5的卷积核,从而将高和宽分别减小4)。
池化层将高和宽减半(窗口形状为 2 × 2 2\times 2 2×2且步幅为2),但通道数则从1增加到16。
全连接层逐层减少输出个数,直到变成图像的类别数10。



5.2 模型训练

5.2.1 数据集

使用Fashion-MNIST作为训练数据集。

fashion_mnist = tf.keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()

train_images = tf.reshape(train_images, shape=(train_images.shape[0], train_images.shape[1], train_images.shape[2], 1))
print(train_images.shape)

test_images = tf.reshape(test_images, shape=(test_images.shape[0], test_images.shape[1], test_images.shape[2], 1))

输出:

(60000, 28, 28, 1)

5.2.2 训练

损失函数和训练算法,依然采用交叉熵损失函数(cross entropy)和小批量随机梯度下降(SGD):

"""
tf.keras.optimizers.SGD:
    momentum: Accelerates SGD in the relevant direction and dampens oscillations.
    nesterov: Whether to apply Nesterov momentum.
"""

optimizer = tf.keras.optimizers.SGD(learning_rate=0.9, momentum=0.0, nesterov=False)

net.compile(optimizer=optimizer, 
            loss='sparse_categorical_crossentropy',
            metrics=['accuracy'])
# 训练
net.fit(train_images, train_labels, epochs=5, validation_split=0.1)

输出:

net.fit(train_images, train_labels, epochs=5, validation_split=0.1)
net.fit(train_images, train_labels, epochs=5, validation_split=0.1)
Train on 54000 samples, validate on 6000 samples
Epoch 1/5
54000/54000 [==============================] - 15s 286us/sample - loss: 1.3557 - accuracy: 0.4590 - val_loss: 0.6590 - val_accuracy: 0.7437
Epoch 2/5
54000/54000 [==============================] - 15s 275us/sample - loss: 0.6410 - accuracy: 0.7432 - val_loss: 0.5498 - val_accuracy: 0.7857
Epoch 3/5
54000/54000 [==============================] - 16s 289us/sample - loss: 0.5494 - accuracy: 0.7829 - val_loss: 0.5215 - val_accuracy: 0.7867
Epoch 4/5
54000/54000 [==============================] - 15s 273us/sample - loss: 0.5168 - accuracy: 0.7999 - val_loss: 0.5084 - val_accuracy: 0.8082
Epoch 5/5
54000/54000 [==============================] - 14s 253us/sample - loss: 0.4798 - accuracy: 0.8135 - val_loss: 0.4520 - val_accuracy: 0.8265
<tensorflow.python.keras.callbacks.History at 0x13bc3bad0>
# 预测
net.evaluate(test_images, test_labels, verbose=2)

输出:

10000/1 - 1s - loss: 0.3569 - accuracy: 0.8158
[0.4777470575332642, 0.8158]


参考

《动手学深度学习》(TF2.0版)
LeCun, Y.; Bottou, L.; Bengio, Y. & Haffner, P. (1998). Gradient-based learning applied to document recognition.Proceedings of the IEEE. 86(11): 2278 - 2324.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值