megengine.autodiff.GradManager¶
- class GradManager[源代码]¶
GradManager 负责计算梯度,或更一般地,矢量-雅可比积,通过反向模式做自动微分(又称为反向传播)。
反向模式自动微分为了最佳计算效率通常会重用许多中间张量。然而在交互式(REPL)环境中,很难知道用户之后将如何使用梯度从而预先保存某些张量。要解决此问题,用户必须以某种方式事先声明什么梯度需要被保留。在 GradManager 中,用户如果希望后续计算张量的梯度,则需要在该张量上调用
attach
方法。此外,在张量被attach
之前对张量的任何计算都会从autodiff
的角度完全被忽略,所以attach
必须在需要微分的任何计算之前被调用。例如,下面的自动微分代码
x = get_x() y = f(x) dy = ones_like(y) dx = vjp(y, x, dy) # vector-Jacobian product
可用 GradManager 在交互式环境下重写为
with GradManager() as gm: x = get_x() gm.attach(x) # must be placed before any computation on x that needs differentiation y = f(x) dy = ones_like(y) gm.backward(y, dy) # doesn't need x, already known via attach() dx = x.grad # backward() saves result to .grad attribute
训练神经网络的一个更现实的例子是
gm = GradManager() gm.attach(model.parameters()) for data in dataset: with gm: loss = model(data) gm.backward(loss) # gradients w.r.t. parameters is accumulated into their .grad attributes
你也可以使用
record()
和release()
而不使用with
语义:gm = GradManager() gm.attach(model.parameters()) for data in dataset: gm.record() loss = model(data) gm.backward(loss) # backward() will clear recorded history and free resources # call release() if backward() is not called # gm.release()
为方便起见,可以(并非必须)重用 GradManager 。如在这些示例中,您只需要 attach 一个张量一次,而 GradManager 将永远记住它。但是,一个 GradManager 只能记录一次计算历史。要同时进行多种微分或进行高阶微分,可根据需要创建尽可能多的 GradManager。
注解
可变张量在执行符号微分时引入歧义:我们指的是 Tensor 的哪个版本?对于 attched 的张量,GradManager 通过在第一次遇见张量时 ‘snapshoting’ 它们来解决这种歧义,要么通过
record
之前就被attach
,要么通过attach
如果 GradManager 已经在记录。attched 的张量将会被解释为它们的快照版本以进行区分。对backward
的第一个参数的相同歧义是只需使用最新版本即可解决。通常,在数据并行的时候,我们需要跨进程计算梯度的均值。使用者最终可获得平均的梯度若一个 “AllReduce” 回调函数像下面一样被注册的话:
import megengine.distributed as dist gm = GradManager() gm.attach(model.parameters(), callback=dist.make_allreduce_cb("MEAN"))
方法
attach
(tensors[, callbacks])指示 GradManager 跟踪张量上的操作,以便那些张量上的梯度,可以在之后进行计算。
Return attached tensor list from
attach
.backward
([y, dy])对所有 attached Tensor 计算梯度 (或向量-雅可比积),并将其积累到对应 Tensor 的 .grad 属性中,在过程中释放资源。
record
()开始记录操作
release
()停止记录操作并释放为计算梯度而保留的资源