深度学习计算
一、层和块
块可以描述单个层、多个层组成的组件或整个模型。
通过定义块,组装块,可以实现复杂的神经网络。
一个块可以由多个class组成。
其实就是
自己定义神经网络net,自己定义层的顺序和具体的init、
forward函数。
层和块的顺序由sequential处理。
eg:
class MLP(
nn
.
Module):
# 这里只要继承了就可以实例化为一个层
# 用模型参数声明层。这里,我们声明两个全连接的层
def __init__(self):
#
调用MLP的父类Module的构造函数来执行必要的参数初始化。
即hidden和out的参数会自动生成。
# 这样,在类实例化时也可以指定其他函数参数,例如模型参数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)))
&
自己定义网络中的层
一般是在init里定义层,在forward里定义参数的传递
即输出的内容
。
# 手搓一个sequential类
class MySequential(nn.Module):
def __init__(self, *args):
super().__init__()
for idx, module in enumerate(args):
# 这里,module是Module子类的一个实例。我们把它保存在'Module'类的成员
# 变量_modules中。_module的类型是OrderedDict
# _modules的优点是,在模块的参数初始化过程中,系统会在里面查找需要初始化参数的子块。
self._modules[str(idx)] = module
def forward(self, X):
# OrderedDict保证了按照成员添加的顺序遍历它们
for block in self._modules.values():
X = block(X)
return X
net =
MySequential
(nn.Linear(
20,
256
), nn.ReLU(), nn.Linear(
256
,
10
))
&
为了更强的灵活性,我们想将自己定义的块加入模型中。
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)
class
NestMLP(nn.Module):
def __init__(self):
super().__init__()
self.net = nn.Sequential(nn.Linear(20, 64), nn.ReLU(),
nn.Linear(64, 32), nn.ReLU())
self.linear = nn.Linear(32, 16)
def forward(self, X):
return
self.linear(self.net(X)) #骚操作
chimera =
nn.Sequential(NestMLP(), nn.Linear(16, 20), FixedHiddenMLP())
二、保存模型参数
torch.
save(
net
.state_dict(), 'mlp.params') #保存参数
clone = MLP()
clone.load_state_dict(torch.load('mlp.params')) #复用参数
clone.eval()