案例一:鳶尾花資料的分類
阿新 • • 發佈:2020-11-05
一:準備資料
1.1:讀入資料集
from sklearn.datasets import load_iris
from sklearn import datasets
import pandas
import matplotlib.pyplot as plt
x_data = datasets.load_iris().data
y_data = datasets.load_iris().target
print(x_data.shape)
print(y_data.shape)
1.2: 資料集亂序
print(y_data)
# seed()+shuffle import random seed=10 random.seed(seed) random.shuffle(x_data) random.seed(seed)# 一定得重複在寫一遍,和上面的seed要相同,不然y_batch和x_batch打亂順序會不一樣 random.shuffle(y_data) print(y_data)
1.3:生成訓練集和測試集
from sklearn.model_selection import train_test_split
(X_train,X_test,y_train,y_test) = train_test_split(x_data, y_data, train_size=0.8, random_state=seed)
print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)
1.4:(特徵 - 標籤)配對,且每次只讀入一部分(batch)進行訓練
import tensorflow as tf # import tensorflow.compat.v1 as tf # tf.enable_eager_execution() train_data = tf.data.Dataset.from_tensor_slices((X_train, y_train)).batch(30) test_data = tf.data.Dataset.from_tensor_slices((X_test, y_test)).batch(30)
batch(30):以每組30個的形式,喂入模型時以bacth為單位。一般選2的冪次。
# DatasetV1Adapter型別
train_data
test_data
二:搭建網路
定義神經網路中所有可訓練引數
w1 = tf.Variable(tf.random.truncated_normal([4,3], stddev=0.1, seed=1, dtype=tf.float64))
b1 = tf.Variable(tf.random.truncated_normal([3], stddev=0.1, seed=1, dtype=tf.float64))
因為X的特徵有4個,所以第一層有4個輸入。
且最終分類結果只有3個,所以最後一層輸入為3
又因為模型只有兩層,所以第一層的輸出 = 下一層的輸入,為3。
所以:
- w1維度為:(4, 3)
- b1維度為:(3, )
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的和
三:引數優化
巢狀迴圈迭代,with結構更新引數,顯示當前loss
for epoch in range(epoch):# 資料集級別迭代
for step,(x_train,y_train) in enumerate(train_data):# batch級別迭代
with tf.GradientTape() as tape: # 記錄梯度資訊
# 正向傳播
y = tf.matmul(x_train, w1) + b1 # 神經網路乘、加運算
y = tf.nn.softmax(y) # 使分類輸出轉換成概率的形式,(注意:此操作後,與獨熱碼同量級,可相減求loss)
y_one_hot = tf.one_hot(y_train, depth=3, dtype=tf.float64)# 將標籤值轉換成獨熱碼格式,方便計算loss和acc
# 計算損失loss
loss = tf.reduce_mean(tf.square(y_one_hot - y))
# # 這兩句話的區別是 loss = tf.reduce_mean(tf.square(y_one_hot, y))
loss_all += loss.numpy()
# 計算loss對各個引數的梯度(導數)
grads = tape.gradient(loss, [w1, b1])
# 梯度自更新 w1 = w1 - lr*grads[0]; b1 = b1- lr*grads[1]
w1.assign_sub(lr*grads[0])
b1.assign_sub(lr*grads[1])
print("Epoch {}, loss: {}".format(epoch, loss_all/4))
train_loss_results.append(loss_all / 4)
loss_all = 0
# 求模型的準確率
total_correct, total_number = 0, 0
for x_test, y_test in test_data:
y = tf.matmul(x_test, w1)+b1 # 模型對三個分類的預測概率
y = tf.nn.softmax(y) # 對y進行歸一化
pred = tf.argmax(y, axis=1) # 獲取概率值最大的下標(也就是獲取y的分類)
pred = tf.cast(pred, dtype=y_test.dtype)
# 若分類正確,則correct=1,否則為0
correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
total_correct += int(tf.reduce_sum(correct)) # 把一個批次的分類結果累加起來,儲存到變數中
total_number += x_test.shape[0]
acc = total_correct / total_number
test_acc.append(acc)
print("Test acc: ", acc)
print("-----------------------------------------------")
這裡的 y 相當於是 y_predict,y_test 相當於y_true。通過softmax將 y 轉換成符合概率分佈的概率值(不是很理解為什麼要加這一步,不加好像也可以)。
因為 y 的維度為[batch, 3],y_test 的維度為 [batch, 1]。採取的方法是將 y_test 轉換成(三維)獨熱編碼。
損失函式 loss 即為兩者的方差。
acc/loss視覺化
plt.title("Loss Function Curve")
plt.xlabel("Epoch")
plt.ylabel("Loss")
# 畫出trian_loss_results曲線,且連線圖示是Loss
plt.plot(train_loss_results, label="$Loss$")
# 畫出曲線的圖示(右上角)
plt.legend()
plt.show()
plt.title("Acc Curve")
plt.xlabel("Epoch")
plt.ylabel("Acc")
plt.plot(test_acc, label="$Accuracy$")# 連線圖示是Accuracy
plt.legend()
plt.show()