1. 程式人生 > 實用技巧 >案例一:鳶尾花資料的分類

案例一:鳶尾花資料的分類

一:準備資料

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()