14.2_解决方案

14.2 解决方案

解决方案很简单。基于以上内容,我们按如下方式修改Variable类。

steps/step14.py

class Variable:   
def backward(self): if self.grad is None: self.grad = np.ones_like(self.data) funcs  $=$  [self creator] while funcs: f  $=$  funcs.pop() gys  $=$  [output.grad for output in f.outputs] gxs  $=$  f.backup(\*gys) if not isinstance(gxs, tuple): gxs  $=$  (gxs,) for x,gx in zip(finputs,gxs): if x.grad is None: x.grad  $\equiv$  gx else: x.grad  $\equiv$  x.grad +gx
if x creator is not None: func.append(x creator)

如上面的代码所示,如果是第1次设置导数(grad),做法就和此前一样,直接用从输出端传来的导数进行赋值。之后如果再传来导数,则“加上”这个导数。

上面的代码使用x.grad = x.grad + gx对导数进行了加法运算。看起来这行代码也可以改为x.grad += gx这种使用了加法赋值运算符 (+=)(+=) 的形式,但实际上这种写法会出现问题。具体原因和背景知识有些复杂,而且脱离了深度学习的本质,所以在此不进行讨论。感兴趣的读者请参考本书的附录A,其中详细介绍了这个问题。

这样就可以重复使用同一个变量了。下面再来试试之前出现问题的计算。

steps/step14.py
$\mathbf{x} =$  Variable(np.array(3.0))   
y  $=$  add(x,x)   
y.backup()   
print(x.grad)

运行结果

2.0

运行上面的代码,我们得到了正确结果2.0。接着,试着把x连加三次。

steps/step14.py
$\mathbf{x} =$  Variable(np.array(3.0))   
 $y =$  add(add(x,x),x)   
y.backup()   
print(x.grad)

运行结果

3.0

结果是3.0。根据 y=x+x+x=3xy = x + x + x = 3x 可知导数为3,与代码运行结果一致。这样,重复使用同一个变量的实现就完成了。