机器学习(五) | 自动微分与反向传播

计算图

反向传播

如对于计算 z=(<\mathbf{x,w}>-y)^{2} 的 \frac{\partial z}{\partial \mathbf{w}} 

记 z = b^2 ,b=a-y ,a=< x, w >则反向求导是先计算 \frac{\partial z}{\partial b} 再计算 \frac{\partial z}{\partial a}=\frac{\partial z}{\partial b}\frac{\partial b}{\partial a}=\frac{\partial z}{\partial b},再计算\frac{\partial z}{\partial \mathbf{x}}=\frac{\partial z}{\partial a}\frac{\partial a}{\partial \mathbf{x}}=\frac{\partial z}{\partial a}\mathbf{w}^{T}

计算复杂度:O(n),内存复杂度O(n)

正向传播

在求复合函数的值的时候就用的是正向传播如f(g(x))先求的m=g(x)再求f(m)

一个简单的例子

import torch

x = torch.arange(4.0)

x.requires_grad_(True)  # 等价于x=torch.arange(4.0,requires_grad=True)
x.grad  # 默认值是None
x

y = 2 * torch.dot(x, x)
y

y.backward()
x.grad

x.grad == 4 * x

# 在默认情况下,PyTorch会累积梯度,我们需要清除之前的值
x.grad.zero_()
y = x.sum()
y.backward()
x.grad

y.backward()的前提

1.y是一个纯标量(即它的'shape'属性为空或为'()')

2.张量对象是叶子节点(即它们的 requires_grad 属性为 True

如果满足则会在计算图中执行反向传播算法。需要注意的是计算得到的每个叶子节点的梯度会会被累积到每个叶子节点的'grad'属性中。往往需要先x.grad.zero_()。需要获取梯度值时可以使用x.grad。

非标量变量的反向传播

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

在 PyTorch 中,张量对象的 grad_fn 属性指示了创建该张量的操作(即计算图中的操作),这个属性告诉 PyTorch 在进行反向传播时如何计算梯度。在这种情况下,MulBackward0 表示这个张量是通过乘法操作得到的,因此 PyTorch 将使用乘法的导数规则来计算梯度。

权重参数 torch.ones(len(x))

分离计算

x.grad.zero_()
y = x * x
u = y.detach()
z = u * x

z.sum().backward()
x.grad == u

y.detach()将u视为常数,即与x无关的量。

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

Python控制流的梯度计算

使用自动微分的一个好处是: [即使构建函数的计算图需要通过Python控制流(例如,条件、循环或任意函数调用),我们仍然可以计算得到的变量的梯度]。 在下面的代码中,while循环的迭代次数和if语句的结果都取决于输入a的值。

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

小结

  • 深度学习框架可以自动计算导数:我们首先将梯度附加到想要对其计算偏导数的变量上,然后记录目标值的计算,执行它的反向传播函数,并访问得到的梯度。
  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值