卷积神经网络mnist手写数字识别代码_搭建经典LeNet5 CNN卷积神经网络对Mnist手写数字数据识别实例与注释讲解,准确率达到97%...
LeNet-5卷積神經網絡是最經典的卷積網絡之一,這篇文章就在LeNet-5的基礎上加入了一些tensorflow的有趣函數,對LeNet-5做了改動,也是對一些tf函數的實例化筆記吧。
環境 Pycharm2019+Python3.7.6+tensorflow 2.0
話不多說,先放完整源碼
from tensorflow.keras import layers, datasets, Sequential, losses, optimizers import tensorflow as tf import matplotlib.pyplot as pltdef get_data():(train_images, train_labels), (val_images, val_labels) = datasets.mnist.load_data()return train_images, train_labels, val_images, val_labelsdef model_build():network = Sequential([layers.Conv2D(6, kernel_size=3, strides=1, input_shape=(28, 28, 1)),layers.MaxPool2D(pool_size=2, strides=2),layers.ReLU(),layers.Conv2D(16, kernel_size=3, strides=1),layers.MaxPool2D(pool_size=2, strides=2),layers.ReLU(),layers.Conv2D(24, kernel_size=3, strides=1),layers.MaxPool2D(pool_size=2, strides=2),layers.ReLU(),layers.Flatten(),layers.Dense(120, activation='relu'),layers.Dropout(0.5),layers.Dense(84, activation='relu'),layers.Dense(10) # 因為輸出的是獨熱編碼設置為10])network.summary()return networktrain_images, train_labels, val_images, val_labels = get_data() plt.figure() plt.imshow(train_images[0]) # 打印第一張圖片檢查數據 plt.colorbar() # 色度條顯示 plt.grid(False) # 不顯示網格 plt.show() print(train_images.shape, train_labels.shape) '''檢查數據標簽是否正確'''lables = ['0', '1', '2', '3', '4','5', '6', '7', '8', '9'] plt.figure(figsize=(10, 10)) for i in range(25):plt.subplot(5, 5, i + 1)plt.xticks([])plt.yticks([])plt.grid(False)plt.imshow(train_images[i], cmap=plt.cm.binary)plt.xlabel(lables[train_labels[i]]) plt.show() train_images = tf.expand_dims(train_images, axis=3) val_images = tf.expand_dims(val_images, axis=3) train_labels = tf.cast(train_labels, tf.int32) val_labels = tf.cast(val_labels, tf.int32) train_labels = tf.one_hot(train_labels, depth=10) val_labels = tf.one_hot(val_labels, depth=10) train_images = tf.convert_to_tensor(train_images) print(train_images.dtype, train_labels.dtype) if train_images.dtype != tf.float32:train_images = tf.cast(train_images, tf.float32) print(train_images, train_labels)model = model_build() earlystop_callback = tf.keras.callbacks.EarlyStopping(monitor='val_acc', min_delta=0.001, patience=112) model.compile(loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True), optimizer='adam', metrics=["acc"]) hist = model.fit(train_images, train_labels, epochs=20, batch_size=28, validation_data=[val_images, val_labels],callbacks=[earlystop_callback])print(hist.history.keys()) print(hist.history['acc'])from tensorflow.keras import layers, datasets, Sequential, losses, optimizers import tensorflow as tf import matplotlib.pyplot as plt先導入我們所需要的庫,為了方便,我把 layers, datasets, Sequential, losses, optimizers做了特別導入。
def get_data():(train_images, train_labels), (val_images, val_labels) = datasets.mnist.load_data()return train_images, train_labels, val_images, val_labels定義數據獲取函數,從tensorflow的mnist中使用load_data()獲取手寫數字數據集,我們在這里會得到四個張量,(train_images, train_labels), (val_images, val_labels),分別為訓練圖像,訓練標簽,驗證圖像,驗證標簽。其中images的張量形狀為(60000, 28, 28) labels張量形狀為(60000, )
labels和images圖像和標簽索引相互對應。
def model_build():network = Sequential([layers.Conv2D(6, kernel_size=3, strides=1, input_shape=(28, 28, 1)),layers.MaxPool2D(pool_size=2, strides=2),layers.ReLU(),layers.Conv2D(16, kernel_size=3, strides=1),layers.MaxPool2D(pool_size=2, strides=2),layers.ReLU(),layers.Conv2D(24, kernel_size=3, strides=1),layers.MaxPool2D(pool_size=2, strides=2),layers.ReLU(),layers.Flatten(),layers.Dense(120, activation='relu'),layers.Dropout(0.5),layers.Dense(84, activation='relu'),layers.Dense(10) # 因為輸出的是獨熱編碼設置為10])network.summary()return network定義模型搭建函數
使用了Sequential封裝網絡
layers.Conv2D(6, kernel_size=3, strides=1, input_shape=(28, 28, 1)),加入第一層,為Conv2D卷積層,卷積核個數為6個, 感受野為3*3,卷積步長為1,網格輸入張量形狀為(28, 28,1)現在我們主要討論卷積在tf里的實現方式,卷積算法我會在未來另一篇文章中介紹,這里不再贅述。
layers.MaxPool2D(pool_size=2, strides=2),池化層,選用了MaxPool2D最大池化層,池化域2*2, 步長為2,pool_size=2, strides=2是一種常見的參數設置,可以使數據寬高縮小到原來的一半,算法到時候和卷積一并介紹。
layers.ReLU(),激活函數層, 選用‘relu’函數
layers.Flatten(), layers.Dense(120, activation='relu'), layers.Dropout(0.5), layers.Dense(84, activation='relu'), layers.Dense(10)這一部分為全連接層,在將數據輸入全連接層前,要先使用flatten層對數據進行鋪平處理。
可以設置dropout層“退火”防止過擬合
因為我們最后實現分類時,我們使用了獨熱編碼來代替原來的label ,所以在最后的輸出層設置了10。
train_images, train_labels, val_images, val_labels = get_data() plt.figure() plt.imshow(train_images[0]) # 打印第一張圖片檢查數據 plt.colorbar() # 色度條顯示 plt.grid(False) # 不顯示網格 plt.show() print(train_images.shape, train_labels.shape) '''檢查數據標簽是否正確''' lables = ['0', '1', '2', '3', '4','5', '6', '7', '8', '9'] plt.figure(figsize=(10, 10)) for i in range(25):plt.subplot(5, 5, i + 1)plt.xticks([])plt.yticks([])plt.grid(False)plt.imshow(train_images[i], cmap=plt.cm.binary)plt.xlabel(lables[train_labels[i]])從get_data()函數中加載我們所需要的數據集
打印第一張圖片,檢查數據集標簽是否正確,正確的標簽使我們訓練的關鍵因素。
我們應該能得到這樣的圖片,標簽表,發現標簽對應是正確的,我們便可以繼續。
圖像展示函數使用的matplotlib庫,具體不再介紹。
train_images = tf.expand_dims(train_images, axis=3) val_images = tf.expand_dims(val_images, axis=3) train_labels = tf.cast(train_labels, tf.int32) val_labels = tf.cast(val_labels, tf.int32) train_labels = tf.one_hot(train_labels, depth=10) val_labels = tf.one_hot(val_labels, depth=10) network = model_build() train_images = tf.convert_to_tensor(train_images) print(train_images.dtype, train_labels.dtype) if train_images.dtype != tf.float32:train_images = tf.cast(train_images, tf.float32) print(train_images, train_labels)對數據的預處理,我覺得這部分很重要,在編寫這個卷積網絡時,我在數據的準備上犯了很多錯誤,導致程序無法運行或訓練效果很差等。
train_images = tf.expand_dims(train_images, axis=3) val_images = tf.expand_dims(val_images, axis=3)我們在上面說過,我們image的shape為(60000, 28, 28),但2d卷積層的輸入要求為4個維度,我們便將所有的image數據擴充了一個維度,變為(60000, 28, 28, 1) 灰白圖像。
train_labels = tf.cast(train_labels, tf.int32) val_labels = tf.cast(val_labels, tf.int32) train_labels = tf.one_hot(train_labels, depth=10) val_labels = tf.one_hot(val_labels, depth=10)我們要將標簽形式轉化為獨熱編碼,比如 [1]-->[0, 1, 0, 0, 0, 0, 0 ,0 ,0, 0] 2-->[0, 0, 1, 0, 0, 0, 0 ,0 ,0, 0],這樣的好處是規避了標簽本身可能存在的數據比較,比如 ‘1’標簽大于‘2’標簽,但在分類時標簽‘1’和‘2’并沒有大小關系,獨熱編碼就很好的規避了這種可能存在的比較。
但在將編碼獨熱化前,需要將label的數據轉化成int32,否則會報錯
network = model_build() train_images = tf.convert_to_tensor(train_images) print(train_images.dtype, train_labels.dtype) if train_images.dtype != tf.float32:train_images = tf.cast(train_images, tf.float32) print(train_images, train_labels)Conv2D的輸入類型為 tf.float32
model = model_build() earlystop_callback = tf.keras.callbacks.EarlyStopping(monitor='val_acc', min_delta=0.001, patience=112) model.compile(loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True), optimizer='adam', metrics=["acc"]) hist = model.fit(train_images, train_labels, epochs=20, batch_size=28, validation_data=[val_images, val_labels],callbacks=[earlystop_callback])編譯訓練的設置,十分重要,這里的參數對準確率有很大的影響。
我們先搭建網絡
earlystop_callback = tf.keras.callbacks.EarlyStopping(monitor='val_acc', min_delta=0.001, patience=112)使用了一個早停callback ,監控對象為驗證集準確率,監控的分度值為0.001,步數112,實現了如果模型在連續在112次內val_acc始終沒有在0.001的分度上有所提升,就認為已經收斂了,訓練結束。這個callback內的參數是隨意設置的,根據自己的目的參數可以調整,合理范圍內一般不影響準確率。
model.compile(loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True), optimizer='adam', metrics=["acc"]) hist = model.fit(train_images, train_labels, epochs=20, batch_size=28, validation_data=[val_images, val_labels],callbacks=[earlystop_callback])模型編譯中,我們在分類的損失函數中一般選擇CategoricalCrossentropy(from_logits=True)
交叉熵損失函數,其中在最后參數選定為True,使用softmax修訂結果,softmax可以將值轉化為概率值,這個選項會對訓練的準確度產生巨大影響。softmax()
訓練模型
print(hist.history.keys()) print(hist.history['acc'])在最后我用hist變量接受我們訓練的數據
我們可以看到在epoch 16中我們的準確率已經達到了較高的水平。
可以通過hist.history返回的字典得到我們訓練的誤差等信息進行誤差圖像等可視化的設置,我在上一篇的全連接網絡實例中介紹了一種簡單的可視化方法。
在tensorflow的官網中可以學習他們對數據結果可視化的樣例。
比如,我大概修改后,我們可以得到這樣的效果
藍色條為模型對他分類的信任度,比如第一個模型認為他有100%的概率認為這個數字是7。
這篇CNN LeNet-5的實例筆記結束了,順便提一句,這個手寫數字數據集在上一篇提到的全連接神經網絡中的準確率高達99.5%。LeNet-5在簡單的灰色手寫數字數據集的識別效果很好,但在復雜彩色圖像下,性能就會急劇下降,下一篇介紹預計為VGG13卷積神經網絡,可以對更復雜圖像進行識別。最近時間不太充裕,晚一些我會繼續發布在tensorflow與神經網絡專欄中。
總結
以上是生活随笔為你收集整理的卷积神经网络mnist手写数字识别代码_搭建经典LeNet5 CNN卷积神经网络对Mnist手写数字数据识别实例与注释讲解,准确率达到97%...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 备案 资料(资料库备案)
- 下一篇: 安卓手机谷歌三件套(安卓手机谷歌)