Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >探讨pytorch中nn.Module与nn.autograd.Function的backward()函数

探讨pytorch中nn.Module与nn.autograd.Function的backward()函数

原创
作者头像
老潘
发布于 2018-05-23 10:04:37
发布于 2018-05-23 10:04:37
5.2K00
代码可运行
举报
运行总次数:0
代码可运行

前言

本文讲解基于pytorch0.4.0版本,如不清楚版本信息请看这里。backward()在pytorch中是一个经常出现的函数,我们一般会在更新loss的时候使用它,比如loss.backward()。通过对loss进行backward来实现从输出到输入的自动求梯度运算。但是这里的backward()如果追根溯源一下,或者说Go to definition一下,我们会发现,其实这个backward是来源于torch.autograd.backward

上面是官方的截图信息。但是这个函数我们可能不常见,那么这个函数在哪儿呢,就在Tensor这个类中(之前是在Variable类中,现在Variable和tensor合并)。而Tensor这个类中有一个函数:

backward()函数,这个函数返回的就是torch.autograd.backward()。也就是说,我们在训练中输入我们数据,然后经过一系列神经网络运算,最后计算loss,然后loss.backward()。这里的backward()归根绝地就是,上面说的这个函数。

正文

本文要说明的两个backward,一个nn.Module中的backward()和torch.autograd.Function中的backward(),其实有一个是假的backward()。

Fake Backward

很容易发现,我们在自己定义一个全新的网络层的时候会继承nn.Module,但是我们只需要实现__init__和forward()即可,不需要实现也没必要实现backward()函数,即使你实现了,你继承了nn.Module并且编写了一个backward()函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class ContentLoss(nn.Module):
   def __init__(self, target, weight):
        super(ContentLoss, self).__init__()
        # we 'detach' the target content from the tree used
        self.target = target.detach() * weight
        # to dynamically compute the gradient: this is a stated value,
        # not a variable. Otherwise the forward method of the criterion
       # will throw an error.
        self.weight = weight
        self.criterion = nn.MSELoss()
  def forward(self, input):
        self.loss = self.criterion(input * self.weight, self.target)
        self.output = input
        return self.output
  def backward(self, retain_graph=True):
        print('ContentLoss Backward works')
        self.loss.backward(retain_graph=retain_graph)
        return self.loss
    ...
    # 执行backward语句,具体代码请看下方的连接。
for sl in style_losses:
    style_score += sl.backward()
for cl in content_losses:
    content_score += cl.backward()

上面这段代码是利用pytorch实现风格迁移的自定义内容损失层,如果不懂看这里:传送门。如果正常操作,在实际运行中上面的backward函数并不会执行也不回打印执行信息。上面定义的backward称为fake backward函数,也就是假的backward函数,不会在pytorch的自动求梯度图中执行。但是为什么这么写,在pytorch官方0.3.0的教程中,可以在loss更新的时候,不使用loss.backward(),而是直接使用类中的.backward()方法然后返回loss即可。

但是在官方的0.4.0的风格迁移示例代码中,上面的代码发生了变化:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class ContentLoss(nn.Module):
     def __init__(self, target, ):
         super(ContentLoss, self).__init__()
         # we 'detach' the target content from the tree used
         # to dynamically compute the gradient: this is a stated value,
         # not a variable. Otherwise the forward method of the criterion
         # will throw an error.
         self.target = target.detach()
     def forward(self, input):
        self.loss = F.mse_loss(input, self.target)
        return input
...
# 执行代码,具体看官网的最新0.4.0风格迁移教程
for sl in style_losses:
    style_score += sl.loss
for cl in content_losses:
    content_score += cl.loss
loss = style_score + content_score
loss.backward()

我们发现没有backward函数了,而且使用的loss function发生了变化,从nn.MSELoss() ==> F.mse_loss()。

