一文看懂 -- TensorFlow實戰之單變量線性迴歸 -- 的全過程

本文簡單分析單變量線性迴歸問題

使用TensorFlow進行算法設計與訓練的核心步驟

  • 1.準備數據
  • 2.構建模型
  • 3.訓練模型
  • 4.進行預測

其中,準備數據的數據或爲需要分析的數據(由現實生活中的數據分析和清洗而得到),或爲人工生成的數據集(主要用於算法的驗證)。

而單變量線性迴歸實戰就是通過人工生成的隨機數集進行分析的。

單變量線性迴歸

迴歸問題:迴歸指的是根據已有的數據特徵預測出一個樣本對應的預測標籤值。
簡單來說,根據給定的數據集,且數據集中的每個樣本都有其對應的值(標籤值),通過給定的數據集進行擬合,找出一條能夠最好代表該數據集的線,然後對於任意給定的樣本,都能夠預測出該樣本對應的值(標籤)。比如,房價預測問題。

單變量線性迴歸問題,即該給定的數據集只有一個特徵/輸入變量 x ,同時它擬合的線爲直線。

單變量線性迴歸實戰

實驗函數:y = w*x + b(x爲特徵,y即標籤)
本例通過生成人工數據集。隨機生成一個近似採樣隨機分佈,使得 w=2.0 b=1,並加入一個噪聲,噪聲的最大振幅爲0.4。(若不加入噪聲,否則生成的點都是直線上的點)

0.導入相關的庫(前置工作)

import tensorflow as tf  # tensorflow 2.0版本
import numpy as np
import matplotlib.pyplot as plt
​
# 在Jupyter中,使用matplotlib顯示圖像需要設置爲inline模式,否則不會顯示圖像
%matplotlib inline

1.人工數據集生成(構建滿足這個函數的x,y並加入噪聲)
採用 numpy 生成等差數列的方法,生成100個點,每個點的取值在-1~1之間,這些點即給定的數據(特徵)集。

# 直接採用np生成等差數列的方法,生成100個點,每個點的取值在-1~1之間
x_data = np.linspace(-1,1,100)

np.random.seed(5)  # 設置隨機數種子(使隨機數結果每次都能重現,可去除)
# y = 2x + 1 + 噪聲,其中,噪聲的維度與x_data一致
y_data = 2*x_data + 1.0 + np.random.randn(*x_data.shape)*0.4

2.構建迴歸模型
在此模型中,x 是每一個樣本點的x軸的值;w,b纔是模型的真正參數(通過訓練模型,求出最合適的w,b,使得此模型在100個樣本點的計算中總損失最小)

# 通過模型執行,將實線前向計算(預測計算)
def model(x,w,b):
    return tf.multiply(x,w)+b   # return w*x+b

3.創建待優化變量

  • tensorflow變量的聲明函數是tf.Variable
  • tf.Variable的作用是保存和更新參數
  • 變量的初始化可以是隨機數、常數、或是通過其他變量的初始值計算得到(通常都不會影響模型最後優化的結果)
# 構建模型中的變量w,對應線性函數的斜率
w = tf.Variable(np.random.randn(),tf.float32)

# 構建模型中的變量b。對應線性函數的截距
b = tf.Variable(0.0,tf.float32)

4.定義損失函數

損失是評價一個模型優良的度量標準,表示對於單個樣本而言模型預測的準確程度。

  • 損失函數用於描述預測值與真實值之間的誤差,從而指導模型收斂方向
  • 常見損失函數:均方差(MSE)和交叉熵(cross-entropy)

對於迴歸問題,最常用的損失函數就是均方差(MSE,Mean Squared Error)。均方差是指預測值和實際值之間的平均方差。平均方差越小,說明測試值和實際值之間的差距越小,即模型性能更優。

均方差損失函數
在這裏插入圖片描述

# 定義均方差損失函數
def loss(x,y,w,b):
    err = model(x,w,b)-y   # 計算模型預測值和標籤值得差異
    squared_err = tf.square(err)   # 求平方,得出方差
    return tf.reduce_mean(squared_err)    # 求均值,得出均方差

5.設置訓練超參數

在機器學習中,超參數是在開始學習過程之前設置值的參數,而不是通過訓練得到的參數數據。
通常情況下,需要對超參數進行優化,選擇一組好的超參數,可以提高學習的性能和效果。

training_epochs = 10  # 迭代次數(訓練輪次)
learning_rate = 0.01  # 學習率

關於學習率

  • 學習率的作用:控制參數更新的幅度
  • 如果學習率設置過大,可能導致參數在極值附近來回搖擺,無法保證收斂
  • 如果學習率設置過小,雖然能保證收斂,但是優化速度會大大降低,需要更多的迭代次數才能達到較理想的優化效果

6.定義計算梯度函數

