PyTorch学习笔记(三):自动求导Autograd

作者: Daisy丶 | 来源:发表于2019-04-26 21:47 被阅读11次

    现代神经网络依靠反向传播(Back Propogation)算法来对模型进行优化,其本质是大规模链式求导。因此,能够对通过编程来对网络参数进行求导是非常重要的。目前的深度学习框架神经网络如PyTorch和TensorFlow等都实现了自动求梯度的功能。

    计算图

    计算图(Computation Graph)是现代深度学习框架的核心,其为高效自动求导算法——反向传播(Back Propogation)提供了理论支持。如下所示,计算图是一种特殊的有向无环图(DAG),用于记录算子与变量之间的关系。

    计算图

    计算图具有两个优势:
    a. 使用非常简单的函数就可以组合成一个极其复杂的模型;
    b. 可以实现自动微分。

    在PyTorch中,通过记录算子与变量之间的关系可以生成表达式对应的计算图。对于表达式y = wx + b,其中wxb是变量,+=是算子。有DAG中,wxb是叶子节点(leaf node),这些节点通常由用户自己创建,不依赖于其他变量。y称为根节点,是计算图的最终目标。

    >>> x = torch.ones(2, 2)
    >>> w = torch.rand(2, 2, requires_grad=True)
    >>> b = torch.rand(2, 2, requires_grad=True)
    >>> y = w * x + b
    >>> x.is_leaf, w.is_leaf, b.is_leaf
    (True, True, True)
    >>> y.is_leaf
    False
    >>>
    

    自动求导

    在创建tensor的时候指定requires_grad参数或者使用requires_grad_()函数来指定是否对该参数进行自动求导。

    >>> x = torch.ones(2, 2)
    >>> w = torch.rand(2, 2, requires_grad=True)
    >>> b = torch.rand(2, 2, requires_grad=True)
    >>> y = w * x + b
    

    x.requires_grad未指定自动求导,因此是False,w.requires_gradb.requires_grad为我们的求导对象,因此是True。虽然未指定y.requires_grad为True,但由于y依赖于需要求导的w,因此y.requires_grad为True。

    >>> x.requires_grad, b.requires_grad, w.requires_grad
    (False, True, True)
    >>> y.requires_grad
    True
    

    有了计算图之后,对根节点调用backward()函数进行反向传播,就能够得到各个需要求导的叶子的导数,通过grad属性即可得到。

    >>> y = w * x + b
    >>> y.backward()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "F:\ProgramData\Anaconda3\lib\site-packages\torch\tensor.py", line 102, in backward
        torch.autograd.backward(self, gradient, retain_graph, create_graph)
      File "F:\ProgramData\Anaconda3\lib\site-packages\torch\autograd\__init__.py", line 84, in backward
        grad_tensors = _make_grads(tensors, grad_tensors)
      File "F:\ProgramData\Anaconda3\lib\site-packages\torch\autograd\__init__.py", line 28, in _make_grads
        raise RuntimeError("grad can be implicitly created only for scalar outputs")
    RuntimeError: grad can be implicitly created only for scalar outputs
    

    如果对非标量y求导,函数需要额外指定grad_tensors,grad_tensors的shape必须和y的相同。

    >>> weights = torch.ones(2, 2)
    >>> y.backward(weights, retain_graph=True)
    >>> w.grad
    tensor([[1., 1.],
            [1., 1.]])
    

    此外,PyTorch中梯度是累加的,每次反向传播之后,当前的梯度值会累加到旧的梯度值上。

    >>> y.backward(weights, retain_graph=True)
    >>> w.grad
    tensor([[2., 2.],
            [2., 2.]])
    >>> y.backward(weights, retain_graph=True)
    >>> w.grad
    tensor([[3., 3.],
            [3., 3.]])
    

    要清空变量当前的梯度,可以使用zero()zero_()函数。

    >>> w.grad.zero_()
    tensor([[0., 0.],
            [0., 0.]])
    >>> w.grad
    tensor([[0., 0.],
            [0., 0.]])
    

    PS:在我们使用PyTorch构建网络时,Model会在反向传播时会自行处理梯度更新问题,上述知识有助于理解PyToch中的自动求导。

    相关文章

      网友评论

        本文标题:PyTorch学习笔记(三):自动求导Autograd

        本文链接:https://www.haomeiwen.com/subject/dzawgqtx.html