保存和加载模型
Posted 浩瀚之水_csdn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了保存和加载模型相关的知识,希望对你有一定的参考价值。
本文档提供了有关 PyTorch 模型保存和加载的各种用例的解决方案。随意阅读整个文档,或者直接跳到所需用例所需的代码。
在保存和加载模型时,需要熟悉三个核心功能:
- torch.save:将序列化对象保存到磁盘。此函数使用 Python 的 pickle实用程序进行序列化。使用此功能可以保存各种对象的模型、张量和字典。
- torch.load:使用pickle的 unpickling 设施将pickle 的目标文件反序列化到内存中。此功能还有助于设备将数据加载到其中(请参阅 跨设备保存和加载模型)。
- torch.nn.Module.load_state_dict:使用反序列化的state_dict加载模型的参数字典 。有关state_dict 的更多信息,请参阅什么是 state_dict?.
内容:
什么是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])
输出:
Model's state_dict:
conv1.weight torch.Size([6, 3, 5, 5])
conv1.bias torch.Size([6])
conv2.weight torch.Size([16, 6, 5, 5])
conv2.bias torch.Size([16])
fc1.weight torch.Size([120, 400])
fc1.bias torch.Size([120])
fc2.weight torch.Size([84, 120])
fc2.bias torch.Size([84])
fc3.weight torch.Size([10, 84])
fc3.bias torch.Size([10])
Optimizer's state_dict:
state {}
param_groups [{'lr': 0.001, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False, 'params': [4675713712, 4675713784, 4675714000, 4675714072, 4675714216, 4675714288, 4675714432, 4675714504, 4675714648, 4675714720]}]
保存和加载模型以进行推理
保存/加载state_dict
(推荐)
节省:
torch.save(model.state_dict(), PATH)
加载:
model = TheModelClass(*args, **kwargs)
model.load_state_dict(torch.load(PATH))
model.eval()
笔记
PyTorch 的 1.6 版本改用torch.save
了一种新的基于 zipfile 的文件格式。torch.load
仍然保留以旧格式加载文件的能力。如果出于任何原因您想torch.save
使用旧格式,请传递 kwarg _use_new_zipfile_serialization=False
。
保存模型进行推理时,只需要保存训练好的模型的学习参数即可。使用该函数保存模型的state_dicttorch.save()
将为您以后恢复模型提供最大的灵活性,这就是为什么它是保存模型的推荐方法。
一个常见的 PyTorch 约定是使用.pt
或 .pth
文件扩展名保存模型。
请记住,model.eval()
在运行推理之前,您必须调用将 dropout 和批处理规范化层设置为评估模式。不这样做会产生不一致的推理结果。
笔记
请注意,该load_state_dict()
函数采用字典对象,而不是保存对象的路径。这意味着您必须在将保存的state_dict传递给load_state_dict()
函数之前反序列化它 。例如,您不能使用 model.load_state_dict(PATH)
.
笔记
如果您只打算保留性能最佳的模型(根据获得的验证损失),请不要忘记 返回对状态的引用而不是其副本!您必须序列化 或使用,否则您将在后续的训练迭代中不断更新。因此,最终的模型状态将是过拟合模型的状态。best_model_state = model.state_dict()
best_model_state
best_model_state = deepcopy(model.state_dict())
best_model_state
保存/加载整个模型
节省:
torch.save(model, PATH)
加载:
# Model class must be defined somewhere
model = torch.load(PATH)
model.eval()
这个保存/加载过程使用最直观的语法并且涉及最少的代码。以这种方式保存模型将使用 Python 的pickle模块保存整个 模块。这种方法的缺点是序列化的数据绑定到特定的类和保存模型时使用的确切目录结构。这样做的原因是 pickle 不保存模型类本身。相反,它保存包含类的文件的路径,该路径在加载时使用。因此,您的代码在其他项目中使用或在重构后可能会以各种方式中断。
一个常见的 PyTorch 约定是使用.pt
或 .pth
文件扩展名保存模型。
请记住,model.eval()
在运行推理之前,您必须调用将 dropout 和批处理规范化层设置为评估模式。不这样做会产生不一致的推理结果。
保存和加载用于推理和/或恢复训练的通用检查点
节省:
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']
model.eval()
# - or -
model.train()
保存一般检查点以用于推理或恢复训练时,您必须保存的不仅仅是模型的 state_dict。保存优化器的state_dict也很重要,因为它包含在模型训练时更新的缓冲区和参数。您可能想要保存的其他项目是您离开的 epoch、最新记录的训练损失、外部torch.nn.Embedding
层等。因此,这样的检查点通常比单独的模型大 2~3 倍。
要保存多个组件,请将它们组织在一个字典中并使用 torch.save()
序列化该字典。一个常见的 PyTorch 约定是使用.tar
文件扩展名保存这些检查点。
要加载项目,首先初始化模型和优化器,然后使用torch.load()
. 从这里,您可以通过简单地按预期查询字典来轻松访问保存的项目。
请记住,model.eval()
在运行推理之前,您必须调用将 dropout 和批处理规范化层设置为评估模式。不这样做会产生不一致的推理结果。如果您希望恢复训练,请致电model.train()
以确保这些层处于训练模式。
在一个文件中保存多个模型
节省:
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)
加载:
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'])
modelA.eval()
modelB.eval()
# - or -
modelA.train()
modelB.train()
保存由多个torch.nn.Modules
. 换句话说,保存每个模型的state_dict和相应优化器的字典。如前所述,您可以通过简单地将任何其他项目附加到字典中来保存可能有助于您恢复训练的任何其他项目。
一个常见的 PyTorch 约定是使用.tar
文件扩展名保存这些检查点 。
要加载模型,首先初始化模型和优化器,然后使用torch.load()
. 从这里,您可以通过简单地按预期查询字典来轻松访问保存的项目。
请记住,model.eval()
在运行推理之前,您必须调用将 dropout 和批处理规范化层设置为评估模式。不这样做会产生不一致的推理结果。如果您希望恢复训练,请调用model.train()
将这些层设置为训练模式。
使用来自不同模型的参数的热启动模型
节省:
torch.save(modelA.state_dict(), PATH)
加载:
modelB = TheModelBClass(*args, **kwargs)
modelB.load_state_dict(torch.load(PATH), strict=False)
部分加载模型或加载部分模型是迁移学习或训练新的复杂模型时的常见场景。利用经过训练的参数,即使只有少数可用,也将有助于热启动训练过程,并有望帮助您的模型比从头开始训练更快地收敛。
无论您是从缺少某些键的部分state_dict加载,还是加载具有比加载到的模型更多键的state_dict,您都可以 在函数中将strict
参数设置为Falseload_state_dict()
以忽略不匹配的键。
如果要将参数从一层加载到另一层,但某些键不匹 以上是关于保存和加载模型的主要内容,如果未能解决你的问题,请参考以下文章