tensoflow2.0學習筆記——手寫識別(MNIST數據)的兩種方法,附代碼。

學習環境

電腦Windows10,環境anaconda3,開發語言Python3.7

目標

用tensorflow訓練MNIST手寫數據,並進行測試

實現方法(兩種方法)

一、用tensorflow構建一個基本的神經網絡,用於預測手寫數字。

         本例爲3層神經網,包括一個輸入層,兩個隱層,一個輸出層。

         輸入數據大小:28*28dpi的手寫圖片,即(28*28)的二維數組,展平後爲長度784的數組。

         直接上代碼,代碼後面有解析:

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets
import os
import cv2

# 利用Tensorflow2中的接口加載mnist數據集
(x_train, y_train), (x_test, y_test) = datasets.mnist.load_data() 

# 對數據進行預處理
def preprocess(x, y):
    x = tf.cast(x, dtype=tf.float32) / 255.
    y = tf.cast(y, dtype=tf.int32)
    return x,y

# 構建dataset對象,方便對數據的打亂,批處理等超操作
train_db = tf.data.Dataset.from_tensor_slices((x_train,y_train)).shuffle(1000).batch(128)
train_db = train_db.map(preprocess) # 使用map操作,對單值調用preprocess方法
test_db = tf.data.Dataset.from_tensor_slices((x_test,y_test)).batch(128)
test_db = test_db.map(preprocess)  # 使用map操作,對單值調用preprocess方法

#導入一張測試圖片(28*28dpi的手寫數字)請修改自己的圖片路徑
check_x = cv2.imread("D:\\tensorflow\\mnist_0_001.png", cv2.IMREAD_GRAYSCALE)
check_y = 0
check_x,check_y = preprocess(check_x,check_y)
check_x = tf.reshape(check_x, [-1, 28*28]) 

# 構建模型中會用到的權重,3層有3組w和b
w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1))
b1 = tf.Variable(tf.zeros([256]))
w2 = tf.Variable(tf.random.truncated_normal([256, 128], stddev=0.1))
b2 = tf.Variable(tf.zeros([128]))
w3 = tf.Variable(tf.random.truncated_normal([128, 10], stddev=0.1))
b3 = tf.Variable(tf.zeros([10]))

# 學習率
lr = 0.01 

# epoch表示整個訓練集循環的次數 這裏循環10次,次數越多學習時間越長,準確率越高
for epoch in range(10):

    # step表示當前訓練到了第幾個Batch
    for step, (x, y) in enumerate(train_db):  #enumerate() --以索引-值對的形式迭代序列

        # 把訓練集進行打平操作
        x = tf.reshape(x, [-1, 28*28])

        # 構建模型並計算梯度
        with tf.GradientTape() as tape: # tf.Variable

            # 三層非線性模型搭建
            h1 = x@w1 + tf.broadcast_to(b1, [x.shape[0], 256])
            h1 = tf.nn.relu(h1)
            h2 = h1@w2 + b2
            h2 = tf.nn.relu(h2)
            out = h2@w3 + b3

            # 把y轉化成one_hot編碼,當depth=10,y=3時,y變換爲[0,0,0,1,0,0,0,0,0,0]
            y_onehot = tf.one_hot(y, depth=10)

            # 計算MSE
            loss = tf.square(y_onehot - out)
            loss = tf.reduce_mean(loss)

        # 計算梯度
        grads = tape.gradient(loss, [w1, b1, w2, b2, w3, b3])
        
        # w = w - lr * w_grad
        # 利用上述公式進行權重的更新
        w1.assign_sub(lr * grads[0])    #tf.assign_sub(ref, value, use_locking=None, name=None),變量 ref 減去 value值,即 ref = ref - value
        b1.assign_sub(lr * grads[1])
        w2.assign_sub(lr * grads[2])
        b2.assign_sub(lr * grads[3])
        w3.assign_sub(lr * grads[4])
        b3.assign_sub(lr * grads[5])

        # 每訓練100個Batch 打印一下當前的loss
        if step % 100 == 0:
            print(epoch, step, 'loss:', float(loss))
    
    # 每訓練完一次數據集 測試一下準確率
    total_correct, total_num = 0, 0
    for step, (x,y) in enumerate(test_db):
        x = tf.reshape(x, [-1, 28*28])
        h1 = tf.nn.relu(x@w1 + b1)
        h2 = tf.nn.relu(h1@w2 + b2)
        out = h2@w3 +b3

        # 把輸出值映射到[0~1]之間
        prob = tf.nn.softmax(out, axis=1)

        # 獲取概率最大值得索引位置
        pred = tf.argmax(prob, axis=1)   #根據axis取值的不同返回每行(0)或者每列(1)最大值的索引
        pred = tf.cast(pred, dtype=tf.int32)  #tf.cast()函數的作用是執行tensorflow中張量數據類型轉換
        correct = tf.cast(tf.equal(pred, y), dtype=tf.int32)
        correct = tf.reduce_sum(correct)
 
        # 獲取每一個batch中的正確率和batch大小
        total_correct += int(correct)
        total_num += x.shape[0]

    # 計算總的正確率
    acc = total_correct / total_num
    print("y:",y, "predict:",pred)

    # predict check_x,利用獲得的權重w和偏置b對手寫數字圖片數據進行預測
    h1 = tf.nn.relu(check_x@w1 + b1)
    h2 = tf.nn.relu(h1@w2 + b2)
    out = h2@w3 +b3

    # 把輸出值映射到[0~1]之間
    prob = tf.nn.softmax(out, axis=1)

    # 獲取概率最大值得索引位置
    pred_check = tf.argmax(prob, axis=1)
    pred_check = tf.cast(pred_check, dtype=tf.int32)
    print('test acc:', acc,"pred=",pred_check,"acc=",tf.equal(check_y ,pred_check))

 

