1. 程式人生 > 其它 >深度學習loss值變為0_TF2.0深度學習實戰(一):分類問題之手寫數字識別

深度學習loss值變為0_TF2.0深度學習實戰(一):分類問題之手寫數字識別

技術標籤:深度學習loss值變為0

ac032b90cb15c88b9eefa5154dd098da.png 點選上面“藍字”關注我們 ec93b60f5e392caa9491621ec401dbfa.png 本專輯持續更新,歡迎關注。本著學習的心,希望和大家相互交流,一起進步!

一、手寫數字識別簡介

008b448938c0edc549a57a965db6a081.png 9a8a7eee5a708e9bb37117b817bbe601.png手寫數字識別是一個非常經典的影象分類任務,經常被作為深度學習入門的第一個指導案例。相當於我們學程式語言時,編寫的第一個程式“Hello World !”。不一樣的是,入門深度學習,需要有一定量的理論基礎。手寫數字識別是基於MNIST資料集的一個影象分類任務,目的是通過搭建深度神經網路,實現對手寫數字的識別(分類)。

二、MNIST資料集介紹

008b448938c0edc549a57a965db6a081.png 9a8a7eee5a708e9bb37117b817bbe601.png為了方便業界統一測試和評估演算法, 1998年Lecun, Bottou和Bengio等人釋出了手寫數字圖片資料集,命名為 MNIST,它包含了 0~9 共 10 種數字的手寫圖片,每種數字一共有 7000 張圖片,採集自不同書寫風格的真實手寫圖片,一共 70000 張圖片。其中60000張圖片作為訓練集,用來訓練模型。10000張圖片作為測試集,用來訓練或者預測。訓練集和測試集共同組成了整個 MNIST 資料集。MINIST資料集中的每張圖片,大小為28 x 28,同時只保留灰度資訊(即單通道)。下圖是MNIST資料集中的部分圖片:

5500f82d84e74574f168bb92c3f9cb3d.png

三、深度學習實戰

008b448938c0edc549a57a965db6a081.png 9a8a7eee5a708e9bb37117b817bbe601.png

3.1 資料集載入

(1)本實驗可直接通過TensorFlow2.0的內建函式載入minist資料集,TensorFlow2.0實現方式為:

# 載入MNIST資料集,返回的是兩個元組,分別表示訓練集和測試集(x,y),(x_val,y_val)=datasets.mnist.load_data()

(2)將資料集格式轉換為張量,方便進行張量運算,並且將灰度值縮放到0-1,方便訓練。

x = tf.convert_to_tensor(x, dtype=tf.float32)/255.  # 轉換為張量,並縮放到0~1y=tf.convert_to_tensor(y,dtype=tf.int32)#轉換為張量(標籤)

(3)構建資料集物件,設定batch和epos。

train_dataset = tf.data.Dataset.from_tensor_slices((x, y))  # 構建資料集物件train_dataset = train_dataset.batch(32).repeat(10)  # 設定批量訓練的batch為32,要將訓練集重複訓練10遍

3.2 網路結構搭建

由於MNIST資料集裡的影象特徵較為簡單,所以本次以搭建一個3層的全連線網路為例,來實現MNIST資料集10分類任務。其中,每個全連線層的節點數分別為:256,128和10。
# 網路搭建network = Sequential([    layers.Dense(256, activation='relu'),  # 第一層    layers.Dense(128, activation='relu'),  # 第二層    layers.Dense(10)  # 輸出層])network.build(input_shape=(None, 28*28))  # 輸入network.summary()#打印出每層的引數列表

3.3 模型裝配與訓練

