动手学深度学习 07
自动求导
向量链式法则
标量链式法则
拓展到向量
拓展到向量最大的问题是要把形状搞对
例1
此处X与W的内积对W求导,为符合分子布局,因此是
例2
自动求导
- 自动求导计算一个函数在指定值上的导数
- 它有别于
- 符号求导(显式计算)
- 数值求导
- 符号求导(显式计算)
计算图
- 将代码分解成操作子
- 将计算表示成无环图
- 显式构造:MXNet/Tensorflow/Theano都可以显式的构造
- 隐式构造:Pytorch/MXNet
自动求导的两种模式
- 链式法则
- 方式一:正向累积
- 方式二:反向累积、又称反向传递
例子
反向累积总结
- 构造计算图
- 前向:执行图,存储中间结果
- 反向:从相反方向执行图
- 去除不需要的枝
- 去除不需要的枝
复杂度
- 计算复杂度差不多
- 反向累积的内存复杂度是O(n),需要存储正向的所有中间结果;正向的内存复杂度是O(1),但是通常在神经网络中不会用
自动求导实现
求导是几乎所有深度学习优化算法的关键步骤。深度学习框架通过自动计算导数,即自动微分(automatic differentiation)来加快求导。自动微分使系统能够随后反向传播梯度,反向传播(backpropagate)意味着跟踪整个计算图,填充关于每个参数的偏导数
一个简单的例子
假设我们想对函数
首先,我们创建变量x
并为其分配一个初始值。
1 | import torch |
现在计算y
1 | y = 2 * torch.dot(x, x) |
通过调用反向传播函数来自动计算y关于x每个分量的梯度,并打印他们
1 | y.backward() |
现在计算x的另一个函数
1 | # 默认情况下,PyTorch会累积梯度,我们需要清除之前的值 |
非标量变量的反向传播
当y不是标量时,向量y关于向量x的导数的最自然解释是一个矩阵。对于高阶和高维的y和x,求导的结果可以是一个高阶张量。深度学习中,我们的目的不是计算微分矩阵,而是批量中每个样本单独计算的偏导数之和
1 | # 对非标量调用backward需要传入一个gradient参数,该参数指定微分函数关于self的梯度。 |
分离计算
有时我们希望将某些计算移动到记录的计算图以外
1 | x.grad.zero_() |
Python控制流的梯度计算
使用自动微分的一个好处是:即使构建函数的计算图需要通过python控制流(例如条件、循环或任意函数调用),我们仍然可以计算得到的变量的梯度
1 | def f(a): |
小结
- 深度学习框架可以自动计算导数:我们首先将梯度附加到想要对其计算偏导数的变量上,然后记录目标之值的计算,执行它的反向传播函数,并访问得到的梯度
QA
- 为什么深度学习中一般对标量求导而不是对矩阵或者向量?
因为loss和精度通常都是标量
- 标题: 动手学深度学习 07
- 作者: 敖炜
- 创建于 : 2023-07-25 14:55:32
- 更新于 : 2024-04-19 09:28:00
- 链接: https://ao-wei.github.io/2023/07/25/动手学深度学习-07/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论