本篇是一个练手项目,目的在于:
1. 熟悉 pytorch
2. 实现 SGD 与 动量梯度下降,并对比收敛性
本教程环境 pytorch 1.3以上
手动实现线性回归模型,一个很简单的模型,不多介绍,直接上代码
import torch as t import matplotlib.pylab as plt ### 制造数据 def make_data(): # y = 2x+3 x = t.rand(1, 10) * 20 y = x * 2 + 3 + t.randn(1, 10) return x, y ### 初始化参数 t.manual_seed(10000) ### 随机种子 w = t.rand(1, 1) b = t.rand(1, 1) ### 动量梯度的初始值 w0 = 0 b0 = 0 lr = 0.001 loss_record = [] for i in range(10000): x_t, y_t = make_data() y_p = t.matmul(w, x_t) + b loss = t.pow(y_p - y_t, 2) * 0.5 loss = t.mean(loss) ### 可 sum 可 mean,一般和 下面的 grad_b 对应 loss_record.append(loss) ### 手动求导,计算梯度 ## 注意这里对 (yp-yt)^2 求导,是 (yp-yt)x,如果是对 (yt-yp)^2 求导,是 -(yt-yp)x grad_w = t.matmul(y_p - y_t, x_t.t()) ### t() 转置 grad_b = t.mean(y_p - y_t) ### SGD 参数更新 # w -= lr * grad_w # b -= lr * grad_b ### 动量梯度下降的参数更新,收敛效果比 SGD 好很多 grad_w_new = 0.8 * w0 + grad_w w.sub_(lr * grad_w) w0 = grad_w ### 记住本次梯度,作为下次的 w0,这里只是记了上次,可以自己设定计前几次,或者计之前全部 grad_b_new = 0.8 * b0 + grad_b b.sub_(lr * grad_b_new) b0 = grad_b print(w, b) plt.plot(loss_record) plt.show()
下面我把学习率变得很低,并且把 动量梯度下降中 的只记录上次 梯度改为 记录之前全部梯度
lr = 0.0000001 grad_w = 0.9 * w0 + grad_w w.sub_(lr * grad_w) w0 = grad_w ### 计之前全部 grad_b = 0.9 * b0 + grad_b b.sub_(lr * grad_b) b0 = grad_b
其他不变,对比下 SGD 与动量梯度的收敛性
左边 SGD, 右边 动量梯度下降