(一)pytorch学习笔记(线性回归 梯度下降)

机器学习中梯度下降法的简单例子

来源于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]

现在我们有十个点,横纵坐标如上所示,再图中可以表示为:
(一)pytorch学习笔记(线性回归 梯度下降)_第1张图片
那我们要做的就是 预测出 a 和 b 去生成一条直线。无限的拟合这十个点。
也就是 预测出 y = ax + b 中的 a 和 b
我们可以通过x 的输出来自动形成一个 a, b 生成一个我们预测出的 y’
这个 y’ 肯定和 实际的结果 y 有很大的差距。我们把这个差距定义为损失函数loss:
L = (y - y')**2
这个损失函数是一个二次方程,可以画出路线图如下所示:
(一)pytorch学习笔记(线性回归 梯度下降)_第2张图片
那么梯度也就是倒数,关于 a 和 b 的倒数:
此时 loss 可以写成

L = (y - (ax+b))**2

这个loss 中有两个变量,我们可以求两个偏导,如下图所示:
(一)pytorch学习笔记(线性回归 梯度下降)_第3张图片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学习笔记(线性回归 梯度下降)_第4张图片
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()

你可能感兴趣的:(pytorch,笔记)