基本数据Tensor可以保证完成前向传播,想要完成神经网络的训练,接下来还需要进行反向传播与梯度更新,而PyTorch提供了自动求导机制autograd,将前向传播的计算记录成计算图,自动完成求导。
训练神经网络—>调整权重w和b值(使网络达到最优)—>反向传播与梯度更新—>自动求导机制autograd—>计算图(autograd依赖计算图)
自动求导机制autograd记录了Tensor的操作,以便自动求导与反向传播



自动求导机制Autograd

可以通过requires_grad参数来创建支持自动求导机制的Tensor。
require_grad参数表示是否需要对该Tensor进行求导,默认为False;设置为True则需要求导,并且依赖于该Tensor的之后的所有节点都需要求导。
Tensor有两个重要的属性,分别记录了该Tensor的梯度与经历的操作。
.grad: 该Tensor对应的梯度, 类型为Tensor,并与Tensor同维度
.grad_fn: 查看该tensor经历了什么样的操作,用作反向传播的梯度计算,如果该Tensor由用户自己创建,则该grad_fn为None。

代码如下:

import torch
a = torch.randn(2,2,requires_grad=True)
b = torch.randn(2, 2)

# 可以看到默认的Tensor是不需要求导的,设置requires_grad为Ture后则需要求导
print(a.requires_grad, b.requires_grad)

# 也可以通过内置函数requires_grad_()将Tensor变为需要求导
b.requires_grad_()
print(b.requires_grad)

# 通过计算生成的Tensor,由于依赖的Tensor需要求导,因此c也需要求导
c = a + b
print(c.requires_grad)

# a与b是自己创建的,grad_fn为None,而c的grad_fn则是一个Add函数操作
print(a.grad_fn, b.grad_fn, c.grad_fn)

计算图

计算图构建

计算图是PyTorch对于神经网络的具体实现形式,包括每一个数据Tensor及Tensor之间的函数function。在此我们以z=wx+b为例,通常在神经网络中,x为输入,w与b为网络需要学习的参数,z为输出,在这一层,计算图构建方法如下图所示。

pytorch自动求导源码_pytorch自动求导源码


计算图构建代码

import torch

x = torch.randn(1)
w = torch.ones(1, requires_grad=True)
b = torch.ones(1, requires_grad=True)
# 自己生成的,因此都为叶节点
print(x.is_leaf, w.is_leaf, b.is_leaf)
# 默认是不需要求导,关键字赋值为True后则需要求导
print(x.requires_grad, w.requires_grad, b.requires_grad)

y = w*x
z = y + b
print(y.is_leaf, z.is_leaf)

# 由于依赖的变量有需要求导的,因此y与z都需要求导
print(y.requires_grad, z.requires_grad)

# grad_fn记录生成该变量经过了什么操作,如y是Mul,z是Add
print(y.grad_fn)
print(z.grad_fn)

# 对根节点调用backward()函数,进行梯度反传
z.backward(retain_graph=True)
print(w.grad)
print(b.grad)

叶节点、中间节点和根节点
在上图中,x、ω和b都是用户自己创建的,因此都为叶节点,ωx首先经过乘法算子产生中间节点y,然后与b经过加法算法产生最终输出z,并作为根节点。
Autograd基本原理
Autograd的基本原理是随着每一个Tensor的计算操作形成和计算图的生成,将操作的function记录在Tensor的grad_fn中。在前向计算完
后,只需对根节点进行backward函数操作,即可从当前根节点自动进行反向传播与梯度计算,从而得到每一个叶子节点的梯度,梯度计算遵循链式求导法则。

Autograd三大特点

PyTorch的Autograd机制使得其可以灵活地进行前向传播与梯度计算

动态图特性

动态图特性:PyTorch建立的计算图是动态的,这也是PyTorch的一大特点。动态图是指程序运行时,每次前向传播时从头开始构建计算图,这样不同的前向传播就可以有不同的计算图,也可以在前向时插入各种Python的控制语句,不需要事先把所有的图都构建出来,并且可以很方便地查看中间过程变量。

backward()函数

backward()函数还有一个需要传入的参数grad_variabels,其代表了根节点的导数,也可以看做根节点各部分的权重系数。因为PyTorch不允许Tensor对Tensor求导,求导时都是标量对于Tensor进行求导,因此,如果根节点是向量,则应配以对应大小的权重,并求和得到标量,再反传。如果根节点的值是标量,则该参数可以省略,默认为1。

梯度累加

当有多个输出需要同时进行梯度反传时,需要将retain_graph设置为True,从而保证在计算多个输出的梯度时互不影响。