671 字
3 分钟
深度神经网络-层和块
层和块
深度神经网络由许多神经网络层组成,每一层都可以看作处理或提取出某一种特征。
为了整合多个层,我们可以定义一个块来包括一些紧密联系的层。
例如:nn.Linear()
就会生成一个线性模型层
自定义块
假设我们要实现一个MLP(多层感知机)的模块,这个MLP中包含一个20*20的线性层和256*256的层.
块的基本构成:
- 有输入
- 通过前向传播函数,经过多个传播层,得到输出。自定义添加隐藏层。
- 计算输入关于输出的梯度,可以使用反向传播算法。
- 存储和访问前向传播计算的参数,
forward()
函数 - 根据需要初始化模型参数
__init__()
函数
class MLP(nn.Block): # 用模型参数声明层。这里,我们声明两个全连接的层 def __init__(self, **kwargs): # 调用MLP的父类Block的构造函数来执行必要的初始化。 # 这样,在类实例化时也可以指定其他函数参数,例如模型参数params(稍后将介绍) super().__init__(**kwargs) self.hidden = nn.Dense(256, activation='relu') # 隐藏层 self.out = nn.Dense(10) # 输出层
# 定义模型的前向传播,即如何根据输入X返回所需的模型输出 def forward(self, X): return self.out(self.hidden(X))
顺序快
pytorch定义了Module类,来表示模型块。
我们可以自定义函数,来向Module中添加自定义的隐藏层。
class MySequential(nn.Module): def __init__(self, *args): super().__init__() for idx, module in enumerate(args): # 这里,module是Module子类的一个实例。我们把它保存在'Module'类的成员 # 变量_modules中。_module的类型是OrderedDict self._modules[str(idx)] = module
""" 通过add(block),给顺序块中加入多个隐藏层
计算梯度时,逐个调用这些隐藏层,得到输出。 """
def forward(self, X): # OrderedDict保证了按照成员添加的顺序遍历它们 for block in self._modules.values(): X = block(X) return X
自定义前向传播函数
在前向传播函数forward()
中,我们可以添加额外的运算操作。
class FixedHiddenMLP(nn.Module): def __init__(self): super().__init__() # 不计算梯度的随机权重参数。因此其在训练期间保持不变 self.rand_weight = torch.rand((20, 20), requires_grad=False) self.linear = nn.Linear(20, 20)
""" nn.Linear()会自动正则化初始参数。
在forward前向传播函数中,我们可以自定义额外的运算
比如添加relu激活函数。 """
def forward(self, X): X = self.linear(X) # 使用创建的常量参数以及relu和mm函数 X = F.relu(torch.mm(X, self.rand_weight) + 1) # 复用全连接层。这相当于两个全连接层共享参数 X = self.linear(X)
# 控制流,下面这段没有实际意义。 while X.abs().sum() > 1: X /= 2 return X.sum()