單變數線性迴歸:TensorFlow 實戰(實戰篇)
導語
目錄慕課:《深度學習應用開發-TensorFlow實踐》
章節:第五講 單變數線性迴歸:TensorFlow 實戰
這一講理論部分請看https://www.cnblogs.com/tangkc/p/15371331.html,TensorFlow版本為2.3
我們所要實現的是一個單變數的線性方程,這個方程可以表示為y=w*x+b
。本案例通過生成人工資料集,隨機生成一個近似取樣隨機分佈,使得w=2.0
,b=1
,並加入一個噪聲,噪聲的最大振幅為0.4
匯入庫並生成資料集
匯入庫
import tensorflow as tf import numpy as np import matplotlib.pyplot as plt #在jupyter中使用matplotlib顯示影象需要設定為inline模式,否則不會在網頁中顯示影象 %matplotlib inline tf.__version__
output:
2.3.0
生成資料集
首先生成輸入資料,構造滿足這個函式的x和y,同時加入一些不滿足方程的噪聲
#直接採用np生成等差數列的方法,生成100個點,取值在[-1,1]
x_data=np.linspace(-1,1,100)
np.random.seed(5)#設定隨機數種子
#產生對應的y=2x+1的值,同時加入噪聲
y_data=2*x_data+1.0+np.random.randn(*x_data.shape)*0.4
np.random.randn
是從標準正態分佈中返回一個或多個樣本值,舉個簡單的例子
而原始碼中的np.random.randn(*x_data.shape)
效果和np.random.randn(100)
是一樣的
下面我們畫一下生成的x
和y
的影象
plt.scatter(x_data,y_data)
plt.xlabel('x')
plt.ylabel('y')
plt.title("Training Data")
# 畫出我們想要得到的目標函式y=2x+1
plt.plot(x_data,1.0+2*x_data,'r',linewidth=3)
構建模型
建模
這個模型還是比較的簡單的
def model(x,w,b):
return tf.multiply(x,w)+b
建立待優化變數
w=tf.Variable(np.random.randn(),tf.float32)# 斜率
b=tf.Variable(0.0,tf.float32)#截距
定義損失函式
損失函式用於描述預測值和真實值之間的誤差,從而指導模型收斂方向,常用的有均方差(MSE)和交叉熵
這裡我們用的是均方差
#定義均方差損失函式
def loss(x,y,w,b):
err=model(x,w,b)-y#計算預測值和真實值之間的差異
squarred_err=tf.square(err)#求平方,得出方差
return tf.reduce_mean(squarred_err)#求均值,得出均方差
訓練模型
設定訓練超引數
epochs=10#迭代次數
lr=0.01#學習率
定義計算梯度函式
def grad(x,y,w,b):
with tf.GradientTape() as tape:
loss_=loss(x,y,w,b)
return tape.gradient(loss_,[w,b])# 返回梯度向量
這裡有一個TF1
和TF2
不同的地方,在 TensorFlow 2
中,使用 tf.GradientTape()
這一上下文管理器封裝需要求導的計算步驟,並使用其 gradient()
方法求導。
執行訓練(SGD)
step=0# 記錄訓練步數
loss_list=[]# 儲存loss值的列表
display_step=10# 控制訓練過程資料資料顯示頻率,不是超引數
for epoch in range(epochs):
for xs,ys in zip(x_data,y_data):
loss_=loss(xs,ys,w,b)# 計算loss
loss_list.append(loss_)
delta_w,delta_b=grad(xs,ys,w,b)#計算梯度
change_w=delta_w*lr#計算w需要調整的量
change_b=delta_b*lr#計算b需要調整的量
w.assign_sub(change_w)
b.assign_sub(change_b)#將w,b變更為減去對應變化量後的值
step=step+1
if step%display_step==0:#顯示訓練過程
print(f'Training Epoch:{epoch+1} Step:{step} Loss:{loss_}')
plt.plot(x_data,w.numpy()*x_data+b.numpy())
這裡就展示一部分的執行結果
本案例所擬合的模型較簡單,訓練5輪之後已經接近收斂,對於複雜模型,需要更多次訓練才能收斂
顯示訓練結果並可視化
print(f'w:{w.numpy()}, b:{b.numpy()}')
plt.scatter(x_data,y_data,label='Original data')
plt.plot(x_data,x_data*2.0+1.0,label="Object line",color='g',linewidth=3)
plt.plot(x_data,x_data*w.numpy()+b.numpy(),label="Fitted line",color='r',linewidth=3)
plt.legend(loc=2)#設定圖例位置
檢視損失變化情況
plt.plot(loss_list)
進行預測
x_test=3.21
predict=model(x_test,w.numpy(),b.numpy())
target=2*x_test+1.0
print(f'預測值:{predict}, 目標值:{target}')
輸出
預測值:7.426405906677246, 目標值:7.42
批量梯度下降BGD模型訓練
隨機梯度下降法 (SGD) 每次迭代只使用一個樣本(批量大小為 1),如果進行足夠的迭代,SGD 也可以發揮作用。“隨機”這一術語表示構成各個批量的一個樣本都是隨機選擇的。
在梯度下降法中,批量指的是用於在單次迭代中計算梯度的樣本總數。
假定批量是指整個資料集,資料集通常包含很大樣本(數萬甚至數千億),此外,資料集通常包含多個特徵。因此,一個批量可能相當巨大。如果是超大批量,則單次迭代就可能要花費很長時間進行計算。
小批量隨機梯度下降法(小批量 SGD) 是介於全批量迭代與 SGD 之間的折衷方案。小批量通常包含 10-1000 個隨機選擇的樣本。小批量 SGD 可以減少 SGD 中的雜亂樣本數量,但仍然比全批量更高效。
那麼,接下來是實現,我們只需要修改一下上面的一部分程式碼就好了。
修改訓練超引數
epochs=100#迭代次數
lr=0.05#學習率
訓練週期和學習率需要做一些調整。訓練週期暫設為100
,意味著所有樣本要參與100
次訓練。學習率設定為0.05
,比SGD
版本的要大。
修改模型訓練過程
loss_list=[]# 儲存loss值的列表
for epoch in range(epochs):
loss_=loss(x_data,y_data,w,b)# 計算loss
loss_list.append(loss_)
delta_w,delta_b=grad(x_data,y_data,w,b)#計算梯度
change_w=delta_w*lr#計算w需要調整的量
change_b=delta_b*lr#計算b需要調整的量
w.assign_sub(change_w)
b.assign_sub(change_b)#將w,b變更為減去對應變化量後的值
print(f'Training Epoch:{epoch+1} Loss={loss_}')
plt.plot(x_data,w.numpy()*x_data+b.numpy())
顯示訓練結果並可視化
print(f'w:{w.numpy()}, b:{b.numpy()}')
plt.scatter(x_data,y_data,label='Original data')
plt.plot(x_data,x_data*2.0+1.0,label="Object line",color='g',linewidth=3)
plt.plot(x_data,x_data*w.numpy()+b.numpy(),label="Fitted line",color='r',linewidth=3)
plt.legend(loc=2)#設定圖例位置
損失值視覺化
plt.plot(loss_list)
完整程式碼
點選檢視程式碼
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
#在jupyter中使用matplotlib顯示影象需要設定為inline模式,否則不會在網頁中顯示影象
%matplotlib inline
#直接採用np生成等差數列的方法,生成100個點,取值在[-1,1]
x_data=np.linspace(-1,1,100)
np.random.seed(5)#設定隨機數種子
#產生對應的y=2x+1的值,同時加入噪聲
y_data=2*x_data+1.0+np.random.randn(*x_data.shape)*0.4
# np.random.randn是從標準正態分佈中返回一個或多個樣本值,
np.random.randn(10)
plt.scatter(x_data,y_data)
plt.xlabel('x')
plt.ylabel('y')
plt.title("Training Data")
# 畫出我們想要得到的目標函式y=2x+1
plt.plot(x_data,1.0+2*x_data,'r',linewidth=3)
def model(x,w,b):
return tf.multiply(x,w)+b
w=tf.Variable(np.random.randn(),tf.float32)# 斜率
b=tf.Variable(0.0,tf.float32)#截距
#定義均方差損失函式
def loss(x,y,w,b):
err=model(x,w,b)-y#計算預測值和真實值之間的差異
squarred_err=tf.square(err)#求平方,得出方差
return tf.reduce_mean(squarred_err)#求均值,得出均方差
def grad(x,y,w,b):
with tf.GradientTape() as tape:
loss_=loss(x,y,w,b)
return tape.gradient(loss_,[w,b])# 返回梯度向量
epochs=100#迭代次數
lr=0.05#學習率
loss_list=[]# 儲存loss值的列表
for epoch in range(epochs):
loss_=loss(x_data,y_data,w,b)# 計算loss
loss_list.append(loss_)
delta_w,delta_b=grad(x_data,y_data,w,b)#計算梯度
change_w=delta_w*lr#計算w需要調整的量
change_b=delta_b*lr#計算b需要調整的量
w.assign_sub(change_w)
b.assign_sub(change_b)#將w,b變更為減去對應變化量後的值
print(f'Training Epoch:{epoch+1} Loss={loss_}')
plt.plot(x_data,w.numpy()*x_data+b.numpy())
print(f'w:{w.numpy()}, b:{b.numpy()}')
plt.scatter(x_data,y_data,label='Original data')
plt.plot(x_data,x_data*2.0+1.0,label="Object line",color='g',linewidth=3)
plt.plot(x_data,x_data*w.numpy()+b.numpy(),label="Fitted line",color='r',linewidth=3)
plt.legend(loc=2)#設定圖例位置
plt.plot(loss_list)
梯度下降演算法總結
批量梯度下降每次迭代都考慮了全部的樣本,做的是全域性優化,但花費的計算資源較大,如果訓練資料非常大,還無法實現全部樣本同步參與。
隨機梯度下降每次迭代只取一條樣本資料, 由於單個樣本的訓練可能會帶來很多噪聲,使得SGD並不是每次迭代都向著整體最優化方向,因此在剛開始訓練時可能收斂得很快,但是訓練一段時間後就會變得很慢。
在SGD和BGD中間,還有一個集合了兩種梯度下降法的優點的方法:小批量梯度下降(MBGD,Mini-batch gradient descent),每次迭代從訓練樣本中隨機抽取一小批進行訓練,這個一小批的數量取值也是一個超引數。
小結
通過一個簡單的例子介紹了利用Tensorflow實現機器學習的思路,重點講解了下述步驟:
- 生成人工資料集及其視覺化
- 構建線性模型
- 定義損失函式
- (梯度下降) 優化過程
- 訓練結果的視覺化
- 利用學習到的模型進行預測
學習筆記,僅供參考,如有錯誤,敬請指正!
同時釋出在CSDN中:https://blog.csdn.net/tangkcc/article/details/120624865