TensorFlow2.1入門學習筆記(5)——構建第一個神經網絡,鳶尾花分類問題(附源碼)


根據前面的基礎知識,可以開始第一個神經網絡的搭建,主要學習的資料西安科技大學:神經網絡與深度學習——TensorFlow2.0實戰,北京大學:人工智能實踐Tensorflow筆記

TensorFlow2.0入門學習筆記(5)——構建第一個神經網絡,鳶尾花分類問題(附源碼)

1.問題背景

問題描述

在這里插入圖片描述
人們通過經驗總結出的規律:通過測量鳶尾花的花萼長、花萼寬、花瓣長、花瓣寬,可以得出鳶尾花的類別。(如:花萼長>花萼寬 且 花瓣長/花瓣寬>2 則為雜色鳶尾花)。大量依靠人工分類工作量巨大,不同的人員分類,標准,准確率都會有所差距。可以借助深度學習來學習其中的特征並對新數據進行預測。

流程設計

  • 大量的[花萼長、花萼寬、花瓣長、花瓣寬(輸入特征),對應的類別(標簽)]數據對構成數據集
  • 把數據集喂入搭建好的神經網絡結構
  • 網絡優化參數得到模型
  • 模型讀入新輸入特征,輸出識別結果
    在這里插入圖片描述

模型設計

搭建網絡模型

在這里插入圖片描述

轉換為數學模型

所有輸入特征x與相應特征權重w相乘加上偏置項b輸出結果y。
x:一行四列矩陣,對應四個特征
w:四行三列矩陣
b:3個偏置項
y:一行三列矩陣,對應三種類別的可信度
在這里插入圖片描述

搭建網絡

每個神經元\(y_0,y_1,y_2與輸入節點x_0,x_1,x_2,x_3\)都有聯系,稱為全連接神經網絡權重w與偏置項b會隨機初始化一組參數
在這里插入圖片描述

前向傳播

神經網絡執行y = x * w + b的過程稱為前向傳播
在這里插入圖片描述

損失函數

損失函數:預測值(y)與標准答案(\(y_i\))的差距,可以定量判斷w,b的優劣,當損失函數輸出最小時會出現最優解。(有多種損失函數,這里用均方誤差)

  • 均方誤差:\(MSE(y,y_i)=\frac{\sum_{k=0}^n(y-y_i)^2}{n}\)
    在這里插入圖片描述
梯度下降

目的:找到一組參數w和b,使得損失函數最小。
梯度:函數對個參數求偏導后的向量,梯度下降的方向是函數減小的方向。
梯度下降:延損失函數梯度下降的方向,尋找損失函數的最小值,得到最優參數。
學習率(learning rate, lr):當學習率設置過小時,收斂過程將變得十分緩慢。當學習率設置過大時,梯度可能會在最小值附近震盪,甚至無法收斂
在這里插入圖片描述

反向傳播

\(w_{t+1}=w_t-lr*\frac{\partial loss}{\partial w_t}\)
從前向后,逐層求損失函數對每層神經元參數的偏導數,迭代更新所有參數。
在這里插入圖片描述

2.數據讀入

數據集介紹:

該數據集已集成在sklearn包中,可直接調入使用,數據共有150組,每組包括花萼長、花萼寬、花瓣長、花瓣寬共四個輸入特征。同時給出了這一組特征的的對應鳶尾花類別。類別包括Setosa Iris(狗尾草鳶尾),Versicolour Iris(雜色鳶尾),Viginaica Iris(弗吉尼亞鳶尾)三類,分別用數字0,1,2表示
在這里插入圖片描述

  • 從sklearn包datasets讀入數據集
from sklearn.datasets import load_iris
x_data = datasets.load_iris().data		#讀入iris數據集的所有輸入特征
y_data = datasets.load_iris().target	#讀入iris數據集所有標簽

數據預處理

  • 數據集亂序:隨機打亂數據
# seed: 隨機數種子,是一個整數,當設置之后,每次生征和標簽一一對應
np.random.seed(116)
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:]
  • 輸入特征和標簽值一一對應,把數據集分批次,每個批次batch(32)組數據
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)

數據訓練

  • 定義神經網絡中所有參數可訓練
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))
  • 嵌套循環迭代,with結構更新參數,顯示當前loss
for epoch in range(epoch):  # 數據集級別迭代
    for step, (x_train, y_train) in enumerate(train_db):  # batch級別的迭代
        with tf.GradientTape() as tape:  # 記錄梯度信息
        	# 前向傳播過程計算y
        	# 計算總loss
        grads = tape.gradient(loss, [w1, b1])	# 求導
        w1.assign_sub(lr * grads[0])  # 參數w1自更新
        b1.assign_sub(lr * grads[1])  # 參數b自更新
    # 每個epoch,打印loss信息
    print("Epoch {}, loss: {}".format(epoch, loss_all/4))
  • 計算當前參數前向傳播后的准確率,顯示當前acc(accuracy)
    for x_test, y_test in test_db:
        y = tf.matmul(x_test, w1) + b1	# y為預測結果
        y = tf.nn.softmax(y)	# y符合概率分布
        pred = tf.argmax(y, axis=1)  # 返回y中最大值的索引,即預測的分類
        pred = tf.cast(pred, dtype=y_test.dtype)	# 調整參數類型與標簽一致
        correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
        correct = tf.reduce_sum(correct)	# 將所有batch中的correct數加起來
        total_correct += int(correct)	# 將所有batch中的correct數加起來
        total_number += x_test.shape[0]
    acc = total_correct / total_number
    test_acc.append(acc)
    print("Test_acc:", acc)

數據可視化

  • 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()  # 畫出圖像
  • acc可視化
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()

3.完整源碼

# 導入所需模塊
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(116)  # 使用相同的seed,保證輸入特影響准確率)
# 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使每次生成的隨機數相同
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()

CSDN鏈接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM