36.1_double backprop的用途

36.1 double backprop的用途

接下来看看 double backprop 除了求高阶导数,还有哪些用途。首先思考下面这个问题。

问题:给定以下两个式子,求 x=2.0x = 2.0 时的 zx\frac{\partial z}{\partial x}zzxx 的导数)。

y=x2(36.1)y = x ^ {2} \tag {36.1}
z=(yx)3+y(36.2)z = \left(\frac {\partial y}{\partial x}\right) ^ {3} + y \tag {36.2}

这个问题还是前面见过的求导的问题。与之前不同的是式子36.2中包含导数。也就是说,我们需要对包含导数的式子进一步求导。这个问题也可以通过double backprop计算。在详细解释之前,我们先手动计算 zx\frac{\partial z}{\partial x} 。式子可按如下方式展开。

yx=2xz=(yx)3+y=8x3+x2zx=24x2+2x\begin{array}{l} \frac {\partial y}{\partial x} = 2 x \\ z = \left(\frac {\partial y}{\partial x}\right) ^ {3} + y = 8 x ^ {3} + x ^ {2} \\ \frac {\partial z}{\partial x} = 2 4 x ^ {2} + 2 x \\ \end{array}

按照上面的方式展开式子后,将 x=2.0x = 2.0 代入 24x2+2x24x^{2} + 2x ,得到答案100.0。

上式中的 yx\frac{\partial y}{\partial x} 不是数值,而是 xx 的表达式。如果此时求出在 x=2.0x = 2.0yx\frac{\partial y}{\partial x} 的值,并将其代入 z=(yx)3+yz = \left(\frac{\partial y}{\partial x}\right)^{3} + y ,我们就会得到错误的结果。

基于以上内容,我们尝试用DeZero来求解这个问题。代码如下所示。

steps/step36.py

import numpy as np   
fromdezero import Variable   
 $\begin{array}{rl} & {\mathrm{x = V�ariable(np.array(2.0))}}\\ & {\mathrm{y = x**2}}\\ & {\mathrm{ybackwardcreate_graph=True})}\\ & {\mathrm{gx = x.grad}}\\ & {\mathrm{x.cleargrad()}}\\ & {\mathrm{z = gx**3 + y}}\\ & {\mathrm{z.backward()}}\\ & {\mathrm{print(x.grad)}} \end{array}$

运行结果

variable(100.)

代码中比较重要的地方是y.create_graph=True)。这行代码的作用是进行反向传播以求出导数。于是,一个新的计算图就被创建了出来(此时, 2×2^{*}\times 的计算图是在用户看不见的地方创建的)。之后使用反向传播创建的计算图进行新的计算,再次进行反向传播。这样就可以求得正确的导数。


图36-1 WGAN-GP中优化的函数(式子引自参考文献[21])

上面代码中的gx=x.grad不仅仅是一个变量(值),还是一个计算图(式子)。因此,我们可以对x.grad的计算图再次进行反向传播。

求出导数的式子,并使用该式子进行计算,然后再次求导的问题可以用double backprop来解决。我们也可以在深度学习的研究中看到double backprop的这种用法。下面介绍几个例子。

36.1_double backprop的用途 - 深度学习自制框架 | OpenTech