簡單說分四步
01準(zhǔn)備數(shù)據(jù) 02搭建網(wǎng)絡(luò) 03優(yōu)化訓(xùn)練參數(shù)————(訓(xùn)練部分 + 測試部分)循環(huán) 04作圖——loss,acc
import tensorflow as tf
import numpy as np
from sklearn import datasets
from matplotlib import pyplot as plt
#01準(zhǔn)備數(shù)據(jù)
x_data=datasets.load_iris().data
y_data=datasets.load_iris().target
#數(shù)據(jù)集亂序
np.random.seed(116)
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116)
#劃分訓(xùn)練集(前120個數(shù)據(jù))和測試集(后30個數(shù)據(jù))
x_train=x_data[:-30]
y_train=y_data[:-30]
x_test=x_data[-30:]
y_test=y_data[-30:]
#統(tǒng)一數(shù)據(jù)類型為float32,以免后面矩陣相乘時因為數(shù)據(jù)類型不一致而報錯
x_train=tf.cast(x_train,tf.float32)
x_test=tf.cast(x_test,tf.float32)
#數(shù)據(jù)配對,使用tensorflow數(shù)據(jù)切片
#使得輸入數(shù)據(jù)(特征)和標(biāo)簽一一配對,訓(xùn)練集120對數(shù)據(jù),測試集30對數(shù)據(jù)
#并分組打包,每32對數(shù)據(jù)打包為一個batch,方便后面模型訓(xùn)練
#所以訓(xùn)練集包含4個batch,測試集包含1個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)
#02 搭建網(wǎng)絡(luò)
#定義網(wǎng)絡(luò)的初始參數(shù)
#隨機(jī)生成符合[截斷式正太分布]的初始參數(shù) w1[4*3] 和 b1[3]
#參數(shù)標(biāo)要記為可訓(xùn)練Variable,而不是常量constant
#標(biāo)準(zhǔn)差0.1,隨機(jī)數(shù)種子seed=1
#(truncated——截斷式,意思就是生成的參數(shù),在均值的上下兩個標(biāo)準(zhǔn)差范圍內(nèi),是為了讓生成的隨機(jī)數(shù)不要相差太多)
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 #學(xué)習(xí)率
epoch=500
#迭代次數(shù)500輪,每輪都在更新參數(shù),看能不能吧損失函數(shù)降到最低,不能的話可以再增加迭代次數(shù)
#可以看到結(jié)果,大概185次迭代后,acc就達(dá)到1了,但是loss還在降低。注意過擬合問題
#新建兩個空列表
#一個記錄每一輪訓(xùn)練后得到的損失函數(shù)值loss,一個記錄每一輪測試后得到的精度acc
#兩個列表后期用于作圖
train_loss_results=[]
test_acc=[]
#上面說到120個訓(xùn)練樣本組成的訓(xùn)練集,我們劃分為4個batch來喂給模型
#所以每輪都會產(chǎn)生四個loss
#每輪記錄的loss應(yīng)該是四個loss的平均值
#設(shè)置一個變量來累加這四個loss
loss_all=0
#03 優(yōu)化訓(xùn)練參數(shù)————(訓(xùn)練部分 + 測試部分)循環(huán)500次
#一:訓(xùn)練部分
#兩層for循環(huán),外層執(zhí)行500次,內(nèi)層是4個訓(xùn)練集的batch和1個測試集的batch
for epoch in range (epoch):
for step , (x_train,y_train) in enumerate(train_db):
#在with結(jié)構(gòu)中記錄梯度信息,計算每一輪batch的損失函數(shù)值
with tf.GradientTape() as tape:
y=tf.matmul(x_train,w1)+ b1 #計算訓(xùn)練集的預(yù)測值
y=tf.nn.softmax(y) #使y值符合概率分布——softmax激活函數(shù)就是歸一化
y_=tf.one_hot(y_train,depth=3)#使訓(xùn)練集的標(biāo)簽轉(zhuǎn)變?yōu)楠?dú)熱碼
#定義損失函數(shù)為——均方誤差損失函數(shù)
loss=tf.reduce_mean(tf.square(y_-y))
#累計四個batch的loss值,方便后面求每次迭代里,loss的平均值
loss_all=loss_all+loss.numpy()
tf.reduce_mean 函數(shù) 用于計算張量tensor沿著指定的數(shù)軸(tensor的某一維度)上的的平均值,主要用作降維或者計算tensor(圖像)的平均值。
tf.reduce_mean(input_tensor, axis=None, keep_dims=False, name=None )
第一個參數(shù)input_tensor: 輸入的待降維的tensor; 第二個參數(shù)axis: 指定的軸,如果不指定,則計算所有元素的均值; 第三個參數(shù)keep_dims:是否降維度, 設(shè)置為True,輸出的結(jié)果保持輸入tensor的形狀,設(shè)置為False,輸出結(jié)果會降低維度;
#進(jìn)行完一次batch后更新參數(shù)
#01求導(dǎo)(損失函數(shù)對各個參數(shù)),02更新
grads =tape.gradient(loss,[w1,b1])
w1.assign_sub(lr*grads[0])
b1.assign_sub(lr*grads[1])
# ---------- 至此,一個batch的訓(xùn)練結(jié)束,獲得了一個損失函數(shù)值,兩個參數(shù)各更新了1次
#每結(jié)束一次epoch,打印一次loss信息(也就是四個batch,獲得了四次loss累計值loss_all)
print("Epoch{}\nloss:{}".format(epoch,loss_all/4))
#記錄下這輪epoch的loss值 到 之前新建的空列表中,方便后面作圖,同時清空loss_all
train_loss_results.append(loss_all/4)
loss_all=0
#二:測試部分
#注意是包含在外層循環(huán)里的 也就是訓(xùn)練500輪,每一輪都在更新參數(shù)獲得loss,每一輪最后都會測試獲得acc
#預(yù)測正確的樣本個數(shù),測試的總樣本個數(shù)
total_correct,total_number=0,0
#遍歷測試集中的所有數(shù)據(jù),計算前想傳播的預(yù)測結(jié)果
for x_test,y_test in test_db:
#使用更新后的參數(shù)進(jìn)行預(yù)測,并計算分類準(zhǔn)確度acc
y=tf.matmul(x_test,w1)+ b1
y=tf.nn.softmax(y)
#返回y中最大值的索引,即預(yù)測的類別號
pred=tf.argmax(y,axis=1) #axis=1,橫向比較
#將pred轉(zhuǎn)換為和y_test一致的數(shù)據(jù)類型,方便比較
pred=tf.cast(pred,dtype=y_test.dtype)
#將pred 與 y_test 相比較 ,若分類正確,則令correct=1,否則為0
#這里需要把equal的結(jié)果(bool類型)轉(zhuǎn)換為int類型
correct=tf.cast(tf.equal(pred,y_test),dtype=tf.int32)
#將每個batch的correct值加起來
correct=tf.reduce_sum(correct)
#將所有batch的correct值加起來
total_correct=total_correct+int(correct)
#total_number為測試的總樣本數(shù),也就是x_test的行數(shù),.shape[0]返回變量行數(shù)
total_number=total_number+x_test.shape[0] #————————說實話不是很懂這里啥意思,為什么要累加
#計算準(zhǔn)確率acc,每一輪epoch計算一次
acc=total_correct/total_number
#將每一輪的acc丟到之前的空列表,方便后面作圖
test_acc.append(acc)
print("Test_acc:",acc)
print("----------------------------------")
輸出結(jié)果:
Epoch0
loss:0.282131090760231
Test_acc 0.16666666666666666
----------------------------------
Epoch1
loss:0.25459615513682365
Test_acc 0.16666666666666666
----------------------------------
Epoch2
loss:0.22570250555872917
Test_acc 0.16666666666666666
----------------------------------
Epoch3
loss:0.21028400212526321
Test_acc 0.16666666666666666
----------------------------------
Epoch4
loss:0.19942264258861542
Test_acc 0.16666666666666666
----------------------------------
Epoch5
loss:0.18873638287186623
Test_acc 0.5
----------------------------------
Epoch6
loss:0.17851299792528152
Test_acc 0.5333333333333333
----------------------------------
Epoch7
loss:0.16922874748706818
Test_acc 0.5333333333333333
----------------------------------
Epoch8
loss:0.16107673197984695
Test_acc 0.5333333333333333
----------------------------------
Epoch9
loss:0.15404684096574783
Test_acc 0.5333333333333333
----------------------------------
·
·
·
·
·
·
Epoch500
#04 作圖————loss,acc
#loss曲線
plt.title("Loss Function Curve")
plt.xlabel("epoch")
plt.ylabel("loss")
plt.plot(train_loss_results,label="$loss$") #這里的label是指圖片上的圖例名稱
plt.legend() #圖片上的圖例
plt.show()
#accuracy曲線
plt.title("Acc Curve")
plt.xlabel("epoch")
plt.ylabel("acc")
plt.plot(test_acc,label="$acc$") #這里的label是指圖片上的圖例名稱
plt.legend() #圖片上的圖例
plt.show()
|