二、直接用tensorflow的Keras創建神經網絡模型。

這裏利用tensorflow 的Keras.model 類創建模型,練習模型,評估模型,預測模型。

本例創建了2層神經網絡,其中隱層有512個神經元,輸出層爲10。模型完成學習後,將通過model.save_weights()保存訓練好的權重和偏置參數,之後就可以通過model.load_weights()導出已存的權重和偏置,然後就可以用學習好的模型進行預測了。

訓練數據的保存還有一種方法:model.save()和model.load()。具體可以在網上找到,這裏不再演示。

模型創建/訓練/評估代碼如下:

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets, layers, optimizers
 
# step1 加載訓練集和測試集合
mnist = tf.keras.datasets.mnist
(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

# step2 創建模型
def create_model():
  return tf.keras.models.Sequential([                #堆疊式創建層
    tf.keras.layers.Flatten(input_shape=(28, 28)),   #將28*28的輸入數組展平爲784的一維數據
    tf.keras.layers.Dense(512, activation='relu'),   #512個神經元,激活函數:relu
    tf.keras.layers.Dropout(0.2),                    #設定20%的隨機扔掉,爲避免過擬合
    tf.keras.layers.Dense(10, activation='softmax')  #輸出層爲10,激活函數:softmax
  ])
model = create_model()
 
# step3 編譯模型 主要是確定優化方法,損失函數等
model.compile(optimizer='adam',    #優化器:'adam',損失函數:'sparse_categorical_crossentropy'
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# step4 模型訓練  訓練1個epochs ,batch_size=256(可以爲None),可以自己修改數字,看看運行結果及耗時情況
model.fit(x=x_train,
          y=y_train,
          epochs=1,
          batch_size=256
          )
 
# step5 用model.evaluate進行模型測試
loss, acc = model.evaluate(x_test, y_test)  #model.evaluate輸入數據(data)和金標準(label),然後將預測結果與金標準相比較,得到兩者誤差並輸出.
print("train model, accuracy:{:5.2f}%".format(100 * acc))
 
# step6 保存模型的權重和偏置
model.save_weights('./save_weights/my_save_weights')

# step7 刪除模型
del model

# step8 重新創建模型
model = create_model()
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# step9 恢復權重
model.load_weights('./save_weights/my_save_weights')

# step10 測試模型
loss, acc = model.evaluate(x_test, y_test)
print("Restored model, accuracy:{:5.2f}%".format(100 * acc))

以下代碼爲檢測圖片,輸入圖片文件名,輸出預測結果。注意:輸入的手寫體如果與MNIST的圖片類似識別率還是很高的,如果是自己用畫圖軟件做的手寫數字則識別成功率很低。

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets, layers, optimizers
import cv2
 
# step1 重新創建模型
def create_model():
  return tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(512, activation='relu'),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation='softmax')
  ])
model = create_model()
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# step2 恢復權重
model.load_weights('./save_weights/my_save_weights')

imgDir = "D:\\tensorflow\\"
imgFile = input("請輸入待檢測的文件名:")
while imgFile != "q":              #輸入q則退出程序

    #導入測試圖片
    check_x = cv2.imread(imgDir+imgFile, cv2.IMREAD_GRAYSCALE)
    check_x = check_x / 255.0
    check_x = tf.reshape(check_x, [1, 28, 28])

    #用model.predict對一個手寫圖片進行預測,顯示預測結果
    prob = model.predict(check_x, batch_size=None) #model.predict輸入數據(data),輸出預測結果
    pred_check = tf.argmax(prob, axis=1)
    pred_check = tf.cast(pred_check, dtype=tf.int32)
    print(imgFile,"預測結果:",pred_check)
    imgFile = input("請輸入待檢測的文件名:")

 

發佈了29 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章