[深度之眼]TensorFlow2.0項目班-模型訓練之GradientTape

在iris鳶尾花分類的數據集上,用 tf.GradientTape 自定義模型訓練的方式來訓練模型
model.fitmodel.compile 分解

import tensorflow as tf
from sklearn import datasets
from matplotlib import pyplot as plt
import numpy as np

x_data = datasets.load_iris().data
y_data = datasets.load_iris().target

# 隨機打亂數據(因爲原始數據是順序的,順序不打亂會影響準確率)
np.random.seed(6)            # 隨機數種子
np.random.shuffle(x_data)      # 打亂數據
np.random.seed(6)
np.random.shuffle(y_data)
tf.random.set_seed(6)

# 劃分數據集
x_train = x_data[:-30]
y_train = y_data[:-30]
x_test = x_data[-30:]
y_test = y_data[-30:]

# 轉換x的數據類型,否則後面矩陣相乘時會因數據類型不一致報錯
x_train = tf.cast(x_train, tf.float32)
x_test = tf.cast(x_test, tf.float32)

# from_tensor_slices函數使輸入特徵和標籤值一一對應。(把數據集分批次,每個批次batch組數據)
train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)

# 生成神經網絡的參數,4個輸入特徵故,輸入層爲4個輸入節點;因爲3分類,故輸出層爲3個神經元
# 用tf.Variable()標記參數可訓練
# 使用seed使每次生成的隨機數相同(方便教學,使大家結果都一致,在現實使用時不寫seed)
w1 = tf.Variable(tf.random.truncated_normal([4, 3], stddev=0.1, seed=1))
b1 = tf.Variable(tf.random.truncated_normal([3], stddev=0.1, seed=1))

lr = 0.1  # 學習率爲0.1
train_loss_results = []  # 將每輪的loss記錄在此列表中,爲後續畫loss曲線提供數據
test_acc = []  # 將每輪的acc記錄在此列表中,爲後續畫acc曲線提供數據
epoch = 500  # 循環500輪
loss_all = 0  # 每輪分4個step,loss_all記錄四個step生成的4個loss的和

# 訓練部分
for epoch in range(epoch):  #數據集級別的循環,每個epoch循環一次數據集
    for step, (x_train, y_train) in enumerate(train_db):  #batch級別的循環 ,每個step循環一個batch
        with tf.GradientTape() as tape:  # with結構記錄梯度信息
            y = tf.matmul(x_train, w1) + b1  # 神經網絡乘加運算
            y = tf.nn.softmax(y)  # 使輸出y符合概率分佈(此操作後與獨熱碼同量級,可相減求loss)
            y_ = tf.one_hot(y_train, depth=3)  # 將標籤值轉換爲獨熱碼格式,方便計算loss和accuracy
            loss = tf.reduce_mean(tf.square(y_ - y))  # 採用均方誤差損失函數mse = mean(sum(y-out)^2)
            loss_all += loss.numpy()  # 將每個step計算出的loss累加,爲後續求loss平均值提供數據,這樣計算的loss更準確
        # 計算loss對各個參數的梯度
        grads = tape.gradient(loss, [w1, b1])

        # 實現梯度更新 w1 = w1 - lr * w1_grad    b = b - lr * b_grad
        w1.assign_sub(lr * grads[0])  # 參數w1自更新
        b1.assign_sub(lr * grads[1])  # 參數b自更新

    # 每個epoch,打印loss信息
    print("Epoch {}, loss: {}".format(epoch, loss_all/4))
    train_loss_results.append(loss_all / 4)  # 將4個step的loss求平均記錄在此變量中
    loss_all = 0  # loss_all歸零,爲記錄下一個epoch的loss做準備

    # 測試部分
    # total_correct爲預測對的樣本個數, total_number爲測試的總樣本數,將這兩個變量都初始化爲0
    total_correct, total_number = 0, 0
    for x_test, y_test in test_db:
        # 使用更新後的參數進行預測
        y = tf.matmul(x_test, w1) + b1
        y = tf.nn.softmax(y)
        pred = tf.argmax(y, axis=1)  # 返回y中最大值的索引,即預測的分類
        # 將pred轉換爲y_test的數據類型
        pred = tf.cast(pred, dtype=y_test.dtype)
        # 若分類正確,則correct=1,否則爲0,將bool型的結果轉換爲int型
        correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
        # 將每個batch的correct數加起來
        correct = tf.reduce_sum(correct)
        # 將所有batch中的correct數加起來
        total_correct += int(correct)
        # total_number爲測試的總樣本數,也就是x_test的行數,shape[0]返回變量的行數
        total_number += x_test.shape[0]
    # 總的準確率等於total_correct/total_number
    acc = total_correct / total_number
    test_acc.append(acc)
    print("Test_acc:", acc)
    print("--------------------------")

# 繪製 loss 曲線
plt.title('Loss Function Curve')  # 圖片標題
plt.xlabel('Epoch')  # x軸變量名稱
plt.ylabel('Loss')  # y軸變量名稱
plt.plot(train_loss_results, label="$Loss$")  # 逐點畫出trian_loss_results值並連線,連線圖標是Loss
plt.legend()  # 畫出曲線圖標
plt.show()  # 畫出圖像

# 繪製 Accuracy 曲線
plt.title('Acc Curve')  # 圖片標題
plt.xlabel('Epoch')  # x軸變量名稱
plt.ylabel('Acc')  # y軸變量名稱
plt.plot(test_acc, label="$Accuracy$")  # 逐點畫出test_acc值並連線,連線圖標是Accuracy
plt.legend()
plt.show()

訓練誤差:
在這裏插入圖片描述
測試集準確率:
在這裏插入圖片描述

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