Needle中Module类的作用是将我们在Homework1实现的底层算子组成更高抽象层方便模型搭建,比如抽象Dropout,Residual层。Module作为一个父类,当需要添加一个新的模块层的时候,我们只需要集成这个父类即可。
其重要的函数是__init__ 和forward 函数。
__init__ :用于子类初始化Module的超参数用于训练。forward :子类需要实现该函数,进行当前层的前向计算。下面展示的简单的identity层就是直接返回其自身。class Module:
def __init__(self):
self.training = True
def parameters(self) -> List[Tensor]:
"""Return the list of parameters in the module."""
return _unpack_params(self.__dict__)
def _children(self) -> List["Module"]:
return _child_modules(self.__dict__)
def eval(self):
self.training = False
for m in self._children():
m.training = False
def train(self):
self.training = True
for m in self._children():
m.training = True
def __call__(self, *args, **kwargs):
return self.forward(*args, **kwargs)
一个简单Module子类的forward示例:
class Identity(Module):
def forward(self, x):
return x
在实现代码之前,我们先来看看模型参数(权重)初始化的一些问题。如果你已经熟悉这两种初始化以及他们解决的问题,直接跳过这部分即可。
训练模型的过程是对于模型的参数weights的进行梯度下降,因此模型权重的数值对于训练至关重要。如果我们将模型的权重都初始化为一个常数,比如0,对于训练的模型会出现如下问题:对称性破坏失败,表达能力受限,训练效率低下甚至停滞,容易陷入坏的局部最优。
一个很容易想到的解决方法是随机初始化模型的参数,但仍会遇到一些问题。