zoukankan      html  css  js  c++  java
  • 动手学深度学习 | 自动求导 | 05

    自动求导

    链式法则,如果扩展到向量,最最重要的还是看形状。

    <x,w>这是内积的写法。

    自动求导涉及到一个计算图的概念,虽然Pytorch不用要求大家理解计算图,但是理解了对使用TensorFlow等都是有好处的。

    计算图其实本质上就和刚刚求导链式法则的过程。

    显示构造,就是先构造好这个公式,然后再带入数值计算,一般数学上都是属于显示构造。

    正向累积就是正常计算,反向传播是从结果不停的反向进行求导。

    反向从根节点向下扫,可以保证每个节点只扫一次;

    正向从叶节点向上扫,会导致上层节点可能需要被重复扫多次(正向中子节点比父节点先计算,因此也无法像反向那样把本节点的计算结果传给每一个子节点)

    自动求导实现

    image-20210918112130183

    操作总结

    import torch
    
    x = torch.arange(4.)
    # 等价于 x = torch.arange(4.,requires_grad=True)
    x.requires_grad_(True) # 需要存储中间结果
    print(x.grad) # 查看x的梯度,默认为None
    
    y = 2*torch.dot(x,x) # 点称
    y # tensor(28., grad_fn=<MulBackward0>)
    
    y.backward() # 对y进行反向传播
    x.grad # 查看BP得到的梯度
    
    # y=2x^2 y'=2x,可以判断BP得到的梯度是否是对的
    4*x == x.grad
    
    x.grad_zero_() # Pytorch的梯度会累积,这里是将0写入梯度中
    y = x.sum() # sum() 相当于点乘一个全为1的向量 
    y.backward()
    x.grad
    
    x.grad_zero_()
    y = x*x
    # x*x == sum(y·y)
    y.sum().backward()
    x.grad
    
    
    # 将计算移动到计算图之外
    x.grad_zero_()
    y = x*x
    u = y.detach()
    z = u*x
    
    z.sum().backward()
    x.grad,x.gard==u
    
    # 及时构建函数的计算图需要通过Python控制流,我们仍然可以计算得到变量的梯度
    def f(a):
        b = a * 2
        while b.norm() < 1000:
            b = b * 2
        if b.sum() > 0:
            c = b
        else:
            c = 100 * b
        return c
    
    # size=() 标量
    # a是一个随机变量,并且需要记录梯度
    a = torch.randn(size=(), requires_grad=True)
    d = f(a)
    d.backward()
    
    # f()可以理解成是一个计算图的流程,最终得到d
    # 因为是标量,所以可以用斜率来验证得到的梯度是否是正确的
    a.grad == d / a
    

    QA

    1. PPT上的显示构造和隐式构造为什么看起来差不多?

    显示构造:把整个计算图都先设计完成,然后再给值

    隐式构造:就直接写程序流程,然后框架会在后台进行计算图的构建

    实际使用过程中,显示构造计算图会麻烦很多!

    1. 为什么深度学习中一般对标量求导而不是对矩阵求导或者向量?如果我的loss是包含向量或者矩阵,那求导之前是不是要把他们变成标量?

    loss通常是一个标量,精度也好,很多机器学习的loss都是一个标量,如果loss是一个向量的loss的话,那就会变得很麻烦。向量向下走就是就是矩阵,矩阵往下走四维矩阵,网络程度一深,那么就会成为一个非常大的张量。

    1. 多个loss分别反向的时候是不是需要累积梯度?

    是的,如果后面你的神经网络有多个损失函数的话,你是需要做梯度累加的,这也是Pytorch默认累加梯度的一个理由。

  • 相关阅读:
    洛谷P3233 世界树
    线性基
    CF321E Ciel and Gondolas
    洛谷P2619 Tree I
    重温一下基本数据类型以及自动提升数据类型的问题
    不可理喻的JSTL标签库
    理解RESTful架构(转)
    Node.js的优点和缺点(转载)
    自制双色球随机号码
    编程, 细心永远都不嫌多(记录java连接数据库的一个错误)
  • 原文地址:https://www.cnblogs.com/Rowry/p/15308173.html
Copyright © 2011-2022 走看看