• 动手学深度学习(pytorch)学习记录4-自动微分[学习记录]


    注:本代码在jupyter notebook上运行
    封面图片来源

    1 一个简单的例子

    作为一个演示例子,假设我们想对函数y=2xTX关于列向量求导。 首先,我们创建变量x并为其分配一个初始值。

    import torch
    
    x = torch.arange(4.0)
    x
    

    在这里插入图片描述
    在我们计算y关于x的梯度之前,需要一个地方来存储梯度。 重要的是,我们不会在每次对一个参数求导时都分配新的内存。 因为我们经常会成千上万次地更新相同的参数,每次都分配新的内存可能很快就会将内存耗尽。 注意,一个标量函数关于向量x的梯度是向量,并且与x具有相同的形状。

    x.requires_grad_(True)  # 等价于x=torch.arange(4.0,requires_grad=True)
    # 这行代码的作用是设置变量 x 需要梯度计算
    print(x.grad)  # 默认值是None
    

    在这里插入图片描述

    # 计算y
    y = 2 * torch.dot(x, x)# 点积
    y
    

    在这里插入图片描述
    x是一个长度为4的向量,计算x和x的点积,得到了我们赋值给y的标量输出。 接下来,通过调用反向传播函数来自动计算y关于x每个分量的梯度,并打印这些梯度。

    y.backward() # 反向传播时,如果x的requires_grad为True,则会计算y关于x的梯度
    # 假设我们想要查看x的梯度(注意:在实际操作中,梯度会在调用backward()后被存储) 
    print(x.grad)
    

    在这里插入图片描述
    函数y=2x^T*X关于x的梯度应为4x。 让我们快速验证这个梯度是否计算正确。

    x.grad == 4 * x
    

    在这里插入图片描述
    现在计算x的另一个函数。

    # 在默认情况下,PyTorch会累积梯度,我们需要清除之前的值
    x.grad.zero_()# 在梯度反向传播之前清除(即归零)模型参数的梯度
    y = x.sum()
    y.backward()
    x.grad
    

    在这里插入图片描述

    2 非标量变量的反向传播

    # 对非标量调用backward需要传入一个gradient参数,该参数指定微分函数关于self的梯度。
    # 本例只想求偏导数的和,所以传递一个1的梯度是合适的
    x.grad.zero_()
    y = x * x
    # 等价于y.backward(torch.ones(len(x)))
    y.sum().backward()
    x.grad
    

    在这里插入图片描述

    3 分离计算

    有时,我们希望将某些计算移动到记录的计算图之外。 例如,假设y是作为x的函数计算的,而z则是作为y和x的函数计算的。 想象一下,我们想计算z关于x的梯度,但由于某种原因,希望将y视为一个常数, 并且只考虑到x在y被计算后发挥的作用。

    这里可以分离y来返回一个新变量u,该变量与y具有相同的值, 但丢弃计算图中如何计算y的任何信息。 换句话说,梯度不会向后流经u到x。 因此,下面的反向传播函数计算z=u*x关于x的偏导数,同时将u作为常数处理, 而不是z=x^3关于x的偏导数。

    x.grad.zero_()# 梯度归零
    y = x * x
    u = y.detach()# detach() 方法的作用是从计算图中分离出一个张量。
    # 这意味着返回的新张量不再依赖于原来的计算图,因此不会参与任何后续的梯度计算。
    z = u * x
    
    z.sum().backward()
    x.grad == u
    

    在这里插入图片描述

    4 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
    
    # 计算梯度
    a = torch.randn(size=(), requires_grad=True)
    d = f(a)
    d.backward()
    

    我们现在可以分析上面定义的f函数。 请注意,它在其输入a中是分段线性的。 换言之,对于任何a,存在某个常量标量k,使得f(a)=k*a,其中k的值取决于输入a,因此可以用d/a验证梯度是否正确。

    a.grad == d / a
    

    在这里插入图片描述

    这一篇有点难度,加入自己理解的比较少。

    本人学习地址https://zh-v2.d2l.ai/
    恳请大佬批评指正。

  • 相关阅读:
    qml保姆级教程四:按钮组件
    RabbitMQ基础
    IEEE期刊如何查找论文模板
    基于Web的个人网页响应式页面设计与实现 HTML+CSS+JavaScript(web前端网页制作课作业)
    读图数据库实战笔记02_图数据建模
    SpringBoot学习笔记(五)IOC
    修复VS2015没有代码提示的问题【已解决】
    leetcode-179-最大数
    智慧医疗新篇章:山海鲸可视化引领行业变革
    MT4 PC端历史版本更新(老版本MT4下载)
  • 原文地址:https://blog.csdn.net/weixin_50995339/article/details/140993736