自动求导

  • 梯度
    梯度是一个向量,表示函数在某一点的变化率最快的方向和大小。在梯度下降法中,梯度指的是目标函数在某一点的梯度向量。梯度下降法通过迭代的方式沿着梯度的反方向逐步更新参数,以最小化目标函数。梯度下降法的基本思想是,沿着梯度的反方向移动一小步,直到找到函数的最小值。

  • 对函数y=2x^T*x,关于列向量求导。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    import torch

    # 假设我们想对函数y=2x^T*x,关于列向量求导
    x = torch.arange(4.0) # 范围为4。0.0~3.0
    print(x)

    # 存储梯度
    x.requires_grad_(True) # 等价于‘x = torch.arange(4.0, requires_grad=True)’ 只有float类型的张量才能用此函数
    x.grad # 默认值为None,用于访问梯度,函数放置于此,x的梯度

    y = 2 * torch.dot(x, x) # 内积,a1*b1+a2*b2+a3*b3+..... ,grad_fn=<MulBackward0>隐式构造
    print(y)

    # 通过调用反向传播函数来自动计算y关于x每个分量的梯度
    y.backward() # 求导 y=2x0^2+2x1^2+2x2^2+2x3^2对每一个分量求偏导等于4x0,4x1,4x2,4x3 即4*0,4*1,4*2,4*3
    print(x.grad)

    print(x.grad == 4 * x)

    # 在默认情况下,pyTorch会累计梯度,我们需要清除之前的值
    x.grad.zero_() # 梯度清零,变为最开始的tensor([0., 1., 2., 3.])
    y = x.sum() # y=x0+x1+x2+x3
    y.backward() # 分别求偏导,得tensor([1., 1., 1., 1.])
    print(x.grad)

    # 深度学习中,我们的目的不是计算微分矩阵,而是批量中每个样本单独计算的偏导数之和
    x.grad.zero_() # 梯度清零,变为最开始的tensor([0., 1., 2., 3.])
    y = x * x # 按元素分别相乘
    # 等价于y.backward(torch.ones(len(x)))
    y.sum().backward() # 求导 y=x0^2+x1^2+x2^2+x3^2对每一个分量求偏导
    # 标量关于向量求导,得到的是一个向量;向量关于向量求导,得到的就是一个矩阵;这里是通过sum的形式转化成了标量,进行求导
    print(x.grad) # 得:tensor([0., 2., 4., 6.])

    # 将某些计算移动到记录的计算图之外
    x.grad.zero_()
    print(x.grad) # 得tensor([0., 0., 0., 0.])
    y = x * x
    u = y.detach() # detach 将变量转为常数,u就是一个常数
    z = u * x

    z.sum().backward() # 得tensor([True, True, True, True])
    print(x.grad == u)

    x.grad.zero_()
    y.sum().backward()
    print(x.grad == 2 * x)


    # 即使构建函数得计算图需要通过Python控制流(例如,条件、循环或任意函数调用),我们仍计算得到的变量的梯度
    def f(a):
    b = a * 2
    while b.norm() < 1000: # norm()用于计算张量 b 的默认 L2 范数
    b = b * 2
    if b.sum() > 0:
    c = b
    else:
    c = b * 100
    return c # 一直是增加系数


    a = torch.randn(size=(), requires_grad=True) # 生成一个没有维度的张量,并且需要梯度计算
    d = f(a)
    d.backward() # d=f(a)=ka,梯度是k,k=d/a

    print(a.grad == d / a) # 得tensor(True)
  • 显示计算:先给公式再给值;
    隐式计算:先给值再给公式