39.2_sum函数的实现

39.2 sum函数的实现

在DeZero的sum函数的反向传播中,梯度的元素会复制为输入变量的形状。然而反向传播需要对Variable实例进行计算,这意味着复制操作必须作为DeZero函数运行。

将元素复制为指定形状的操作与NumPy的广播功能相同。这个操作将在下一个步骤中通过broadcast_to(x, shape)函数实现。该函数用于将x(Variable实例)复制为shape的形状。

这里预先使用broadcast_to函数。这样一来,我们就可以用如下代码实现DeZero的Sum类和sum函数。

dezero/functions.py

class Sum(Function): def forward(self, x): self.x_shape = x.shape y = x.sum() return y def backward(self, gy): gx = broadcast_to(gy, self.x_shape) return gx   
def sum(x): return Sum() (x)

在上面的代码中,反向传播的处理使用了将在下一个步骤实现的broadcast_to函数。通过这个函数复制梯度gy的元素,使其与输入变量在形状上一致,这样就实现了sum函数。下面我们尝试使用一下刚刚实现的sum函数。

steps/step39.py

import numpy as np   
fromdezero import Variable   
importdezero-functionsasF   
 $\begin{array}{rl} & {\mathrm{x} = \mathrm{Variable}(\mathrm{np.array}([1,2,3,4,5,6]))}\\ & {\mathrm{y} = \mathrm{F.sum(x)}}\\ & {\mathrm{y/backward()}}\\ & {\mathrm{print(y)}}\\ & {\mathrm{print(x.grad)}} \end{array}$

运行结果

variable(21)  
variable([1 1 1 1 1 1])

上面的代码正确地完成了加法运算并求出了梯度。sum函数也支持输入变量不是向量的情况。下面是对二维数组(矩阵)进行计算的结果。

steps/step39.py

$\mathbf{x} =$  Variable(np.array([[1,2,3],[4,5,6]]))  
y  $=$  F.sum(x)  
y.backup()  
print(y)  
print(x.grad)

运行结果

variable(21)  
variable([[1 1 1]  
[1 1 1]])

如上面的结果所示,x.grad的形状和x的形状相同,输出的值也正确。通过以上代码,我们实现了“基础版”的sum函数。接下来,我们将扩展当前的sum函数,实现真正的sum函数。