一文看懂 -- 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)

输出:
在这里插入图片描述

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