LeNet-5科学家Yann LeCun在1998年发表论文《Gradient based learning applied to document-recognition》上提出的一个神经网络模型,是最早期的卷积神经网络,论文中,作者将LeNet-5应用于于灰度图像的数字识别中获得了不错的效果。关于LeNet-5卷积神经网络原理,在上一篇介绍卷积神经网络入门博客中已经阐述清楚,本篇中,我们主要对LeNet-5使用TensorFlow进行实现。 LeNet-5网络结构如下所示:
接下来,本文就上图所示LeNet-5结构进行实现。
import tensorflow as tf import numpy as np import matplotlib.pyplot as plt from tensorflow import keras from tensorflow.keras import datasets, layers, optimizers, Sequential ,metrics
TensorFlow中自带手写数字识别图像数据集,使用datasets模块进行加载即可。
(x, y), (x_test, y_test) = datasets.mnist.load_data()
查看数据的数量和图像size:
print(x.shape, y.shape) print(x_test.shape, y_test.shape)
(60000, 28, 28) (60000,) (10000, 28, 28) (10000,)
可见,训练集中包含60000张图像,测试集中包含10000章图像,图像大小为2828。图像size与上图LeNet-5卷积网络中所用3232数据集有所不同,不过没关系,我们在第一层卷积层中对图像进行padding即可。
使用matplotlib对数据集进行展示,如下所示,图片上方数字为图像对应的数字。
index = 1 fig, axes = plt.subplots(4, 3, figsize=(8, 4), tight_layout=True) for row in range(4): for col in range(3): axes[row, col].imshow(x[index]) axes[row, col].axis('off') axes[row, col].set_title(y[index]) index += 1 plt.show()
刚加载好的图像是numpy数组形式,元素值在0~255之间,需要进行类型转换和归一化。这里我们定义一个preprocess作为预处理函数,在将数据集打包成TensorFlow的dataset形式后,使用map函数调用preprocess对数据进行预处理更加方便。
def preprocess(x, y): x = tf.cast(x, dtype=tf.float32) / 255. x = tf.reshape(x,[28,28,1]) y = tf.cast(y, dtype=tf.int32) return x, y
batchs = 32 # 每个簇的大小,批量梯度下降法时每一批的包含图像的数量
打包成TensorFlow到的dataset对象,并随机打乱数据:
db = tf.data.Dataset.from_tensor_slices((x, y)) db = db.map(preprocess).shuffle(10000).batch(batchs)
对测试集同样打包成dataset,不过测试集可以不随机打乱:
db_test = tf.data.Dataset.from_tensor_slices((x_test, y_test)) db_test = db_test.map(preprocess).batch(batchs)
net_layers = [ # 卷积部分网络 # 第一个卷积层:5*5*6 # 这个padding在最初的LeNet-5网络中是没有的,那时候还没有padding的概念,为了使这一层输出与元素LeNet-5网络保持一致,所以这里添加padding操作 layers.Conv2D(6, kernel_size=[5,5],padding='same', activation='relu'), # 6个5*5的卷积核,进行padding # 池化层 layers.MaxPool2D(pool_size=[2, 2], strides=2), # 池化层大小2*2,步长2 # layers.ReLU() # 第二个池化层:5*5*16 layers.Conv2D(16, kernel_size=[5,5],padding='valid', activation='relu'), # 池化层 layers.MaxPool2D(pool_size=[2, 2], strides=2), # layers.ReLU() layers.Flatten(), # 展平成一维数组 # 全连接层 layers.Dense(120,activation='relu'), layers.Dense(84,activation='relu'), layers.Dense(10,activation='softmax') ]
model = tf.keras.models.Sequential(net_layers) # 将上面创建的层合并打包成模型 model.build(input_shape=(None, 28, 28, 1)) # 指定输入数据形状 optimizer = tf.keras.optimizers.SGD(learning_rate=0.01) # 创建优化器 model.compile(optimizer=optimizer, # 配置模型 loss='sparse_categorical_crossentropy', # 指定损失函数 metrics=['accuracy']) model.fit(db,epochs=5, validation_data=db_test) # 训练模型
Epoch 1/5 1875/1875 [==============================] - 46s 25ms/step - loss: 0.5028 - accuracy: 0.8513 - val_loss: 0.0000e+00 - val_accuracy: 0.0000e+00 Epoch 2/5 1875/1875 [==============================] - 42s 22ms/step - loss: 0.1257 - accuracy: 0.9619 - val_loss: 0.1051 - val_accuracy: 0.9671 Epoch 3/5 1875/1875 [==============================] - 42s 23ms/step - loss: 0.0928 - accuracy: 0.9716 - val_loss: 0.0798 - val_accuracy: 0.9742 Epoch 4/5 1875/1875 [==============================] - 43s 23ms/step - loss: 0.0746 - accuracy: 0.9766 - val_loss: 0.0666 - val_accuracy: 0.9785 Epoch 5/5 1875/1875 [==============================] - 41s 22ms/step - loss: 0.0638 - accuracy: 0.9801 - val_loss: 0.0580 - val_accuracy: 0.9800
<tensorflow.python.keras.callbacks.History at 0x7fba79d4b610>
可以看到,经过5轮迭代之后,模型的准确率达到98.01%,这在当时已经是相当不错的成绩。 上述代码对LeNet-5卷积神经网络进行实现,网络一共包含7层(激活函数不计算在内),注意,上文中实现的是现代版的LeNet卷积网络,与最初Yann LeCun论文中描述的LeNet-5在结构上是一致的,不过,现代版的LeNet-5网络更多使用ReLU激活函数作为中间层激活函数和Softmax在输出层转化为概率输出,另外在池化层现代更多用最大池化,而不是当初的平均池化。
文章来源: 博客园
原文链接: https://www.cnblogs.com/chenhuabin/p/12840434.html
客服
官方群
服务时间: