前言

本文记录在学习pytorch的一些心得

手写线性回归之前我们需要了解一下pytorch的tensor中的requires_grad属性,当requires_grad=True时,它会追踪该张量的全部操作,也就为我们的梯度更新做出了前提

首先我们要知道什么是梯度:梯度也就是一个向量,导数+变化最快的方向(学习的前进方向)

而梯度一般也是和loss相结合使用的

判断模型的好坏就是看loss的大小,越小越好

loss=(YpredictYtrue)2(回归损失)loss=Ytruelog(Ypredict)(分类损失)\begin{aligned} loss & = (Y_{predict}-Y_{true})^2 &(回归损失) \\ loss & = Y_{true} \cdot log(Y_{predict}) &(分类损失) \end{aligned}

而当我们取得第一个loss的使用就要开始想怎么去减小loss的大小

大概可以看这个图

mark

随机选择一个起始点w0w_0,通过调整w0w_0,让loss函数取到最小值

mark

ww的更新方法

  1. 计算ww的梯度(导数)

w=f(w+0.000001)f(w0.000001)20.000001\begin{aligned} \nabla w = \frac{f(w+0.000001)-f(w-0.000001)}{2*0.000001} \end{aligned}

  1. 更新ww

    w=wαww = w - \alpha \nabla w

其中:

w<0,意味着W将增大w>0,意味着W将减小\nabla w<0 ,意味着W将增大\\ \nabla w>0 ,意味着W将减小

总结:梯度就是多元函数参数的变化趋势(参数学习的方向),只有一个自变量时称为导数

而在神经网络中我们求梯度的方式就是反向传播,具体原理(能力有限解释不清),但是用处就是通过反向传播推导,求得梯度值

下面我们准备写一下一个简单线性回归方程

我们假设定义一个y=3x+0.8的线性函数

import torch
import numpy as np
import matplotlib.pyplot as plt
#设置学习率
rate=0.01
#生成随机数据
x=torch.rand([500,1])
#线性回归函数,后面就是梯度计算就是为了到达和它基本一致的w和b
y_true=3*x+0.8
#生成w
w=torch.rand([1,1],requires_grad=True)
#生成b,b是一个标量
b=torch.tensor(0,requires_grad=True,dtype=torch.float32)
#同时我们迭代时要注意每次迭代前要将梯度清0,不然梯度值是一直相加的而这样的参数更新无实际意义
#迭代3000次
for i in range(3000):
#形成预测函数:y=w*x+b
y_predict=torch.matmul(x,w)+b
#计算均方误差
loss=(y_true-y_predict).pow(2).mean()
#梯度归0
if w.grad is not None:
w.grad.data.zero_()
if b.grad is not None:
b.grad.data.zero_()
#反向传播,找到梯度值
loss.backward()
#更新梯度参数
#w=w-a▽w
w.data=w.data-rate*w.grad
b.data=b.data-rate*b.grad
#打印更新后的参数值
if i%50==0:
print("w={},b={},loss={}".format(w.item(),b.item(),loss))

这样迭代3000次后,我们最后得到的w,b就已经十分接近3和0,8了

w=2.9634265899658203,b=0.8195856213569641,loss=0.00010962356464006007

这个时候我们进行简单的画图

plt.figure(figsize=(20,8))
plt.scatter(x.numpy().reshape(-1),y_true.numpy().reshape(-1))#原数据的散点图
y_predict=torch.matmul(x,w)+b
plt.plot(x.numpy().reshape(-1),y_predict.detach().numpy().reshape(-1))#现预测数据的直线图
plt.show()

如图所示:

mark

从图上看出预测的函数基本上和原函数拟合,这就是线性回归的意义,通过梯度下降法,找到梯度下降的方向,然后通过参数的迭代去找到w和b的参数形成预测函数,进行模型验证.

(注:x.backward(),此时便能够求出导数doutdx\frac{d out}{dx}后调用x.gard能够获取导数值也就是梯度值)

api介绍

  1. tensor.data:

    • 在tensor的require_grad=False,tensor.data和tensor等价

    • require_grad=True时,tensor.data仅仅是获取tensor中的数据

  2. tensor.numpy():

    • require_grad=True不能够直接转换,需要使用tensor.detach().numpy(),先抽取数据值在进行转换