首页 > 其他分享 >几个例子帮你梳理PyTorch知识点(张量、autograd)

几个例子帮你梳理PyTorch知识点(张量、autograd)

时间:2022-12-23 20:31:08浏览次数:56  
标签:知识点 autograd torch item PyTorch dtype device grad

因为我最近想学Pytorch lightning,重构一下之前的代码,所以回来梳理一下Pytorch的语法,好进行下一步学习,所以从头重新回顾一下Pytorch。这个文章是通过几个简单例子帮大家回顾一下Pytorch一些重点基础概念。

Pytorch有两个重要的特征:

  • 使用n维张量进行运算,可以使用GPU加速计算。
  • 使用自动微分构建、训练神经网络

从$sin(x)$开始

Tensor和Numpy的用法差不多,但是Tensor可是使用进行加速计算,这比CPU计算要快50倍甚至更多。

更多区别可以看这个:PyTorch的Tensor这么简单,你还用不明白吗? - 掘金 (juejin.cn)

我们知道,在基础的回归问题中:给定一些数据,符合一定的分布,我们要建立一个神经网络去拟合这个分布,神经网络学习出来的表达式就作为我们数据分布的表达式。

这里我们用一个三次多项式$y=a+bx+cx^2+dx^3$来拟合$sin(x)$,训练过程使用随机梯度下降进行训练,通过计算最小化预测值和真实值之间的欧氏距离来拟合随机数据。

代码解释见代码中的注释部分。

import torch
import math

dtype = torch.float
device = torch.device("cpu")


# 下边这行代码可以用也可以不用,注释掉就是在CPU上运行
# device = torch.device("cuda:0") 

# 创建输入输出数据,这里是x和y代表[-π,π]之间的sin(x)的值
x = torch.linspace(-math.pi, math.pi, 2000, device=device, dtype=dtype)
y = torch.sin(x)

#随机初始化权重
a = torch.randn((), device=device, dtype=dtype)
b = torch.randn((), device=device, dtype=dtype)
c = torch.randn((), device=device, dtype=dtype)
d = torch.randn((), device=device, dtype=dtype)

learning_rate = 1e-6
for t in range(2000):
    # 前向过程,计算y的预测值
    y_pred = a + b * x + c * x ** 2 + d * x ** 3

    # 计算预测值和真实值的loss
    loss = (y_pred - y).pow(2).sum().item()
    if t % 100 == 99:
        print(t, loss)

    # 反向过程计算 a, b, c, d 关于 loss 的梯度
    grad_y_pred = 2.0 * (y_pred - y)
    grad_a = grad_y_pred.sum()
    grad_b = (grad_y_pred * x).sum()
    grad_c = (grad_y_pred * x ** 2).sum()
    grad_d = (grad_y_pred * x ** 3).sum()

    # 使用梯度下降更新参数
    a -= learning_rate * grad_a
    b -= learning_rate * grad_b
    c -= learning_rate * grad_c
    d -= learning_rate * grad_d


print(f'Result: y = {a.item()} + {b.item()} x + {c.item()} x^2 + {d.item()} x^3')

结果如下:

image.png

如果换成勒让德多项式呢?

之前讲过深扒torch.autograd原理 - 掘金 (juejin.cn)

这里我们再浅浅简述一下autograd。

在上边的例子里,我们是手动实现了神经网络的前向和反向传播过程,因为这只是一个简单的两层网络,所以现实来也不是很困难,但是放对于一些大的复杂网络,要手动实现整个前向和反向过程就是非常困难的事情了。

现在我们可以使用pytorch提供autograd包去自动求导,自动计算神经网络的反向过程。当我们使用autograd的时候,神经网络前向过程就是定义一个计算图,计算图上的节点都是张量,边是从输入到输出的计算函数。用计算图进行反向传播可以轻松计算梯度。

虽然听起来很复杂,但是用起来很简单。每个张量都代表计算图上的一个节点,如果x是一个张量,并且你设置好了x.requires_grad=True,那x.grad就是另一个存储x关于某些标量的梯度的张量。

然后我们继续使用三次多项式来拟合我们的sin(x),但是现在我们就可以不用手动实现反向传播的过程了。

