我们在选择架构和设置了超参数后,就进入训练阶段,我们的目标是找到使损失函数最小化的参数值。经过训练,我们需要使用这些参数作出未来的预测。有时,我么需要提取参数以便在其他环境中复用他们,将模型保存到磁盘,以便在其他软件中可以执行
本节介绍:
1、访问参数,用于调式、诊断和可视化
2、参数初始化
3、在不同模型组建间共享参数
#我们首先关注具有单隐藏层的多层感知机
例子:
import torch from torch import nn net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 1)) X = torch.rand(size=(2, 4))参数访问
可以通过索引来访问模型的任意层。这就像模型是一个列表一样 ,检查第二个全连接层的参数
print(net[2].state_dict())目标参数
从第二个神经网络层提取偏置,提取后返回的是一个参数类实例,并进一步访问该参数的值。
# print(type(net[2].bias)) # print(net[2].bias) # print(net[2].bias.data)
参数是复合的对象,包含值、梯度和额外信息。这就是我们需要显式请求值的原因,除了值之外,我们还可以访问每个参数的梯度。由于我们还没有调用这个网络的反向传播,所以参数的梯度处于初始状态
net[2].weight.grad == None一次性访问所有参数
访问第一个全连接层的参数
print(*[(name, param.shape) for name, param in net[0].named_parameters()])
访问所有层的参数
print(*[(name, param.shape) for name, param in net.named_parameters()])从嵌套块收集参数
先定义一个生成块的的函数,然后将这些块组合到更大的块中
def block1():
return nn.Sequential(nn.Linear(4,8),nn.ReLU(),nn.Linear(8,4),nn.ReLU())
def block2():
net = nn.Sequential()
for i in range(4):
net.add_module(f'block {i}',block1())
return net
regnet = nn.Sequential(block2(),nn.Linear(4,1))
X = torch.rand(size=(2,4))
regnet(X)
查看网络的组织情况
print(rgnet)
可以像访问列表一样访问网络的各层
rgnet[0][1][0].bias.data参数初始化
PyTorch的nn.init模块提供了多种预置初始化方法
内置初始化调用内置初始化器,将所有权重参数初始化为标准差为0.01的高斯随机变量并将偏置参数置0
def init_normal(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, mean=0, std=0.01)
nn.init.zeros_(m.bias)
net.apply(init_normal)
net[0].weight.data[0], net[0].bias.data[0]
所有参数初始化为给定的常数
def init_constant(m):
if type(m) == nn.Linear:
nn.init.constant_(m.weight, 1)
nn.init.zeros_(m.bias)
net.apply(init_constant)
net[0].weight.data[0], net[0].bias.data[0]
对某些块应用不同的初始化方法
def xavier(m):
if type(m) == nn.Linear:
nn.init.xavier_uniform_(m.weight)
def init_42(m):
if type(m) == nn.Linear:
nn.init.constant_(m.weight, 42)
net[0].apply(xavier)
net[2].apply(init_42)
print(net[0].weight.data[0])
print(net[2].weight.data)
自定义初始化
def my_init(m):
if type(m) == nn.Linear:
print("Init", *[(name, param.shape)
for name, param in m.named_parameters()][0])
nn.init.uniform_(m.weight, -10, 10)
m.weight.data *= m.weight.data.abs() >= 5
net.apply(my_init)
net[0].weight[:2]
参数绑定
# 我们需要给共享层一个名称,以便可以引用它的参数。
shared = nn.Linear(8, 8)
net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(),
shared, nn.ReLU(),
shared, nn.ReLU(),
nn.Linear(8, 1))
net(X)
# 检查参数是否相同
print(net[2].weight.data[0] == net[4].weight.data[0])
net[2].weight.data[0, 0] = 100
# 确保它们实际上是同一个对象,而不只是有相同的值。
print(net[2].weight.data[0] == net[4].weight.data[0])
小结
- 我们有几种方法可以访问、初始化和绑定模型参数。
- 我们可以使用自定义初始化方法。
来源:动手学深度学习



