pytorch学习笔记四

这篇博客介绍了如何使用PyTorch构建一个简单的线性回归模型,通过梯度下降法优化权重和偏置。文章详细展示了从定义模型、损失函数到计算梯度和迭代训练的全过程,并对输入数据进行了归一化处理,以确保模型的稳定训练。最终,通过可视化输出展示训练结果。
摘要由CSDN通过智能技术生成

pytorch学习笔记四————一个简单的学习模型

本次将尝试用微分和梯度下降法进行一个最基础的学习模型:线性回归
以下是两组数据

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是以摄氏度为单位的温度,而t_u是我们未知的单位,我们想搞清楚两组数据的关系
我们的未知数据可能遵循一个线性模型
于是利用线性模型进行验证:
t c = w × t u + b t_c=w\times t_u +b tc=w×tu+b
这里的w和b有两个专业的名字,分别称作权重和偏置

损失函数

有了参数,就需要对这些参数的正确性进行评估,而评估的方法函数就称作为损失函数,这里我们用目标与实际的差的平方来作为损失函数
l o s s = ( t p − t c ) 2 loss=(t_p-t_c)^2 loss=(tptc)2
注意这里的t_p是t_u推导出来的,而t_c则就是实际的t_c,与第一个公式里的t_c含义不太一样
用pytorch实现模型和损失函数就如下:

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()

减小损失

既然我们有了损失函数,所以我们肯定要想办法使得我们的损失函数尽可能的小,如果只靠感觉的话很有可能不准,所以为了能够定量的使其减小,我们采用导数来计算出损失函数在某个点的形状,此时再沿着导数下降,就太不会出现下降过多或者下降过慢的情况
为了能能够计算损失对一个参数的导数,我们可以采用链式法则,先计算损失对其输入输出的导数,再乘模型对参数的导数,如下:
∂ l o s s f n ∂ w = ∂ l o s s f n ∂ t p ⋅ ∂ t p ∂ w \frac{\partial loss_{f_n}}{\partial w}=\frac{\partial loss_{f_n}}{\partial t_p}\cdot \frac{\partial t_p}{\partial w} wlossfn=tplossfnwtp
所以则有以下的损失函数计算公式:

def dloss_fn(t_p,t_c):
    dsq_diffs=2*(t_p-t_c)/t_p.size(0)
    return dsq_diffs
def dmodel_dw(t_u,w,b):
    return t_u
def dmodel_db(t_u,w,b):
    return 1.0

这里有几个注意点,一个是dloss_fn的最后要除一个向量的长度,这是因为loss_fn返回的是平均值,而平均值的导数即是导数的平均值,因此求完导后得到一个矩阵,再对矩阵求平均值即可,再后面的链式求导数直接用sum()即可
由此我们得到最后的梯度计算公式

def grad_fn(t_u,t_c,t_p,w,b):
    dloss_dtp=dloss_fn(t_p,t_c)
    dloss_dw=dloss_dtp*dmodel_dw(t_u,w,b)
    dloss_db=dloss_dtp*dmodel_db(t_u,w,b)
    return torch.stack([dloss_dw.sum(),dloss_db.sum()])

注:torch.stack不是栈,而是拼接函数

迭代训练

既然已经获得了导数,那么我们只需要顺着导数进行迭代训练,使得损失函数最小即可达到我们的目标
代码如下:

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('Epoch %d,Loss %f' %(epoch,float(loss)))
        print('params:',params)
        print('Grad:',grad)
    return params

学习率learning rate是一个需要仔细调得参数,如果参数过大,则会导致它们的值来回波动,每次更新修正过度,它们的优化的过程则是不稳定的,而如果太小则会优化的太慢

归一化输入

大多数情况下,不同的参数的修正处于不同的比例空间下,在这种情况下,如果学习率过大,可以有效更新其中一个参数,而对于另一个参数来说,学习率就会变得非常的不稳定,而一个只适于另一个参数的学习率也不足以有效的改变前者
为了解决这个问题,用一个简单的方法:改变输入,而不是改变模型可以简单的改变学习率
我们将t_u乘0.1来获得一个更好的输入,如下

t_un=0.1*t_u
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)

在这调整完成后只需将相应的参数放缩到对应的比例即可完成训练

可视化输出

训练完成对其进行可视化输出即可,所有的代码参考如下:
附一张训练完成的图片:
在这里插入图片描述

import torch
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)

w=torch.ones(())
b=torch.zeros(())

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()

def dloss_fn(t_p,t_c):
    dsq_diffs=2*(t_p-t_c)/t_p.size(0)
    return dsq_diffs

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_dtp=dloss_fn(t_p,t_c)
    dloss_dw=dloss_dtp*dmodel_dw(t_u,w,b)
    dloss_db=dloss_dtp*dmodel_db(t_u,w,b)
    return torch.stack([dloss_dw.sum(),dloss_db.sum()])

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('Epoch %d,Loss %f' %(epoch,float(loss)))
        print('params:',params)
        print('Grad:',grad)
    return params
t_un=0.1*t_u
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)

from matplotlib import pyplot as plt
t_p=model(t_un,*params)
fig=plt.figure()
plt.xlabel("X")
plt.ylabel("Y")
plt.plot(t_u.numpy(),t_p.detach().numpy())
plt.plot(t_u.numpy(),t_c.numpy(),'o')
plt.show()

# loss=loss_fn(t_p,t_c)
# print(loss)
'''
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)
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)

w=w-learning_rate*loss_rate_of_change_w
b=b-learning_rate*loss_rate_of_change_b
'''
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值