梯度的引入与思考
【问题1】为什么要引入梯度下降,梯度下降是用来解决什么问题的?
【思考】回忆一下在笔记02中我们是如何找到的w?对,是穷举!
我们是在[0.0,4.0]区间,每隔0.1取一个值,穷举了所有w的可能取值,根据w-loss图像得出结论:loss最小时,w=2。
在实际情况中,一方面我们很可能一开始就无法确定w的大致范围,进而导致没办法穷举w的值。另一方面,权重W也可能是多维的,一一穷举会很麻烦。所以我们就希望,可不可以让程序自己来寻找最合适的w值。
此时,就把求w值问题变成一个如何寻找w最小值问题。
【问题2】如何寻找最小w?
【思考】可通过下列步骤寻找w最小值:
①初始化w:先假定w取一个值,作为寻找的起始点。
②判断方向:根据梯度值,判断w应该往左走还是往右走可以找到w最小值(沿着梯度反方向,即为寻找最小值的方向)。
移动:移动的过程就是更新权重w的过程,每次朝着梯度反方向③小幅度移动。
④更新权重w:移动完成后,将当前w值作为最新权重值,更新公式如下图所示:
不断重复上述操作,当w快找到最小值点时,此时w-loss图像的梯度接近0(可以理解为曲线在接近w最小值点斜率接近0),此时cost对w的导数接近为0,在公式中w=w-α×0。此时得到的w即为所求的w。
【概念】梯度方向定义:函数上升的方向即为梯度的方向。
所以,梯度的反方向即为函数下降的方向(即:寻找LOSS最小值点的方向)
梯度下降寻找权重w最小值
1.导入数据集
PS:与之前代码相同
import matplotlib.pyplot as plt x_data = [1.0, 2.0, 3.0] y_data = [2.0, 4.0, 6.0]
2.定义模型
PS:与之前代码相同
def forward(x): return x * w
3.定义损失函数
PS:与之前代码相同
# 定义损失函数MSE # loss = (y_pred - y)² # loss_sum = += loss (对每个x=1.0,2.0,3.0,求loss后求和) # loss_sum / len(xs) 在对cost求均值 def cost(xs, ys): loss_sum = 0 for x, y in zip(xs, ys): y_pred = forward(x) # 计算预测值y loss_sum += (y_pred - y) ** 2 return loss_sum / len(xs)
4.定义梯度算法
y_pred预测值公式如下:
cost(w)损失函数公式如下:
gradient梯度公式如下:
gradient梯度关于权重w、初始值Xn和Yn的公式如下(由上述公式根据复合函数求导法则推导而来):
# 定义梯度计算方法 求cost(w)对w的偏导数 梯度也需要求和后求均值 def gradient(xs, ys): grad = 0 for x, y in zip(xs, ys): grad += 2 * x * (x * w - y) return grad / len(xs)
5.训练模型
for epoch in range(100): # 默认步长为1,epoch从0-99训练100次 cost_val = cost(x_data, y_data) # 计算均方损失MSE grad_val = gradient(x_data, y_data) # 计算梯度 w -= 0.01 * grad_val # 学习率lr等于0.01 # 使用梯度下降的方法更新权重 print(' Epoch:', epoch, ' w=', w, ' loss=', cost_val) # 每训练一次,打印一下权重w和损失loss的值
6.全部代码
import matplotlib.pyplot as plt x_data = [1.0, 2.0, 3.0] y_data = [2.0, 4.0, 6.0] # 定义的初始权重值 w = 1.0 # 定义模型y=wx def forward(x): return x * w # 定义损失函数MSE # loss = (y_pred - y)² # loss_sum = += loss (对每个x=1.0,2.0,3.0,求loss后求和) # loss_sum / len(xs) 在对cost求均值 def cost(xs, ys): loss_sum = 0 for x, y in zip(xs, ys): y_pred = forward(x) # 计算预测值y loss_sum += (y_pred - y) ** 2 return loss_sum / len(xs) # 定义梯度计算方法 求cost(w)对w的偏导数 梯度也需要求和后求均值 def gradient(xs, ys): grad = 0 for x, y in zip(xs, ys): grad += 2 * x * (x * w - y) return grad / len(xs) # 最终绘制图像的x epoch_list = [] cost_list = [] print('Predict (before training)', 4, forward(4)) for epoch in range(100): # 默认步长为1,epoch从0-99训练100次 cost_val = cost(x_data, y_data) # 计算均方损失MSE grad_val = gradient(x_data, y_data) # 计算梯度 w -= 0.01 * grad_val # 学习率lr等于0.01 # 使用梯度下降的方法更新权重 print(' Epoch:', epoch, ' w=', w, ' loss=', cost_val) epoch_list.append(epoch) # 收集当前是第几次训练 cost_list.append(cost_val) # 收集对应训练的损失值 print('Predict (after training)', 4, forward(4)) # 绘图 plt.plot(epoch_list, cost_list) plt.ylabel('cost') plt.xlabel('epoch') plt.show()
7.展示pytorch绘制的图像(epoch-loss)
从图中可以发现,当训练epoch次数增加的时候,损失值会越来越小。
此时打印4 和forward(4),就会得到forward(4)的值接近于8。所以权重w=y/x=2