import torch
import math
 
dtype = torch.float
device = torch.device("cpu")

# 下边这行代码可以用也可以不用,注释掉就是在CPU上运行
# device = torch.device("cuda:0") 
 
# 创建输入输出数据,这里是x和y代表[-π,π]之间的sin(x)的值
x = torch.linspace(-math.pi, math.pi, 2000, device=device, dtype=dtype)
y = torch.sin(x)
 
# 随机初始化权重
# 注意这里我们设置了requires_grad=True,让autograd自动跟踪计算图的梯度计算
a = torch.randn((), device=device, dtype=dtype, requires_grad=True)
b = torch.randn((), device=device, dtype=dtype, requires_grad=True)
c = torch.randn((), device=device, dtype=dtype, requires_grad=True)
d = torch.randn((), device=device, dtype=dtype, requires_grad=True)
 
learning_rate = 1e-6
for t in range(2000):
    
    # 前向过程,计算y的预测值
    y_pred = a + b * x + c * x ** 2 + d * x ** 3

    # 计算预测值和真实值的loss
    loss = (y_pred - y).pow(2).sum()
    if t % 100 == 99:
        print(t, loss.item())
 
    # 使用autograd计算反向过程,调用之后会计算所有设置了requires_grad=True的张量的梯度
    # 调用之后 a.grad, b.grad. c.grad  d.grad 会存储 abcd关于loss的梯度
    loss.backward()
 
    # 使用梯度下降更新参数
    # 因为权重设置了requires_grad=True,但是在梯度更新这里我们不需要跟踪梯度,所以加上with torch.no_grad()
    with torch.no_grad():
        a -= learning_rate * a.grad
        b -= learning_rate * b.grad
        c -= learning_rate * c.grad
        d -= learning_rate * d.grad
 
        # 更新之后将气度清零,以便下一轮运算,不清零的话它会一直累计
        a.grad = None
        b.grad = None
        c.grad = None
        d.grad = None
 
print(f'Result: y = {a.item()} + {b.item()} x + {c.item()} x^2 + {d.item()} x^3')

image.png

在pytorch这种autograd的情况下,每个基础的的autograd操作只是两个作用于张量的方法。

  • forward:由输入张量计算输出张量
  • backward:接收输出张量相对于某个标量值的梯度,并计算输入张量相对于相同标量值的梯度。

在pytorch中我们可以定义我们自己的autograd操作,你只需要实现一个torch.autograd.Function的子类,写好forwardbackward函数即可。构造好新的autograd之后我们就可以像调用其他函数一样调用它,将输入张量传递进去即可。

比如我们不用$y=a+bx+cx^2+dx^3$了,改成一个三次勒让德多项式(Legendre polynomial),形式为$y = a+bP_3(c+dx)$,其中$P_3(x) = \frac 1 2 (5x^3-3x)$。

import torch
import math
 
class LegendrePolynomial3(torch.autograd.Function):
    def forward(ctx, input):
        
        # 在前向过程中我们接受一个输入张量,并返回一个输出张量
        # ctx是一个上下文对象,用于存储反向过程的内容
        # 你可以用save_for_backward方法缓存任意在反向计算过程中要用的对象。
        
        ctx.save_for_backward(input)
        return 0.5 * (5 * input ** 3 - 3 * input)

    def backward(ctx, grad_output):
        # 在反向过程中,我们接受一个张量包含了损失关于输出的梯度,我们需要计算损失关于输入的梯度。
        input, = ctx.saved_tensors
        return grad_output * 1.5 * (5 * input ** 2 - 1)
 
        
dtype = torch.float
device = torch.device("cpu")

# 下边这行代码可以用也可以不用,注释掉就是在CPU上运行
# device = torch.device("cuda:0") 

# 创建输入输出数据,这里是x和y代表[-π,π]之间的sin(x)的值
x = torch.linspace(-math.pi, math.pi, 2000, device=device, dtype=dtype)
y = torch.sin(x)

