<style></style> <style></style> <style></style> <style></style>
LeNet-5科學家Yann LeCun在1998年發表論文《Gradient based learning applied to document-recognition》上提出的一個神經網路模型,是最早期的卷積神經網路,論文中,作者將LeNet-5應用于于灰度影像的數字識別中獲得了不錯的效果,關于LeNet-5卷積神經網路原理,在上一篇介紹卷積神經網路入門博客中已經闡述清楚,本篇中,我們主要對LeNet-5使用TensorFlow進行實作,
LeNet-5網路結構如下所示:
接下來,本文就上圖所示LeNet-5結構進行實作,
In [25]: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模塊進行加載即可,
In [26]:(x, y), (x_test, y_test) = datasets.mnist.load_data()
查看資料的數量和影像size:
In [27]: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對資料集進行展示,如下所示,圖片上方數字為影像對應的數字,
In [28]: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對資料進行預處理更加方便,
In [29]: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, yIn [30]:
batchs = 32 # 每個簇的大小,批量梯度下降法時每一批的包含影像的數量
打包成TensorFlow到的dataset物件,并隨機打亂資料:
In [31]:db = tf.data.Dataset.from_tensor_slices((x, y)) db = db.map(preprocess).shuffle(10000).batch(batchs)
對測驗集同樣打包成dataset,不過測驗集可以不隨機打亂:
In [32]:db_test = tf.data.Dataset.from_tensor_slices((x_test, y_test)) db_test = db_test.map(preprocess).batch(batchs)In [40]:
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') ]In [41]:
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.9800Out[41]:
<tensorflow.python.keras.callbacks.History at 0x7fba79d4b610>
可以看到,經過5輪迭代之后,模型的準確率達到98.01%,這在當時已經是相當不錯的成績,
上述代碼對LeNet-5卷積神經網路進行實作,網路一共包含7層(激活函式不計算在內),注意,上文中實作的是現代版的LeNet卷積網路,與最初Yann LeCun論文中描述的LeNet-5在結構上是一致的,不過,現代版的LeNet-5網路更多使用ReLU激活函式作為中間層激活函式和Softmax在輸出層轉化為概率輸出,另外在池化層現代更多用最大池化,而不是當初的平均池化,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/31255.html
標籤:其他