# 計算樣本數據[x,y]在參數[w,b]點上的梯度(對應優化器)
def grad(x,y,w,b):
	# x,y對應特徵值和標籤值+所有需要優化的參數(變量)
    with tf.GradientTape() as tape:
        loss_ = loss(x,y,w,b)
    return tape.gradient(loss_,[w,b])  # 返回梯度向量

在tensorflow 2中,使用tf.GradientTape()這一上下文管理器封裝需要求導的計算步驟,並使用其gradient()方法求導。(tensorflow 1.x 版本是通過定義梯度下降優化器說明需要最小化損失值)

7.執行訓練(採用隨機梯度下降SGD)

step = 0  # 記錄訓練步數
loss_list = []    # 用於保存loss值的列表
display_step = 10      # 控制訓練過程數據顯示的頻率,不是超參數

for epoch in range(training_epochs):
    for xs,ys in zip(x_data,y_data):
        loss_ = loss(xs,ys,w,b)   # 計算損失
        loss_list.append(loss_)   # 保存本次損失計算結果
        
        # 訓練更新 w,b
        delta_w,delta_b = grad(xs,ys,w,b)  # 計算該當前[w,b]點的梯度
        change_w = delta_w * learning_rate      # 計算變量w需要調整的量
        change_b = delta_b * learning_rate      # 計算變量b需要調整的量
        w.assign_sub(change_w)   # 變量w值變更爲減去change_w後的值
        b.assign_sub(change_b)   # 變量b值變更爲減去change_b後的值
        
        step = step+1   # 訓練步數+1
        if step%display_step == 0:   # 顯示訓練過程信息
            print("Training Epoch:",'%02d'%(epoch+1),"Step:%03d"%(step),"loss_=","%.6f"%(loss_))
    plt.plot(x_data,w.numpy()*x_data+b.numpy())   # 完成一輪訓練後,畫出迴歸的線條

輸出如圖(省略部分損失值的打印輸出):
在這裏插入圖片描述
從上圖可知,由於本案例所擬合的模型較簡單,訓練5、6輪之後已經接近收斂(迴歸線條重合)。
對於複雜模型,需要更多次訓練才能收斂。

8.顯示訓練結果(即w,b的訓練結果)

print("w:",w.numpy())   # w的值應該在2附加
print("b:",b.numpy())   # b的值應該在1附加

輸出:
在這裏插入圖片描述
9.結果可視化

訓練結果可視化:

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)  # 通過參數loc指定圖例的位置

輸出結果:
在這裏插入圖片描述
紅線(訓練函數y=wx+b,其中w,b經訓練獲得)與綠線(目標函數y=2*x+1)將近重合。

損失可視化:

plt.plot(loss_list)

輸出:
在這裏插入圖片描述
可以看到,經過前幾輪的訓練後,模型漸進於收斂,損失值變化都不大。

10.根據訓練結果進行預測

x_test = 3.21  # 測試樣本

predict = model(x_test,w.numpy(),b.numpy())
print("預測值:%f"%predict)

target = 2*x_test+1.0
print("目標值:%f"%target)

輸出:
在這裏插入圖片描述

本文是通過隨機梯度下降(SGD)算法對數據集進行迭代訓練,有興趣的小夥伴可以試試通過批量梯度下降(BGD)算法進行訓練。。。

附上批量梯度下降(BGD)算法訓練需更改代碼:

1.修改超參數

training_epochs = 100  # 迭代次數(訓練輪次)
learning_rate = 0.10  # 學習率

訓練週期和學習率需做調整。迭代次數設置爲100,表示要參與100次訓練;學習率設置爲0.10,比SGD算法的大些。

2.修改模型訓練過程(BGD)

loss_list = []    # 用於保存loss值的列表

for epoch in range(training_epochs):
    loss_ = loss(x_data,y_data,w,b)   # 計算損失
    loss_list.append(loss_)   # 保存本次損失計算結果
        
    delta_w,delta_b = grad(x_data,y_data,w,b)  # 計算該當前[w,b]點的梯度
    change_w = delta_w * learning_rate      # 計算變量w需要調整的量
    change_b = delta_b * learning_rate      # 計算變量b需要調整的量
    w.assign_sub(change_w)   # 變量w值變更爲減去change_w後的值
    b.assign_sub(change_b)   # 變量b值變更爲減去change_b後的值
           
    print("Training Epoch:",'%02d'%(epoch+1),"loss=%.6f"%(loss_))
    plt.plot(x_data,w.numpy()*x_data+b.numpy())   # 完成一輪訓練後,畫出迴歸的線條

訓練100次,將每次的損失值存入 loss_list 列表。

訓練結果可視化:

損失值(部分截圖):
在這裏插入圖片描述
除了開始幾輪訓練損失值波動較大外,後續損失值漸近。

迴歸線:
在這裏插入圖片描述
畫出的迴歸線漸漸重合(顏色較深的部分)。

:損失值的可視化

plt.plot(loss_list)

輸出:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章