# 随机初始化权重
# 注意这里我们设置了requires_grad=True,让autograd自动跟踪计算图的梯度计算
a = torch.full((), 0.0, device=device, dtype=dtype, requires_grad=True)
b = torch.full((), -1.0, device=device, dtype=dtype, requires_grad=True)
c = torch.full((), 0.0, device=device, dtype=dtype, requires_grad=True)
d = torch.full((), 0.3, device=device, dtype=dtype, requires_grad=True)
 
learning_rate = 5e-6
for t in range(2000):
    # 我们给我们自定义的autograd起个名叫P3,然后用Function.apply方法调用
    P3 = LegendrePolynomial3.apply
 
    # 前向过程计算y,用的是我们自定义的P3的autograd
    y_pred = a + b * P3(c + d * x)
 
    # 计算并输出loss
    loss = (y_pred - y).pow(2).sum()
    if t % 100 == 99:
        print(t, loss.item())
 
    # 使用autograd计算反向过程
    loss.backward()
 
    # 使用梯度下降更新权重
    with torch.no_grad():
        a -= learning_rate * a.grad
        b -= learning_rate * b.grad
        c -= learning_rate * c.grad
        d -= learning_rate * d.grad
 
        # 在下一轮更新之前将梯度清零,否则会一直累计
        a.grad = None
        b.grad = None
        c.grad = None
        d.grad = None
 
print(f'Result: y = {a.item()} + {b.item()} * P3({c.item()} + {d.item()} x)')

image.png

标签:知识点,autograd,torch,item,PyTorch,dtype,device,grad
From: https://blog.51cto.com/Lolitann/5966309

相关文章

  • 数据库事务的一些知识点
    在日常开发中处理好数据库事务问题是相当重要的,下面以MySQL、Spring为例整理了一些数据库事务的知识点。1.事务属性事务属性(特性、原则)是指事务ACID属性,它们分别是:原......
  • PyTorch复现ResNet学习笔记
    PyTorch复现ResNet学习笔记一篇简单的学习笔记,实现五类花分类,这里只介绍复现的一些细节如果想了解更多有关网络的细节,请去看论文《DeepResidualLearningforImageRec......
  • PyTorch 深度学习实践第八讲(Dataset and DataLoader)
    上课代码importtorchimportnumpyasnpfromtorch.utils.dataimportDataset#Data是一个抽先类fromtorch.utils.dataimportDataLoaderclassDiabetesDataset(Datas......
  • pytorch train demo
    一、用pytorch实现lenet类似网络的训练1.网络结构2.代码mporttorch......
  • PyTorch 深度学习实践第七讲(处理多维特征的输入)
    基本原理降维基本原理备注:读文档和基本架构能力很重要,具备此技能能够拥有强的泛化能力上课代码importtorchimportnumpyasnpimporttorch.nn.functionalasFimportmatp......
  • PyTorch 深度学习实践第六讲(逻辑回归)
    LogisticFunctionSigmoidFunctions交叉熵备注:BCE越小分布越接近,越好深度学习基本框架上课代码importtorchimportnumpyasnpimporttorch.nn.functionalasFimportmat......
  • JavaScript Date 对象知识点复习
    复制单个代码控制台运行看结果从Date对象返回一个月中的某一天(1~31)。console.log("newDate().getDate()"-----------,newDate().getDate())从Date对象返......
  • 用一个图像分类实例拿捏Pytorch使用方法
    写在最前边这篇文章要写的内容看封面,就是要用一篇文章讲解一下,怎么用Fashion-MNIST数据集,我们自己建一个神经网络,训练好之后用它做图片分类。importtorchfromtorchim......
  • PyTorch 深度学习实践第五讲(用PyTorch实现线性回归)
    基本步骤上课代码importtorchx_data=torch.Tensor([[1.0],[2.0],[3.0]])y_data=torch.Tensor([[2.0],[4.0],[6.0]])#x与y必须是矩阵classLinearModel(torch.n......
  • PyTorch 深度学习实践第四讲(反向传播)
    简单回顾关于w的更新神经网络原理备注:最后加入惩罚项反向传播原理备注:后期对权重进行更新,先进行前馈过程,再反向相应代码importtorchx_data=[1.0,2.0,3.0]y_data=[2.0,4......