这是一个项目实践,通过自动微分、反向传播的方式来实现一个线性回归算法。
引入torch库
# 实现简单线性回归 import torch
定义超参数
# 定义超参数 learning_rate = 0.0007 times = 10000 * 8 # 训练次数
超参数就是在训练开始前需要预设的一些参数,这些参数会很大程度影响训练的速度和质量。
加载数据
这里随机生成一些点就可以了,根据函数表达式y = 3 * x + 0.8来构建x和y,定义域为[0, 1]。
x和y都是一个大小为[500, 1]的矩阵。
# 加载数据 x = torch.rand([500, 1]) y = 3 * x + 0.8
设置参数
这两个参数\(w, b\)就是我们要更新的两个值。
# 设置参数 w = torch.rand([1, 1], requires_grad=True, dtype=torch.float32) b = torch.rand([1, 1], requires_grad=True, dtype=torch.float32)
在经过许多轮的训练后,计算机可以算出最好的w和b。
计算预测值和loss误差
我们要不断地修改\(w, b\),但是往那个方向修改呢?就是往loss减少的方向,也就是w和b的在loss上的导数的方向(也叫梯度下降的方向)。
loss的计算公式为\(loss = mean((y - y_{pre})^2)\),这里\(y\)和\(y_{pre}\)都是一个向量(一维矩阵)。
y_predict = torch.matmul(x, w) + b # 因为是标量所以w * x + b也可以。 loss = (y - y_predict).pow(2).mean()
梯度下降更新w和b
注意前面的w和b有一个特殊的参数requires_grad=True,这表明w和b会被跟踪记录他们的梯度。
此时需要将loss反向传播,即可计算出w和b在loss上的梯度。
但是在前面一篇文章讲过《[Pytorch]机器学习入门项目笔记:自动微分(2) (eriktse.com)》,多次的backward一般是不允许的,因为这里的梯度是叠加上去算的,所以我们需要在每次训练开始将梯度初始化为0。
# 将梯度数据清空 if w.grad is not None: w.grad.data.zero_() if b.grad is not None: b.grad.data.zero_() loss.backward() # 反向传播 w.data = w.data - w.grad * learning_rate # 梯度下降 b.data = b.data - b.grad * learning_rate if i % 50 == 0: print(w.item(), b.item(), loss.item())
完整代码
# 实现简单线性回归 import torch # 定义超参数 learning_rate = 0.0007 times = 10000 * 8 # 加载数据 x = torch.rand([500, 1]) y = 3 * x + 0.8 # 设置参数 w = torch.rand([1, 1], requires_grad=True, dtype=torch.float32) b = torch.rand([1, 1], requires_grad=True, dtype=torch.float32) for i in range(times): y_predict = torch.matmul(x, w) + b loss = (y - y_predict).pow(2).mean() # 将梯度数据清空 if w.grad is not None: w.grad.data.zero_() if b.grad is not None: b.grad.data.zero_() loss.backward() # 反向传播 w.data = w.data - w.grad * learning_rate # 梯度下降 b.data = b.data - b.grad * learning_rate if i % 50 == 0: print(w.item(), b.item(), loss.item())
Comments NOTHING