上面的这段代码没有定义backward函数,也没有执行retain_grad操作。为什么两个版本的不一样,其实第一个版本(0.3.0)完全没必要写backward函数,也没必要再单独执行backward()函数,因为最终目的都是一样的,都是要实现对loss的backward,在forward中进行操作的时候,其实我们已经对torch.autograd.Function的subclass进行了操作。也就是说在我们对tensor进行每一步操作运算的时候都会生成一个Function类的子类,里面定了好了forward和backward操作,最后连成计算图,所以没有必要多此一举。

说了这么多,既然不建议在nn.Module中定义backward。那我们能不能自己定义backward函数。

Real Backward

可以的。

通过继承torch.autograd.Function来定义。这一方面官方有教程,这里就不赘述。(下方是官方示例程序)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class MyReLU(torch.autograd.Function):
 """
 We can implement our own custom autograd Functions by subclassing
  torch.autograd.Function and implementing the forward and backward passes
  which operate on Tensors.
 """
  @staticmethod
  def forward(ctx, x):
    """
 In the forward pass we receive a context object and a Tensor containing the
 input; we must return a Tensor containing the output, and we can use the
    context object to cache objects for use in the backward pass.
 """
    ctx.save_for_backward(x)
    return x.clamp(min=0)
  def backward(ctx, grad_output):
    """
 In the backward pass we receive the context object and a Tensor containing
    the gradient of the loss with respect to the output produced during the
    forward pass. We can retrieve cached data from the context object, and must
    compute and return the gradient of the loss with respect to the input to the
    forward function.
 """
    x, = ctx.saved_tensors
    grad_x = grad_output.clone()
    grad_x[x < 0] = 0
 return grad_x

这里讲一下我们在什么情况下需要自己定义:

我们平常使用的nn.Module其实说白了就是一层包装(Contain),比如nn.Conv2继承了nn.Module,但是里面的核心函数是torch.nn.function.conv2d,为什么要包装下,原因很简单,为了方便,因为我们使用的卷积层是有参数的,这些参数是可以学习的(learnable parameters)。在这个包装类中我们通过torch.nn.parameter的Parameter类把参数进行包装然后传递给torch.nn.function中的函数进行计算,这样也就简化了我们的操作。

那么什么时候需要使用torch.autograd.Function去定义自己的层,在有些操作通过组合pytorch中已有的层实现不了的时候,比如你要实现一个新的梯度下降算法,那么就可以尝试着写这些东西。但是要注意,因为这个涉及到了底层,你需要forward和backward一起写,然后自己写对中间变量的操作,比如gradinput以及gradoutput。

比如这样写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class my_function(Function):
 def forward(self, input, parameters):
        self.saved_for_backward = [input, parameters]
        # output = [对输入和参数进行的操作,这里省略]
        return output
 def backward(self, grad_output):
        input, parameters = self.saved_for_backward
        # grad_input = [forward(input)关于 parameters 的导数] * grad_output
        return grad_input
# 然后通过定义一个Module来包装一下
class my_module(nn.Module):
      def __init__(self, ...):
         super(my_module, self).__init__()
         self.parameters = # 初始化一些参数
      def backward(self, input):
          output = my_function(input, self.parameters) # 在这里执行你之前定义的function!
          return output

这样你就可以通过自定义层然后包装,然后来使用了。

后记

对于这个包装,其实包不包装对于执行效率的影响几乎可以不计,对于没有学习参数的层,比如Relu(nn.ReLU vs F.relu),其实包不包装对于使用起来没什么区别。

文章来自Oldpan博客:https://cloud.tencent.com/developer/article/1149993

参考链接

https://discuss.pytorch.org/t/defining-backward-function-in-nn-module/5047

https://discuss.pytorch.org/t/whats-the-difference-between-torch-nn-functional-and-torch-nn/681

https://discuss.pytorch.org/t/difference-of-methods-between-torch-nn-and-functional/1076

