30.2_确认工作②:Function类
30.2 确认工作②:Function类
接下来是Function类。下面是Function类的__call__方法的代码。我们重点看一下阴影部分。
class Function: def__call__(self,\*inputs): inputs $=$ [as_variable(x)for $\mathbf{x}$ in inputs] #①正向传播的计算(主处理) xs=[x.data for x in inputs] ys $=$ self.forward(*xs) if not isinstance(ys,tuple): ys $=$ (ys,) outputs $=$ [Variable(as_array(y)) for y in ys] if Configenable_backprop: self_generation $=$ max([x_generation for x in inputs]) #②创建连接 for output in outputs: output.set creator(self) selfinputs $=$ inputs self.output $=$ [weakref.ref(output) for output in outputs] return outputs if lenoutputs) $>1$ else outputs[0]①处通过xs = [x.data for x in inputs]提取Variable的实例变量data,并将其汇总在列表xs中,然后调用forward(*xs)进行具体的计算。
接下来是②的部分。这部分创建了Variable和Function之间的连接。从变量到函数的连接是通过set creator方法实现的。它的原理是让新创建的Variable记住它的父函数(自己)。同时,通过将函数的输入变量和输出变量赋给inputs和outputs的实例变量,保持从函数到变量的连接。

在变量和函数之间建立连接是为了之后反向传播导数。DeZero在计算发生时动态地创建了这种连接。
DeZero中的函数都继承自Function类。继承了Function的类需要在forward方法中实现具体计算。下面是Sin类中进行sin函数计算的代码。
class Sin(Function): def forward(self, x): y = np.sin(x) return y def backward(self, gy): x = self.inputs[0].data gx = gy * np.cos(x) return gx代码中的forward方法的参数和返回值都是ndarray实例。同样,backward方法的参数和返回值也都是ndarray实例。使用Sin类可以进行以下计算。
def $\sin (\mathbf{x})$ return Sin()x
$\mathrm{x} =$ Variable(np.array(1.0))
y $=$ sin(x)上面的代码只进行了sin函数的正向传播。图30-3展示了此时变量和函数的“活动”可视化后的样子。

图30-3 的计算图(仅正向传播)
如图30-3所示,在正向传播中,具体的计算在Sin类的forward方法中进行。由此便产生了变量和函数之间的连接。再提示一遍,这个连接是在Function类的__call__方法中创建的。