• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

Pytorch自动求导函数详解流程以及与TensorFlow搭建网络的对比

python 搞代码 4年前 (2022-01-09) 21次浏览 已收录 0个评论
文章目录[隐藏]

一、定义新的自动求导函数

在底层,每个原始的自动求导运算实际上是两个在Tensor上运行的函数。其中,forward函数计算从输入Tensor获得的输出Tensors。而backward函数接收输出,Tensors对于某个标量值得梯度,并且计算输入Tensors相对于该相同标量值得梯度。
在Pytorch中,可以容易地通过定义torch.autograd.Function的子类实现forward和backward函数,来定义自动求导函数。之后就可以使用这个新的自动梯度运算符了。我们可以通过构造一个实例并调用函数,传入包含输入数据的tensor调用它,这样来使用新的自动求导运算
以下例子,自定义一个自动求导函数展示ReLU的非线性,并调用它实现两层网络,如上一节

import torch
class myrelu(torch.autograd.Function):#自定义子类
    # 通过建立torch.autograd的子类来实现自定义的autograd函数,并完成张量的正向和反向传播
    @staticmethod
    def forward(ctx, x):
        # 在正向传播中,接受到一个上下文对象和一个包含输入的张量,必须返回一个包含输出的张量,可以使用上下文对象来缓存对象,以便在反向传播中使用
        ctx.save_for_backward(x)
        return x.clamp(min=0)
    @staticmethod
    def backward(ctx, grad_output):
        """
        在反向传播中,我们接收到上下文对象和一个张量,
        其包含了相对于正向传播过程中产生的输出的损失的梯度。
        我们可以从上下文对象中检索缓存的数据,
        并且必须计算并返回与正向传播的输入相关的损失的梯度。
        """
        x, = ctx.saved_tensors
        grad_x = grad_output.clone()
        grad_x[x < 0] = 0
        return grad_x

调用自定义的类实现两层网络

#%%
device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# n是批量大小,d_in是输入维度
# h是隐藏的维度,d_out是输出维度
n,d_in,h,d_out=64,1000,100,10
# 创建随机输入和输出数据,requires_grad默认设置为False,表示不需要后期微分操作
x=torch.randn(n,d_in,device=device)
y=torch.randn(n,d_out,device=device)
# 随机初始化权重,requires_grad默认设置为True,表示想要计算其微分
w1=torch.randn(d_in,h,device=device,requires_grad=True)
w2=torch.randn(h,d_out,device=device,requires_grad=True)

learning_rate=1e-6
for i in range(500):
    #前向传播,使用tensor上的操作计算预测值y
  #调用自定义的myrelu.apply函数
    y_pred=m<div style="color:transparent">本文来源gaodai^.ma#com搞#代!码网</div>yrelu.apply(x.mm(w1)).mm(w2)
       
    
    #使用tensor中的操作计算损失值,loss.item()得到loss这个张量对应的数值
    loss=(y_pred-y).pow(2).sum()
    print(i,loss.item())
    
    #使用autograd计算反向传播,这个调用将计算loss对所有的requires_grad=True的tensor梯度,
    #调用之后,w1.grad和w2.grad将分别是loss对w1和w2的梯度张量
    loss.backward()
    #使用梯度下降更新权重,只想对w1和w2的值进行原地改变:不想更新构建计算图
    #所以使用torch.no_grad()阻止pytorch更新构建计算图
    with torch.no_grad():
        w1-=learning_rate*w1.grad
        w2-=learning_rate*w2.grad
        #反向传播后手动将梯度置零
        w1.grad.zero_()
        w2.grad.zero_() 

运行结果

二、Pytorch 和 TensorFlow对比

  • PyTorch自动求导看似非常像TensorFlow:这两个框架中,都定义了计算图,使用自动微分来计算梯度,两者最大的不同是TensorFlow的计算图是静态的,而PyTorch使用的是动态的计算图。
  • 在TensorFlow中,定义计算图一次,然后重复执行相同的图,可能会提供不同的输入数据,而在PyTorch中,每一个前向通道定义一个新的计算图。
  • **静态图的好处在于可以预先对图进行优化。**如:一个框架可以融合一些图的运算来提升效率,或者产生一个策略来将图分布到多个GPU或机器上。但是如果重复使用相同的图,那么重复运行同一个图时,前期潜在的代价高昂的预先优化的消耗就会被分摊。
  • 静态图和动态图的一个区别就是控制流。对于一些模型,对每个数据点执行不同的计算。如:一个递归神经网络可能对于每个数据点执行不同的时间步数,这个展开可以作为一个循环来实现。对于一个静态图,循环结构要作为图的一部分。因此,TensorFlow提供了运算符将循环嵌入到图当中。对于动态图来说,情况更加简单:为每个例子即时创建图,使用普通的命令式控制流来为每个输入执行不同的计算。

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Pytorch自动求导函数详解流程以及与TensorFlow搭建网络的对比
喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址