刘二大人pytorch第三讲 梯度下降
第二讲的思想是,已知给出的数据为线性分布(即可以使用y=wx去拟合),使用穷举法列出一个取值区间内所有的w值,根据给出的训练数据,计算每个w下的loss值(使用均方误差计算损失),取使得loss最小的w为为最优点。但是穷举思想在小区间、简单参数的情况下可以实现,如果区间太大、或者权重参数过多时就没法计算了。分治思想也同样不适用于目标函数的求优,因为损失函数是一个不规则的函数,分治的思想容易错过最优点。
梯度下降的思想:随机给定w的初始值,计算损失函数在该w下的偏导(梯度),更新w,使得loss(目标函数)每次朝着梯度下降最快的方向往前走,直到得到最优解(使得loss最小的值)。
(实质上就是给定w值,计算给定的w下的损失函数值,找到使得损失函数最小的那个w为最优解。只不过上一讲是穷举给出w,这里使用梯度下降思想寻找最优w)
梯度下降
- 损失函数:
- 计算梯度:
- 更新权重:
其中, 表示学习率
代码实现
import numpy as np
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_pred, 即公式里的yhead(预测值)
def forward(x):
'''
返回预测值
:param x: 输入
:return: 网络的输出值
'''
return x*w # y_pred
# 计算cost 损失函数值
def cost(xs, ys):
"""
返回的是损失值
Args:
xs (数组): _输入数据_
ys (数组): _对应的真实值_
Returns:
_float_: _预测值与真实值的均方误差值_
"""
cost = 0
for x, y in zip(xs,ys):
y_pred = forward(x)
cost += (y_pred - y)**2
return cost / len(xs)
# 计算梯度
def gradient(xs,ys):
grad = 0
for x, y in zip(xs,ys):
grad = grad + 2*x*(x*w - y)
return grad / len(xs)
epoch_list = []
cost_list = []
for epoch in range(100):
"""
遍历100个epoch
"""
cost_val = cost(x_data, y_data) # 计算损失值
grad_val = gradient(x_data, y_data) # 计算梯度值
w-= 0.01 * grad_val # 更新权重w
print('epoch:', epoch, 'w=', w, 'loss=', cost_val) # 输出每轮结果
epoch_list.append(epoch)
cost_list.append(cost_val)
plt.plot(epoch_list,cost_list) # 画出loss随着不断训练迭代变化的函数图
plt.ylabel('Loss')
plt.xlabel('epoch')
plt.show()
# 给出一个测试数据4,使用最终的w来预测输入为4时的y值
print('Predict (after traing)', 4, forward(4))
输出结果:
epoch: 0 w= 1.0933333333333333 loss= 4.666666666666667
epoch: 1 w= 1.1779555555555554 loss= 3.8362074074074086
...
...
epoch: 98 w= 1.9999387202080534 loss= 2.131797981222471e-08
epoch: 99 w= 1.9999444396553017 loss= 1.752432687141379e-08
Predict (after traing) 4 7.999777758621207
由上图可见,随着迭代训练次数增多,模型收敛(loss趋近于一个最小值,基本不再上升)。(注:如果发散,最常见的一个原因可能是学习率取得太大)
随机梯度下降
代码实现:
import matplotlib.pyplot as plt
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w = 1.0
def forward(x):
return x*w
# 计算损失
def loss(x, y):
y_pred = forward(x)
return (y_pred - y)**2
# 计算sgd
def gradient(x, y):
return 2*x*(x*w - y)
epoch_list = []
loss_list = []
print('predict (before training)', 4, forward(4))
for epoch in range(100):
for x,y in zip(x_data, y_data):
grad = gradient(x,y)
w = w - 0.01*grad
print("\tgrad:", x, y,grad)
l = loss(x,y)
print("progress:",epoch,"w=",w,"loss=",l)
epoch_list.append(epoch)
loss_list.append(l)
print('predict (after training)', 4, forward(4))
plt.plot(epoch_list,loss_list)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()