5分鐘入門到實戰!基於神經網絡——鳶尾花識別(Iris)

ai人工智能知識庫 發佈 2024-01-18T16:34:15.415276+00:00

前言鳶尾花識別是學習AI入門的案例,這裡和大家分享下使用Tensorflow 2框架,編寫程序,獲取鳶尾花數據,搭建神經網絡,最後訓練和識別鳶尾花。

前言

鳶尾花識別是學習AI入門的案例,這裡和大家分享下使用tensorflow 2框架,編寫程序,獲取鳶尾花數據,搭建神經網絡,最後訓練和識別鳶尾花。

目錄

  • 鳶尾花識別——思路流程:
  • 認識鳶尾花
  • 獲取鳶尾花數據
  • 整理數據為訓練集,測試集
  • 搭建神經網絡模型
  • 鳶尾花識別 完整代碼:

如果需要獲取到這個【實戰項目合集+源碼的話幫忙轉發、轉發、轉發一下然後再關注我私信回復「學習」得到獲取方式吧!


鳶尾花識別——思路流程:

1)獲取鳶尾花數據,分析處理。

2)整理數據位訓練集,測試集。

3)搭建神經網絡模型

4)訓練網絡,優化網絡模型參數。

5)保存最優的模型,進行鳶尾花識別。


認識鳶尾花

我們先認識下什麼是鳶尾花?

鳶尾花分類:狗尾草鳶尾、雜色鳶尾、維吉尼亞鳶尾

鳶尾花的特徵是什麼呢?

鳶尾花花萼長、花萼寬、花瓣長、花瓣寬。我們通過對數據進行分析總結出了規律:通過測量花的花萼長、花萼寬、花瓣長、花瓣寬,可以得出鳶尾花的類別(如:花萼長>花萼寬且花瓣長/花瓣寬>2 ,則雜色鳶尾)


獲取鳶尾花數據

4 個屬性作為輸入特徵:花萼長、花萼寬、花瓣長、花瓣寬 ;

類別作為標籤,0 代表狗尾草鳶尾,1 代表雜色鳶尾,2 代表維吉尼亞鳶尾。

iris數據集 即鳶尾花數據。x_data 存放 iris數據集所有輸入特徵(4 種);y_data存放 iris數據集所有標籤(3種)

  • from sklearn import datasets
  • from pandas import DataFrame
  • import pandas as pd

  • x_data = datasets.load_iris().data # .data返回iris數據集所有輸入特徵
  • y_data = datasets.load_iris().target # .target返回iris數據集所有標籤
  • print("x_data from datasets: \n", x_data)
  • print("y_data from datasets: \n", y_data)

  • x_data = DataFrame(x_data, columns=['花萼長度', '花萼寬度', '花瓣長度', '花瓣寬度']) # 為表格增加行索引(左側)和列標籤(上方)
  • pd.set_option('display.unicode.east_asian_width', True) # 設置列名對齊
  • print("x_data add index: \n", x_data)

  • x_data['類別'] = y_data # 新加一列,列標籤為『類別』,數據為y_data
  • print("x_data add a column: \n", x_data)


在sklearn庫中,x_data,y_data的原始數據:

在x_data[ ]數據中,新加一列,列標籤為『類別』,數據為y_data:


整理數據為訓練集,測試集

把輸入特徵 和 標籤 做成數據對,即每一行輸入特徵有與之對應的類別;得出一共150行數據;其中75%作為訓練集,即120行;25%作為測試集,即後30行。

注意:訓練集和測試集,沒有交集,它們之間都沒有一樣的數據。

  • # 導入所需模塊
  • 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)

為了訓練更高效,通常會把數據變成batch(包),例如,把32行數據為一個小包batch。


搭建神經網絡模型

從數據中分析出,有4個輸入特徵,所以輸入層有4個節點;鳶尾花3種類別,所以輸出層有3個節點. 我們需要初始化網絡中的參數(權值、偏置)。

通過前向傳播計算,即從輸入層到輸出層疊代計算,預測出是那個類別的鳶尾花,對比是否預測正確(通過損失函數計算出 預測值和真實值的偏差,這個偏差越小代表預測越接近真實;最終選擇最優的參數)。

輸入層和輸出層之間的映射關係接近正確的,模型基本訓練好了。

即所有的輸入 x 乘以各自線上的權重 w 求和加上偏置項 b 得到輸出 y 。

輸出 y 中,1.01 代表 0 類鳶尾得分,2.01 代表 1 類鳶尾得分,-0.66 代表 2 類鳶尾得分。通過輸出 y 可以看出數值最大(可能性最高)的是 1 類鳶尾,而5不是標籤 0 類鳶尾。這是由於最初的參數 w 和 b 是隨機產生的,現在輸出的結果是不準確的。

為了修正這一結果,我們用 損失函數,定義預測值 y 和標準答案(標籤)_y 的差距,損失函數可以定量的判斷當前這組參數 w 和 b 的優劣,當損失函數最小時,即可得到最優 w 的值和 b 的值。

損失函數,其目的是尋找一組參數 w 和 b 使得損失函數最小。為達成這一目的,我們採用梯度下降的方法。

損失函數的梯度 表示損失函數對各參數求偏導後的向量,損失函數梯度下降的方向,就是是損失函數減小的方向。梯度下降法即沿著損失函數梯度下降的方向,尋找損失函數的最小值,從而得到最優的參數。

首先來看看梯度下降的一個直觀的解釋。比如我們在一座大山上的某處位置,由於我們不知道怎麼下山,於是決定走一步算一步,也就是在每走到一個位置的時候,求解當前位置的梯度,沿著梯度的負方向,也就是當前最陡峭的位置向下走一步,然後繼續求解當前位置梯度,向這一步所在位置沿著最陡峭最易下山的位置走一步。這樣一步步的走下去,一直走到覺得我們已經到了山腳。當然這樣走下去,有可能我們不能走到山腳,而是到了某一個局部的山峰低處。

  從上面的解釋可以看出,梯度下降不一定能夠找到全局的最優解,有可能是一個局部最優解。當然,如果損失函數是凸函數,梯度下降法得到的解就一定是全局最優解。


鳶尾花識別 完整代碼:

  • # -*- 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()


訓練過程,一共疊代500次,最後得出 loss: 0.032300274819135666 Test_acc: 1.0

隨著疊代次數的增加,損失率(預估值和真實值的偏差)在減少;準確率在不多提高,最終到達100%(即:1)

如果需要獲取到這個【實戰項目合集+源碼的話幫忙轉發、轉發、轉發一下然後再關注我私信回復「學習」得到獲取方式吧!

關鍵字: