45.1_扩展Layer类

45.1 扩展Layer类

当前的Layer类可以持有多个Parameter。这里进一步扩展Layer类,使其也可以持有其他的Layer。它们之间的关系如图45-1所示。

Layer

Parameter

Parameter

Layer

Parameter

Parameter

Layer

Parameter

图45-1 新的Layer类

如图45-1所示,Layer中可以容纳其他的Layer。也就是说,这是一个嵌套结构。本步骤的目标是从图45-1最上层的Layer中取出所有的参数。为此我们要将当前的Layer类修改成下面这样。

dezero/layers.py

class Layer: def__init__(self): self._params  $\equiv$  set()   
def__setattr__(self,name,value): ifisinstance(value,(Parameter,Layer)):  $①$  再增加Layer self._params.add(name) super().__setattr__(name,value)   
def params(self): for name in self._params: obj  $=$  self._dict_[name] ifisinstance(obj,Layer):  $②$  从Layer取出参数 yield from obj.params() else: yield obj

第1个变化是在设置实例变量时将Layer实例的名称也添加到.params。这样,Parameter和Layer实例的名称就被添加到.params中。

第2个变化发生在取出参数的处理上。params方法从.params中取出name(字符串),然后根据name将name对应的对象作为obj取出。如果obj是Layer实例,则继续调用obj.params()。这样就能从Layer的Layer中递归取出参数了。

使用yield的函数叫作生成器。我们可以通过yield from来使用一个生成器创建另一个新的生成器。yield from是Python 3.3中引入的功能。

这样就完成了新的Layer类。使用这个Layer类可以按如下方式实现神经网络。

importdezero.layersasL   
importdezero-functionsasF   
fromdezero import Layer   
model  $=$  Layer()   
model.l1  $=$  L.Linear(5) #只指定输出大小   
model.l2  $=$  L.Linear(3)   
#进行推理的函数   
defpredict(model,x): y  $=$  model.l1(x) y  $=$  F.sigmoid(y) y  $=$  model.l2(y) returny   
#访问所有参数   
forp in model.params(): print(p)   
#重置所有参数的梯度   
model.cleargrads()

上面的代码使用model = Layer()创建了实例,然后向model增加了作为实例变量的Linear实例。这样,执行推理的函数就可以实现为predict(model, x)。这里重要的一点是我们能够通过model.params()访问model中存在的所有参数。此外,model.cleargrads()可以重置所有参数的梯度。像这样,我们可以使用Layer类来统一管理神经网络中使用的所有参数。

除了上面的方法,还有更便捷的方法可以使用Layer类。具体来说,就是将模型定义为一个继承Layer类的“类”。代码如下所示。

class TwoLayerNet(Layer): def__init__(self,hidden_size,out_size): super().__init__(self.l1  $=$  L.Linear(hiden_size) self.l2  $=$  L.Linear(out_size) defforward(self,x): y  $=$  F.sigmoid(self.l1(x)) y  $=$  self.l2(y) returny

上面的代码定义了一个类名为TwoLayerNet的模型。该类继承于Layer,并实现了__init__和forward方法。__init__方法创建了需要使用的Layer,并使用self.l1 = ...进行了设置。而在forward方法中,我们编写了执行推理的代码。这样就能将神经网络的代码整合到TwoLayerNet这一个类中。

这里展示的采用面向对象的方式定义模型的做法(也就是把模型以类为单位进行整合)出自于Chainer框架。这种做法后来常用在PyTorch和TensorFlow等框架中。