保存和加载模型
关于保存和加载模型,有三个核心功能需要熟悉:
什么是state_dict
?
在PyTorch中,模型的可学习参数(即权重和偏差) torch.nn.Module
包含在模型的参数中 (通过访问model.parameters()
)state_dict是一个简单的Python字典对象,每个层映射到其参数张量。请注意,只有具有可学习参数的层(卷积层,线性层等)和已注册的缓冲区(batchnorm的running_mean)才在模型的state_dict中具有条目。优化器对象(torch.optim
)还具有state_dict,其中包含有关优化器状态以及所用超参数的信息。
由于 state_dict 对象是Python词典,因此可以轻松地保存,更新,更改和还原它们,从而为PyTorch模型和优化器增加了很多模块化。
让我们从训练分类器 教程中使用的简单模型 看一下state_dict。
# Define model
class TheModelClass(nn.Module):
def __init__(self):
super(TheModelClass, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
# Initialize model
model = TheModelClass()
# Initialize optimizer
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
# Print model's state_dict
print("Model's state_dict:")
for param_tensor in model.state_dict():
print(param_tensor, "\t", model.state_dict()[param_tensor].size())
# Print optimizer's state_dict
print("Optimizer's state_dict:")
for var_name in optimizer.state_dict():
print(var_name, "\t", optimizer.state_dict()[var_name])
推理模型的保存和加载
保存/加载state_dict
Save:
torch.save(model.state_dict(), PATH)
Load:
model = TheModelClass(*args, **kwargs)
model.load_state_dict(torch.load(PATH))
整个模型的保存和加载
Save:
torch.save(model, PATH)
Load:
# Model class must be defined somewhere
model = torch.load(PATH)
保存和加载用于推理和/或继续训练的常规检查点
Save:
torch.save({
'epoch': epoch,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'loss': loss,
...
}, PATH)
model = TheModelClass(*args, **kwargs)
optimizer = TheOptimizerClass(*args, **kwargs)
checkpoint = torch.load(PATH)
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
epoch = checkpoint['epoch']
loss = checkpoint['loss']
保存用于检查或继续训练的常规检查点时,您必须保存的不仅仅是模型的 state_dict。保存优化器的state_dict也是很重要的,因为它包含随着模型训练而更新的缓冲区和参数。您可能要保存的其他项目包括您未启用的时期,最新记录的训练损失,外部torch.nn.Embedding
图层等。
要保存多个组件,请将它们组织在字典中并用于 torch.save()序列化字典。常见的PyTorch约定是使用.tar
文件扩展名保存这些检查点。
要加载项目,请首先初始化模型和优化器,然后使用本地加载字典torch.load()
。从这里,您只需按期望查询字典即可轻松访问已保存的项目。
将多个模型保存在一个文件中
Save:
torch.save({
'modelA_state_dict': modelA.state_dict(),
'modelB_state_dict': modelB.state_dict(),
'optimizerA_state_dict': optimizerA.state_dict(),
'optimizerB_state_dict': optimizerB.state_dict(),
...
}, PATH)
Load:
modelA = TheModelAClass(*args, **kwargs)
modelB = TheModelBClass(*args, **kwargs)
optimizerA = TheOptimizerAClass(*args, **kwargs)
optimizerB = TheOptimizerBClass(*args, **kwargs)
checkpoint = torch.load(PATH)
modelA.load_state_dict(checkpoint['modelA_state_dict'])
modelB.load_state_dict(checkpoint['modelB_state_dict'])
optimizerA.load_state_dict(checkpoint['optimizerA_state_dict'])
optimizerB.load_state_dict(checkpoint['optimizerB_state_dict'])
保存由多个模型组成的模型时torch.nn.Modules
,例如GAN,序列到序列模型或模型集成,您将采用与保存常规检查点相同的方法。换句话说,保存每个模型的state_dict和相应的优化器的字典。如前所述,您可以保存任何其他可以帮助您恢复训练的项目,只需将它们添加到字典中即可。
torch.save(modelA.state_dict(), PATH)
modelB = TheModelBClass(*args, **kwargs)
modelB.load_state_dict(torch.load(PATH), strict=False)
在转移学习或训练新的复杂模型时,部分加载模型或加载部分模型是常见方案。利用经过训练的参数,即使只有少数几个可用的参数,也将有助于热启动训练过程,并希望与从头开始训练相比,可以更快地收敛模型。
无论是从缺少某些键的部分state_dict加载,还是要加载比要加载的模型更多的key 的state_dict
,都可以 在函数中将strict参数设置为False,load_state_dict()
以忽略不匹配的键。
如果要将参数从一层加载到另一层,但是某些键不匹配,只需更改要加载的state_dict
中参数键的名称, 以匹配要加载到的模型中的键。
Save:
torch.save(model.state_dict(), PATH)
Load:
device = torch.device('cpu')
model = TheModelClass(*args, **kwargs)
model.load_state_dict(torch.load(PATH, map_location=device))
在使用GPU训练的CPU上加载模型时,将其传递 torch.device('cpu')
给map_location
函数中的 torch.load()
参数。在这种情况下,使用map_location
参数将张量下面的存储动态地重新映射到CPU设备。
Save:
torch.save(model.state_dict(), PATH)
Load:
device = torch.device("cuda")
model = TheModelClass(*args, **kwargs)
model.load_state_dict(torch.load(PATH))
model.to(device)
# Make sure to call input = input.to(device) on any input tensors that you feed to the model
Save:
torch.save(model.state_dict(), PATH)
Load:
device = torch.device("cuda")
model = TheModelClass(*args, **kwargs)
model.load_state_dict(torch.load(PATH, map_location="cuda:0")) # Choose whatever GPU device number you want
model.to(device)
# Make sure to call input = input.to(device) on any input tensors that you feed to the model
更多详情可见https://pytorch.apachecn.org/docs/1.2/beginner/saving_loading_models.html