再探MNIST

這裏就是搭建一個CNN網絡來做手寫數字的識別。

import tensorflow as tf
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

# 加載數據集
minst = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = minst.load_data()
# 設置數據集使之符合tensorflow的輸入
x_train = np.pad(x_train, ((0, 0), (2, 2), (2, 2)), 'constant', constant_values=0)
x_test = np.pad(x_test, ((0, 0), (2, 2), (2, 2)), 'constant', constant_values=0)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train = x_train/255
x_test = x_test/255
x_train = x_train.reshape(x_train.shape[0], 32, 32, 1)
x_test = x_test.reshape(x_test.shape[0], 32, 32, 1)

# 模型建立
model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(filters=6, kernel_size=(5, 5), padding="valid", activation=tf.nn.tanh, input_shape=(32, 32, 1)),
    # 這裏的input_shape就對輸入的形狀大小有限制。激活函數是神經網絡的靈魂。
    # 它把線性變換轉變成了非線性的。
    # 至於padding是什麼?該單詞的中文意思是填補。
    # 如果是valid,到了邊界部分,不夠一個卷積核大小的,就直接丟掉不用了,若是same,則自己填充0使之達到一個卷積核的大小。
    # "SAME"時,卷積之後的輸出形狀大小是取上整(W/S)  W是輸入圖片的尺寸大小。S是步長。
    # "VALID"時,卷積之後的輸出形狀大小是取上整((W-F+1)/S) F是卷積核大小。
    tf.keras.layers.AveragePooling2D(pool_size=(2, 2), strides=(2, 2), padding="same"),
    # 平均池化,池化之後的圖像的大小會一半。
    tf.keras.layers.Conv2D(filters=16, kernel_size=(5, 5), padding="valid", activation=tf.nn.tanh),
    tf.keras.layers.AveragePooling2D(pool_size=(2, 2), strides=(2, 2), padding="same"),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(units=120, activation=tf.nn.tanh),
    tf.keras.layers.Dense(units=84, activation=tf.nn.tanh),
    tf.keras.layers.Dense(units=10, activation=tf.nn.softmax),
    # 關於各個激活函數是個什麼鬼樣子,可以自己去搜一下。
])

# 模型訓練
# 超參設置
num_epochs = 10
batch_size = 64
learning_rate = 0.001
# 優化器
adam_optimizer = tf.keras.optimizers.Adam(learning_rate)
# 這裏使用這個優化器。# arxiv.org/abs/1412.6980v8 聽說這是說明書,但從來沒打開過。。
model.compile(optimizer=adam_optimizer, loss=tf.keras.losses.sparse_categorical_crossentropy, metrics=['accuracy'])
# loss函數使用的是這個,這個函數適合多分類問題,這裏就是多分類。與categorical_accuracy相同,這個尤其對稀疏的目標值預測時有用。

import datetime  # 計算時間
start_time = datetime.datetime.now()
model.fit(x=x_train, y=y_train, batch_size=batch_size, epochs=num_epochs)
end_time = datetime.datetime.now()
time_cost = end_time-start_time
print("time_cost = ", time_cost)

# 下面這裏是測試了。是讀入一個圖片,是我手寫的一個數字。做處理,滿足輸入格式後輸入。
# 測試
img = cv.imread('0.jpg')   # 載入
print(img.shape)
plt.imshow(img)
plt.show()
# 轉爲灰度
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
print(img.shape)
plt.imshow(img)
plt.show()
# 轉換成白底黑字,因爲訓練集裏面就是這樣。而我寫出來的轉成灰度之後是黑底白字。
img = cv.bitwise_not(img)
print(img.shape)
plt.imshow(img)
plt.show()
# 這裏的目的是讓黑色更黑,白色更白。0代表黑色 #255代表白色
img[img <= 95] = 0
img[img > 150] = 255
print(img.shape)
plt.imshow(img)
plt.show()
# 接下來是處理格式,使之滿足輸入的格式。
img = cv.resize(img, (32, 32))
print(img.shape)
cv.imshow('image', img)
img = img.astype('float32')
img /= 255
img = img.reshape(1, 32, 32, 1)
print(img.shape)
pred=model.predict(img)
print(pred)  # 輸出判斷爲每個數字的概率。
print(pred.argmax())  # 輸出具體的那個數字。

手寫的數字長這樣。
手寫的數字長這樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章