Pyorch中的自动求导。

对于复杂的网络结构,如果手动实现反向传播,不仅费时费力,而且容易出错。torch.autograd提供自动求导的功能,方便大家使用。它能够根据输入和前向传播过程自动构建计算图,并执行反向传播。在使用中我们只需要专注于定义前向传播的网络结构即可,torch.autograd会自动帮我们处理好反向传播过程中的求导。

计算图(Computation Graph)是现代深度学习框架如PyTorch和TensorFlow等的核心,其为高效自动求导算法——反向传播(Back Propogation)提供了理论支持,关于计算图的基础知识推荐阅读Christopher Olah的文章

PyTorch中autograd的底层采用了计算图,计算图是一种特殊的有向无环图(DAG),用于记录算子与变量之间的关系。一般用矩形表示算子,椭圆形表示变量。如表达式𝐳 = 𝐰𝐱 + 𝐛可分解为𝐲 = 𝐰𝐱和𝐳 = 𝐲 + 𝐛,其计算图如下图所示,图中MULADD都是算子,𝐰,𝐱,𝐛即变量。

如上有向无环图中,$\textbf{X}$和$\textbf{b}$是叶子节点(leaf node),这些节点通常由用户自己创建,不依赖于其他变量。$\textbf{z}$称为根节点,是计算图的最终目标。利用链式法则很容易求得各个叶子节点的梯度。 $$ {\partial z \over \partial b} = 1,\space {\partial z \over \partial y} = 1
{\partial y \over \partial w }= x,{\partial y \over \partial x}= w
{\partial z \over \partial x}= {\partial z \over \partial y} {\partial y \over \partial x}=1 * w
{\partial z \over \partial w}= {\partial z \over \partial y} {\partial y \over \partial w}=1 * x
$$ 而有了计算图,上述链式求导即可利用计算图的反向传播自动完成,其过程如下图所示。

import torch

def f(x):
    y = x**2
    return y

def gradf(x):
    """
    手动求导
    """
    dx = 2*x
    return dx

x = torch.randn(3,4, requires_grad = True)
print(x)
y = f(x)
print(y)
# autograd
y.backward(torch.ones(y.size())) # gradient形状与y一致
print(x.grad)
# 手动
print(gradf(x))
# autograd的计算结果与利用公式手动计算的结果一致

"""
tensor([[ 3.1988, -1.0697, -0.2496,  0.0252],
        [ 0.0834,  0.6836, -0.0576,  0.8692],
        [-1.7781, -1.4217,  1.4543, -0.2541]], requires_grad=True)
        
tensor([[1.0233e+01, 1.1444e+00, 6.2284e-02, 6.3285e-04],
        [6.9580e-03, 4.6736e-01, 3.3167e-03, 7.5544e-01],
        [3.1616e+00, 2.0212e+00, 2.1150e+00, 6.4553e-02]],
       grad_fn=<PowBackward0>)
       
tensor([[ 6.3977, -2.1395, -0.4991,  0.0503],
        [ 0.1668,  1.3673, -0.1152,  1.7383],
        [-3.5562, -2.8433,  2.9086, -0.5081]])
        
tensor([[ 6.3977, -2.1395, -0.4991,  0.0503],
        [ 0.1668,  1.3673, -0.1152,  1.7383],
        [-3.5562, -2.8433,  2.9086, -0.5081]], grad_fn=<MulBackward0>)
"""