https://discuss.pytorch.org/t/whats-the-difference-between-torch-nn-functional-and-torch-nn/681/4

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【小白学习PyTorch教程】四、基于nn.Module类实现线性回归模型
大多数情况下创建一个继承自 Pytorch 中的 nn.Module 的类,这样可以使用 Pytorch 提供的许多高级 API,而无需自己实现。
润森
2022/08/18
3990
【小白学习PyTorch教程】四、基于nn.Module类实现线性回归模型
迁移学习
迁移学习 from __future__ import print_function import torch import torch.nn as nn from torch.autograd import Variable import torch.optim as optim from PIL import Image import matplotlib.pyplot as plt from torchvision.utils import save_image impo
sofu456
2019/07/09
6490
迁移学习
torch.autograd.Function 用法及注意事项
众所周知,作为深度学习框架之一的 PyTorch 和其他深度学习框架原理几乎完全一致,都有着自动求导机制,当然也可以说成是自动微分机制。有些时候,我们不想要它自带的求导机制,需要在它的基础之上做些扩展,这个时候我们只需借用 PyTorch 框架中的 Function 类就可以实现了。
不可言诉的深渊
2022/11/11
1.3K0
torch.autograd.Function 用法及注意事项
pytorch中autograd以及hook函数详解
有些公式为图片,如果这个页面加载不出来,请看这里:https://oldpan.me/archives/pytorch-autograd-hook
老潘
2018/05/14
3.4K4
pytorch中autograd以及hook函数详解
三分钟教你如何PyTorch自定义反向传播
在前面两篇教程中,我们详细讲解了如何编写cuda算子,并用PyTorch进行调用,并且详细讲述了三种编译cuda算子的方式,具体可以看前面两篇:
godweiyang
2021/04/08
1.7K0
使用Pytorch实现风格迁移(Neural-Transfer)
本文主要向大家分享一个小编刚刚学习的神经网络应用的实例:风格迁移(Neural-Transfer)。这是一个由 Leon A. Gatys,Alexander S. Ecker和Matthias Bethge提出的算法。通过这个算法,我们可以用一种新的风格对指定图片进行重构,更通俗一点即:风格图片+内容图片=输出图片,即:
用户1621951
2021/09/02
5K0
使用 PyTorch 进行 风格迁移(Neural-Transfer)
本教程主要讲解如何实现由 Leon A. Gatys,Alexander S. Ecker和Matthias Bethge提出的Neural-Style 算法。Neural-Style 或者叫 Neural-Transfer,可以让你使用一种新的风格将指定的图片进行重构。 这个算法使用三张图片,一张输入图片,一张内容图片和一张风格图片,并将输入的图片变得与内容图片相似,且拥有风格图片的优美风格。
磐创AI
2019/09/24
8250
使用 PyTorch 进行 风格迁移(Neural-Transfer)
pytorch学习笔记(七):pytorch hook 和 关于pytorch backward过程的理解
ke1th
2018/01/02
3.5K0
PyTorch 60分钟入门系列之神经网络
前面的学习大致了解了autograd,nn依赖于autograd来定义模型并进行求导。一个nn.Module包含多个神经网络层,以及一个forward(input)方法来返回output。
AI异构
2020/07/29
4700
PyTorch 60分钟入门系列之神经网络
【深度学习】翻译:60分钟入门PyTorch(三)——神经网络
原文翻译自:Deep Learning with PyTorch: A 60 Minute Blitz
黄博的机器学习圈子
2021/02/12
7370
Pytorch 学习笔记之自定义 Module
本文介绍了如何使用 PyTorch 实现自定义循环神经网络(RNN)。首先介绍了如何定义一个自定义的 RNN 模块,然后通过一个简单的例子展示了如何使用自定义的 RNN 模块构建一个循环神经网络。在例子中,使用 PyTorch 提供的类实现了一个基本的 RNN,该类可以自动求导,并能够处理任意长度的序列。最后,介绍了如何使用 PyTorch 构建更复杂的循环神经网络。
丁科
2017/05/05
7.3K1
Pytorch 学习笔记之自定义 Module
pytorch中retain_graph参数的作用
在pytorch神经网络迁移的官方教程中有这样一个损失层函数(具体看这里提供0.3.0版中文链接:https://oldpan.me/archives/pytorch-neural-transfer)。
老潘
2018/06/21
4.5K0
pytorch中retain_graph参数的作用
最新翻译的官方 PyTorch 简易入门教程
https://github.com/fengdu78/machine_learning_beginner/tree/master/PyTorch_beginner
用户1737318
2019/11/19
1.5K0
最新翻译的官方 PyTorch 简易入门教程
PyTorch 2.2 中文官方教程(十一)
PyTorch C++ 前端是 PyTorch 机器学习框架的纯 C++ 接口。虽然 PyTorch 的主要接口自然是 Python,但这个 Python API 坐落在一个庞大的 C++ 代码库之上,提供了基础数据结构和功能,如张量和自动微分。C++ 前端暴露了一个纯 C++11 API,扩展了这个底层 C++ 代码库,提供了用于机器学习训练和推断所需的工具。这包括一个内置的常见神经网络建模组件集合;一个 API 用于扩展此集合以添加自定义模块;一个流行的优化算法库,如随机梯度下降;一个并行数据加载器,具有定义和加载数据集的 API;序列化例程等。
ApacheCN_飞龙
2024/02/05
9730
PyTorch 2.2 中文官方教程(十一)
手把手教你由TensorFlow上手PyTorch(附代码)
来源:机器之心 作者:Illarion Khlestov 本文为你解读PyTorch 的易用性。 当我第一次尝试学习 PyTorch 时,没几天就放弃了。和 TensorFlow 相比,我很难弄清
数据派THU
2018/03/22
2.1K0
手把手教你由TensorFlow上手PyTorch(附代码)
[源码解析] PyTorch 流水线并行实现 (6)--并行计算
前几篇文章我们介绍了 PyTorch 流水线并行的基本知识,自动平衡机制和切分数据,本文我们结合论文内容来看看如何实现流水线。
罗西的思考
2021/10/13
1.6K0
利用pytorch实现神经网络风格迁移Neural Transfer
载入图像输入大小无要求,最终会被剪裁到相同大小,这是因为神经网络设计了一个特定的输入大小,因此内容图像和风格图像必须大小一致。
老潘
2018/06/19
1.1K0
利用pytorch实现神经网络风格迁移Neural Transfer
torch.autograd.Function
对Function的直观理解Function与Module的差异与应用场景写一个简单的ReLU Function1.对Function的直观理解在之前的介绍中,我们知道,Pytorch是利用Variable与Function来构建计算图的。回顾下Variable,Variable就像是计算图中的节点,保存计算结果(包括前向传播的激活值,反向传播的梯度),而Function就像计算图中的边,实现Variable的计算,并输出新的Variable。Function简单说就是对Variable的运算,如加减乘除,
狼啸风云
2020/04/08
1.4K0
浅谈Pytorch与Torch的关系
Pytorch发布已经有一段时间了,我们在使用中也发现了其独特的动态图设计,让我们可以高效地进行神经网络的构造、实现我们的想法。那么Pytorch是怎么来的,追根溯源,pytorch可以说是torch的python版,然后增加了很多新的特性,那么pytorch和torch的具体区别是什么,这篇文章大致对两者进行一下简要分析,有一个宏观的了解。
老潘
2018/06/04
55.1K0
浅谈Pytorch与Torch的关系
PyTorch 源码解读之 torch.autograd
来源 | https://zhuanlan.zhihu.com/p/321449610
磐创AI
2021/02/23
1.9K0
PyTorch 源码解读之 torch.autograd
推荐阅读
相关推荐
【小白学习PyTorch教程】四、基于nn.Module类实现线性回归模型
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验