来源于pytorch的官方学习资料的总结
y = [0.5, 14.0, 15.0, 28.0, 11.0, 8.0, 3.0, -4.0, 6.0, 13.0, 21.0]
x = [35.7, 55.9, 58.2, 81.9, 56.3, 48.9, 33.9, 21.8, 48.4, 60.4, 68.4]
现在我们有十个点,横纵坐标如上所示,再图中可以表示为:
那我们要做的就是 预测出 a 和 b 去生成一条直线。无限的拟合这十个点。
也就是 预测出 y = ax + b 中的 a 和 b
我们可以通过x 的输出来自动形成一个 a, b 生成一个我们预测出的 y’
这个 y’ 肯定和 实际的结果 y 有很大的差距。我们把这个差距定义为损失函数loss:
L = (y - y')**2
这个损失函数是一个二次方程,可以画出路线图如下所示:
那么梯度也就是倒数,关于 a 和 b 的倒数:
此时 loss 可以写成
L = (y - (ax+b))**2
这个loss 中有两个变量,我们可以求两个偏导,如下图所示:
L 关于 a 的偏导叫做a的梯度(Ga),L关于b的偏导叫做b的梯度(Gb)。
我们的梯度下降法就是根据这个梯度的值来更新 a 和 b 的。
那么怎么根据梯度来更新 a 和 b 的值呢?
a = a - Ga
b = b - Gb
我们只需要很简单的减法就可以实现根据梯度来更新 a 和 b,当梯度大于0的时候,我们需要减小权值降低loss,反之相反。
那么我们要根据这个梯度怎样的进行学习呢,我们更新的过程应该是缓慢的,当梯度过大的时候我们需要其他的方法来控制我们的更新速度,这个时候我们就引入了learning rate。
a = a - Ga * learning rate
b = b - Gb * learning rate
学习率决定了我们每次更新的速度。每一次迭代我们都可以根据梯度更新权值,经过几千次的更新迭代后,我们会得到如下图所示的一条拟合于这十个点的线。
pytorch的代码如下:
import torch
import numpy
from matplotlib import pyplot as plt
t_c = [0.5, 14.0, 15.0, 28.0, 11.0, 8.0, 3.0, -4.0, 6.0, 13.0, 21.0]
t_u = [35.7, 55.9, 58.2, 81.9, 56.3, 48.9, 33.9, 21.8, 48.4, 60.4, 68.4]
t_c = torch.tensor(t_c)
t_u = torch.tensor(t_u)
# t_c = w * t_u + b
"""
predicted temperatures t_p/ actual measurements t_c
loss :
1. |t_p - t_c|
2. (t_p - t_c)^2
"""
def model(t_u, w, b):
return w * t_u + b
def loss_fn(t_p, t_c):
squared_diffs = (t_p - t_c)**2
return squared_diffs.mean()
w = torch.ones(1)
b = torch.zeros(1)
t_p = model(t_u, w, b)
loss = loss_fn(t_p, t_c) # tensor(1763.8846)
delta = 0.1
loss_rate_of_change_w = \
(loss_fn(model(t_u, w+delta, b), t_c) -
loss_fn(model(t_u, w-delta, b), t_c)) / (2.0 * delta)
"""
this code is saying that in a small neighborhood of the current values of w and b,
a unit increase in w leads to do some change in the loss.If the change is negative ,
you need to increase w to minimize the loss, whereas if the change is positive,you
need to decrease w.
"""
"""
you should scale the rate of change by a typically small factor, this scaling factor
has many names, the one used in machine learning is learning_rate.
"""
learning_rate = 1e-2
w = w - learning_rate * loss_rate_of_change_w
# we can do the same with b:
loss_rate_of_change_b = \
(loss_fn(model(t_u, w, b+delta), t_c) -
loss_fn(model(t_u, w, b-delta), t_c)) / (2.0 * delta)
b = b - learning_rate * loss_rate_of_change_b
def loss_fn(t_p, t_c):
squared_diffs = (t_p - t_c) ** 2
return squared_diffs.mean()
def dloss_fn(t_p, t_c):
dsq_diffs = 2 * (t_p - t_c)
return dsq_diffs
def model(t_u, w, b):
return w * t_u + b
def dmodel_dw(t_u, w, b):
return t_u
def dmodel_db(t_u, w, b):
return 1.0
def grad_fn(t_u, t_c, t_p, w, b):
dloss_dw = dloss_fn(t_p, t_c) * dmodel_dw(t_u, w, b)
dloss_db = dloss_fn(t_p, t_c) * dmodel_db(t_u, w, b)
return torch.stack([dloss_dw.mean(), dloss_db.mean()])
def training_loop(n_epochs, learning_rate, params, t_u, t_c):
for epoch in range(1, n_epochs+1):
w, b = params
t_p = model(t_u, w, b)
loss = loss_fn(t_p, t_c)
grad = grad_fn(t_u, t_c, t_p, w, b)
params = params - learning_rate * grad
print('params : ')
print(params)
print('grads : ')
print(grad)
print('Epoch %d, Loss %f' % (epoch, float(loss)))
return params
# normalize input got the same result
# t_un = t_u/t_u.sum() * 10 # Epoch 5000, Loss 2.937128
t_un = 0.1 * t_u # Epoch 5000, Loss 2.927648
params = training_loop(
n_epochs= 5000,
learning_rate=1e-2,
params=torch.tensor([1.0, 0.0]),
t_u=t_un,
t_c=t_c)
t_p = model(t_un, *params)
print(t_p.detach())
fig = plt.figure(dpi=70)
plt.xlabel('x_label')
plt.ylabel('y_label')
# plt.plot(t_u.numpy(), t_p.detach().numpy())
plt.plot(t_u.numpy(), t_c.numpy(), 'o')
plt.show()