本文将首先介绍线性回归的数学原理,并借助目前主流的框架进行实现。
1.线性回归的目标
找到一条直线,使得
f
(
x
i
)
=
w
x
i
+
b
f\left( x_i \right) =wx_i+b
f(xi)=wxi+b
如何确定w,b,使损失函数值最小
(
w
∗
,
b
∗
)
=
arg
min
(
w
,
b
)
∑
i
=
1
m
(
f
(
x
i
)
−
y
i
)
2
=
arg
min
(
w
,
b
)
∑
i
=
1
m
(
y
i
−
w
x
i
−
b
)
2
.
\begin{aligned}\left(w^{*}, b^{*}\right) &=\underset{(w, b)}{\arg \min } \sum_{i=1}^{m}\left(f\left(x_{i}\right)-y_{i}\right)^{2} \\ &=\underset{(w, b)}{\arg \min } \sum_{i=1}^{m}\left(y_{i}-w x_{i}-b\right)^{2} . \end{aligned}
(w∗,b∗)=(w,b)argmini=1∑m(f(xi)−yi)2=(w,b)argmini=1∑m(yi−wxi−b)2.
根据梯度下降法可知,当变量沿着梯度方向移动时,函数值增大最快,当变量沿着梯度反方向时,函数值减小最快。
目前,我们要求损失函数的最小值,当然是将变量沿着梯度反方向移动。
假设移动步长为lr,也就是常说的学习率。移动步长过高和过低,都会对我们的结果有一定的影响。通常lr=0.05
w
k
+
1
=
w
k
−
∂
E
∂
w
⋅
l
r
w^{k+1}=w^k-\frac{\partial E}{\partial w}\cdot lr
wk+1=wk−∂w∂E⋅lr
b
k
+
1
=
b
k
−
∂
E
∂
b
⋅
l
r
b^{k+1}=b^k-\frac{\partial E}{\partial b}\cdot lr
bk+1=bk−∂b∂E⋅lr
更新w,b后重新计算损失函数的值,如果损失函数的值不小于我们预先设定的值,则继续进行更新参数,直到损失函数的值足够小后,结束。输出w,b。
2.PyTorch实现线性回归
import torch
torch.manual_seed(10)
lr = 0.05 # 学习率
# 创建训练数据
x = torch.rand(20, 1) * 10 # x data (tensor), shape=(20, 1)
# torch.randn(20, 1) 用于添加噪声
y = 2*x + (5 + torch.randn(20, 1)) # y data (tensor), shape=(20, 1)
# 构建线性回归参数
w = torch.randn((1), requires_grad=True) # 设置梯度求解为 true
b = torch.zeros((1), requires_grad=True) # 设置梯度求解为 true
# 迭代训练 1000 次
for iteration in range(1000):
# 前向传播,计算预测值
wx = torch.mul(w, x)
y_pred = torch.add(wx, b)
# 计算 MSE loss
loss = (0.5 * (y - y_pred) ** 2).mean()
# 反向传播
loss.backward()
# 更新参数
b.data.sub_(lr * b.grad)
w.data.sub_(lr * w.grad)
# 每次更新参数之后,都要清零张量的梯度
w.grad.zero_()
b.grad.zero_()
if loss.data.numpy() < 1:
break
3.tensorflow2.0实现线性回归
# https://blog.csdn.net/qq_40643699/article/details/108836622
import tensorflow as tf
import numpy as np
# 前期准备---数据处理:归一化
x_row = np.array([2013, 2014, 2015, 2016, 2017], dtype=np.float32)
y_row = np.array([12000, 14000, 15000, 16500, 17500], dtype=np.float32)
# 数据归一化需要用np容器类型的数据,因为TensorFlow没有x.min和x.max操作
x = (x_row - x_row.min()) / (x_row.max() - x_row.min())
y = (y_row - y_row.min()) / (y_row.max() - y_row.min())
# 利用TensorFlow2.0来线性回归
X = tf.constant(x)
Y = tf.constant(y) # 数据类型转换:因为使用到了TensorFlow的库,所以在这里所有变量都需要时Tensor类型了
a = tf.Variable(initial_value=0.)
b = tf.Variable(initial_value=0.)
variable = [a, b]
epoch = 30000
optimizer = tf.keras.optimizers.SGD(learning_rate=0.00001)
for i in range(epoch):
with tf.GradientTape() as tape:
Y_predict = a * X + b
loss = tf.reduce_sum(tf.square(Y_predict - Y))
grad = tape.gradient(loss, variable)
print('gradient', grad)
optimizer.apply_gradients(grads_and_vars=zip(grad, variable))
print('a', a, 'b', b)