手寫數字圖片識別-卷積神經網絡


導入依賴

from tensorflow import keras
from matplotlib import pyplot as plt
from tensorflow.keras.layers import Conv2D, MaxPool2D, Flatten, Dense

 

下載數據集

mnist數據集是一個公共的手寫數字數據集,一共有7W張28*28像素點的0-9手寫數字圖片和標簽,其中有6W張是訓練集,1W張是測試集。

mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()

其中,x_train為訓練集特征,y_train為訓練集標簽,x_test為測試集特征,y_test為測試集標簽。

 

數據歸一化

使本來是0-255之間的灰度值,變為0-1之間的數值,從而讓梯度變得平緩,更容易收斂找到最優解。

x_train, x_test = x_train / 255.0, x_test / 255.0

 

增加維度

給數據集增加一個維度,使其變為6W張28*28的單通道數據,讓卷積核進行特征提取。

x_train = x_train.reshape(x_train.shape[0], 28, 28, 1)
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1)

 

獨熱碼

y_train = keras.utils.to_categorical(y_train, 10)
y_test = keras.utils.to_categorical(y_test, 10)

進行獨熱編碼后,每個分類對應一個狀態碼,1為是,0為否。 如某張圖片標簽是6,則獨熱碼為:0 0 0 0 0 0 1 0 0 0

 

切分驗證集

從訓練集中拿出5000個樣本來作為驗證集,驗證集用於參與訓練更新梯度。

x_validation = x_train[:5000]
y_validation = y_train[:5000]
x_train = x_train[5000:]
y_train = y_train[5000:]

 

搭建網絡結構

使用三層卷積兩層全連接的網絡結構,第一層卷積使用32個3*3的卷積核,第二三層卷積使用64個3*3的卷積核,卷積的目的是提取圖片的空間特征,最大池化是為了抑制過擬合。

model = keras.models.Sequential([
    Conv2D(32, (3, 3), activation='relu',input_shape=(28, 28, 1)),
    MaxPool2D((2, 2)),
    Conv2D(64, (3, 3), activation='relu'),
    MaxPool2D((2, 2)),
    Conv2D(64, (3, 3), activation='relu'),
    Flatten(),
    Dense(64, activation='relu'),
    Dense(10, activation='softmax')
])

 

編譯模型

使用多分類類別交叉熵損失函數,優化器選擇rmsprop,正常情況下都可以選擇此優化器,它不會令你失望,這也是默認缺省優化器。

model.compile(loss='categorical_crossentropy', optimizer='rmsprop',metrics=['accuracy'])

 

保存模型

checkpoint_save_path = "./checkpoint/mnist2.ckpt"
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,save_weights_only=True, save_best_only=True)

 

執行訓練

數據集按32個為一批喂入神經網絡,總共迭代7次,每迭代一次測試一次准確率。

history = model.fit(x_train, y_train, batch_size=32, epochs=7,  verbose=1, validation_data=(x_validation,y_validation),validation_freq=1,callbacks=[cp_callback])

 

評估模型

score = model.evaluate(x_test, y_test, verbose=0, batch_size=32)
print('測試准確率:{}, 測試loss值: {}'.format(score[1], score[0]))

 

可視化acc和loss曲線

plt.rcParams['font.sans-serif']=['SimHei']
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

plt.subplot(1, 2, 1)
plt.plot(acc, label='訓練Acc')
plt.plot(val_acc, label='測試Acc')
plt.title('Acc曲線')
plt.legend()

plt.subplot(1, 2, 2)
plt.plot(loss, label='訓練Loss')
plt.plot(val_loss, label='測試Loss')
plt.title('Loss曲線')
plt.legend()
plt.show()

此時運行程序,待訓練完成后,會顯示出acc和loss的訓練圖像,同時當前目錄下會出現checkpoint文件夾。

 

可以看到,加入了卷積計算的神經網絡,效果有了一定提升,模型測試的准確率達到了99%。

 

復現網絡結構

訓練完成之后,接下來應該編寫一個應用程序,用來接收圖片,識別圖片,返回識別結果。

因此我這里新開一個py文件

from PIL import Image
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.layers import Conv2D,  MaxPool2D, Flatten, Dense

首先要復現訓練時的網絡結構

model = keras.models.Sequential([
    Conv2D(32, (3, 3), activation='relu',input_shape=(28, 28, 1)),
    MaxPool2D((2, 2)),
    Conv2D(64, (3, 3), activation='relu'),
    MaxPool2D((2, 2)),
    Conv2D(64, (3, 3), activation='relu'),
    Flatten(),
    Dense(64, activation='relu'),
    Dense(10, activation='softmax')
])

 

加載模型

model_save_path = './checkpoint/mnist2.ckpt'
model.load_weights(model_save_path)

 

圖片識別

我用Photoshop畫了十張圖,用來進行識別

 

imgs = ['./img/p_0.jpg','./img/p_1.jpg','./img/p_2.jpg','./img/p_3.jpg','./img/p_4.jpg','./img/p_5.jpg','./img/p_6.jpg','./img/p_7.jpg','./img/p_8.jpg','./img/p_9.jpg']

for path in imgs:

    #讀取圖片
    img = Image.open(path)
    img = img.resize((28, 28), Image.ANTIALIAS)
    img_arr = np.array(img.convert('L'))

    #訓練的圖片是黑底白字,但是我們識別的圖片是白底黑字,所以需要顏色取反
    #將像素值轉化為0和255兩個極端值 在保留圖片有用信息的同時 濾掉背景噪聲 使圖片更干凈
    for i in range(28):
        for j in range(28):
            if img_arr[i][j] < 150:
                img_arr[i][j] = 255
            else:
                img_arr[i][j] = 0

    # 歸一化
    img_arr = img_arr / 255.0

    # 添加一個維度
    x_predict = img_arr.reshape(1, 28, 28, 1)

    # 識別
    result = model.predict(x_predict)
    pred = tf.argmax(result[0])
    print('正在識別:{} ---- > {}'.format(path, pred))

運行結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM