沐神文章与代码链接:
https://zh-v2.d2l.ai/chapter_deep-learning-computation/model-construction.html#id3
1.块是什么:
一个“块”可能指的是一系列层的组合
2.块的功能:
1. 将输入数据作为其前向传播函数的参数。
2. 通过前向传播函数来生成输出。请注意,输出的形状可能与输入的形状不同。例如,我们上面模型中的第一个全连接的层接收任意维的输入,但是返回一个维度256的输出。
3. 计算其输出关于输入的梯度,可通过其反向传播函数进行访问。通常这是自动发生的。
4. 存储和访问前向传播计算所需的参数。
5. 根据需要初始化模型参数
3.定义块的步骤:
1.定义构造函数---初始化各种层和参数
2.定义前向传播函数---神经网络通过前向传播函数来定义数据如何在网络中流动。
代码解析1:
class MLP(nn.Module):
# 用模型参数声明层。这里,我们声明两个全连接的层
def __init__(self):
# 调用MLP的父类Module的构造函数来执行必要的初始化。
# 这样,在类实例化时也可以指定其他函数参数,例如模型参数params(稍后将介绍)
super().__init__()
self.hidden = nn.Linear(20, 256) # 隐藏层
self.out = nn.Linear(256, 10) # 输出层
# 定义模型的前向传播,即如何根据输入X返回所需的模型输出
def forward(self, X):
# 注意,这里我们使用ReLU的函数版本,其在nn.functional模块中定义。
return self.out(F.relu(self.hidden(X)))
X=torch.rand(1,20)
net = MLP()
net(X)
net=MLP()时
1.启动__init__函数
1.1 启动super().__init__(),负责基础的初始化
1.2 定义两个层 self.hidden self.out
net(X)时
2.调用forward函数
将输入X传给self.hidden
将self.hidden的输出传给self.out
注意:
1.F.relu()=torch.nn.functional.relu()
2.在定义两个层是就对层的参数进行了默认的初始化策略 (如果想要更改初始化策略需要,新创建一个初始化函数然后应用 如下)
#使用Xavier均匀初始化方法初始化权重,使用零初始化方法初始化偏置
def init_weights(m):
if type(m) == nn.Linear:
init.xavier_uniform_(m.weight)
init.zeros_(m.bias) # 应用初始化函数
net.apply(init_weights)
代码解析2:
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)
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()
X=torch.rand(1,20)
net = FixedHiddenMLP()
net(X)
如何理解:定义块的目的:便是可以在多个层之间加上灵活的处理
__init__
1.self.rand_weight = torch.rand((20, 20), requires_grad=False)创建了一个20x20的矩阵,且做了随机初始化之后,规定该矩阵的值不会变化
2.定义了线性层
__forward__
通过定义块定义了类似于(但下面的代码肯定是不可行的)
X=Sequential(Linear(20,20),F.relu(torch.mm(X, self.rand_weight) + 1),Linear(20,20))
while X.abs().sum() >1:
x/=2
retun X.sum()