使用TensorFlow原生程式碼實現鳶尾花分類
阿新 • • 發佈:2020-10-10
# -*- coding: UTF-8 -*- # 利用鳶尾花資料集,實現前向傳播、反向傳播,視覺化loss曲線 # 匯入所需模組 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 # 隨機打亂資料(因為原始資料是順序的,順序不打亂會影響準確率) # seed: 隨機數種子,是一個整數,當設定之後,每次生成的隨機數都一樣(為方便教學,以保每位同學結果一致) np.random.seed(116) # 使用相同的seed,保證輸入特徵和標籤一一對應 np.random.shuffle(x_data) np.random.seed(116) np.random.shuffle(y_data) tf.random.set_seed(116) # 將打亂後的資料集分割為訓練集和測試集,訓練集為前120行,測試集為後30行 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()