搭建好網路結構後,首先要對網路模型裝配,指定網路使用的優化器物件,損失函式,評價指標等。然後對網路模型進行訓練,在這過程中,要將資料送入神經網路進行訓練,同時建立好梯度記錄環境,最終打印出圖片分類精度的測試結果。
optimizer = optimizers.SGD(lr=0.01)  # 宣告採用批量隨機梯度下降方法,學習率=0.01acc_meter = metrics.Accuracy()  # 建立準確度測量器for step, (x, y) in enumerate(train_dataset):  # 一次輸入batch組資料進行訓練    with tf.GradientTape() as tape:  # 構建梯度記錄環境        x = tf.reshape(x, (-1, 28*28))  # 將輸入拉直,[b,28,28]->[b,784]        out = network(x)  # 輸出[b, 10]        y_onehot = tf.one_hot(y, depth=10)  # one-hot編碼        loss = tf.square(out - y_onehot)        loss = tf.reduce_sum(loss)/32  # 定義均方差損失函式,注意此處的32對應為batch的大小        grads = tape.gradient(loss, network.trainable_variables)  # 計算網路中各個引數的梯度        optimizer.apply_gradients(zip(grads, network.trainable_variables))  # 更新網路引數        acc_meter.update_state(tf.argmax(out, axis=1), y)  # 比較預測值與標籤,並計算精確度    if step % 200 == 0:  # 每200個step,列印一次結果        print('Step', step, ': Loss is: ', float(loss), ' Accuracy: ', acc_meter.result().numpy())acc_meter.reset_states()#每一個step後準確度清零

3.4 測試結果

在影象分類或識別任務中,經常會將預測精確度accuracy作為評價一個分類器好壞的指標。當accuracy越接近1(100%)時,說明該分類器的預測效果越好。下圖展示了訓練結束時的一個測試結果。可以看到,此時訓練集上的準確度達到了97%左右,已經很接近1了,繼續訓練應該可以得到更高的精確度。 e57c762fa81aeb4158220ea78f1f6c36.png

四、完整程式清單(附詳細註釋)

008b448938c0edc549a57a965db6a081.png 9a8a7eee5a708e9bb37117b817bbe601.png
import tensorflow as tf  # 匯入TF庫from tensorflow.keras import layers, optimizers, datasets, Sequential, metrics  # 匯入TF子庫# 1.資料集準備(x, y), (x_val, y_val) = datasets.mnist.load_data()  # 載入資料集,返回的是兩個元組,分別表示訓練集和測試集x = tf.convert_to_tensor(x, dtype=tf.float32)/255.  # 轉換為張量,並縮放到0~1y = tf.convert_to_tensor(y, dtype=tf.int32)  # 轉換為張量(標籤)print(x.shape, y.shape)train_dataset = tf.data.Dataset.from_tensor_slices((x, y))  # 構建資料集物件train_dataset = train_dataset.batch(32).repeat(10)  # 設定批量訓練的batch為32,要將訓練集重複訓練10遍# 2.網路搭建network = Sequential([    layers.Dense(256, activation='relu'),  # 第一層    layers.Dense(128, activation='relu'),  # 第二層    layers.Dense(10)  # 輸出層])network.build(input_shape=(None, 28*28))  # 輸入# network.summary()# 3.模型訓練(計算梯度,迭代更新網路引數)optimizer = optimizers.SGD(lr=0.01)  # 宣告採用批量隨機梯度下降方法,學習率=0.01acc_meter = metrics.Accuracy()  # 建立準確度測量器for step, (x, y) in enumerate(train_dataset):  # 一次輸入batch組資料進行訓練    with tf.GradientTape() as tape:  # 構建梯度記錄環境        x = tf.reshape(x, (-1, 28*28))  # 將輸入拉直,[b,28,28]->[b,784]        out = network(x)  # 輸出[b, 10]        y_onehot = tf.one_hot(y, depth=10)  # one-hot編碼        loss = tf.square(out - y_onehot)        loss = tf.reduce_sum(loss)/32  # 定義均方差損失函式,注意此處的32對應為batch的大小        grads = tape.gradient(loss, network.trainable_variables)  # 計算網路中各個引數的梯度        optimizer.apply_gradients(zip(grads, network.trainable_variables))  # 更新網路引數        acc_meter.update_state(tf.argmax(out, axis=1), y)  # 比較預測值與標籤,並計算精確度    if step % 200 == 0:  # 每200個step,列印一次結果        print('Step', step, ': Loss is: ', float(loss), ' Accuracy: ', acc_meter.result().numpy())acc_meter.reset_states()#每一個step後準確度清零
喜歡就點個在看再走吧 ed1093fcd33ef7cdd4e332970cfbd1a8.png