在 PyTorch 中保存经过训练的模型的最佳方式?
Best way to save a trained model in PyTorch?
我正在寻找在 PyTorch 中保存经过训练的模型的替代方法。到目前为止,我找到了两个替代方案。
- torch.save() to save a model and torch.load() 加载模型。
- model.state_dict() to save a trained model and model.load_state_dict()加载保存的模型。
我遇到过这个 discussion 建议使用方法 2 而不是方法 1。
我的问题是,为什么第二种方法更受欢迎?难道只是因为 torch.nn 模块有这两个功能而鼓励我们使用它们吗?
在他们的 github 仓库中找到 this page,我将把内容复制粘贴到这里。
保存模型的推荐方法
序列化和恢复模型有两种主要方法。
第一种(推荐)只保存和加载模型参数:
torch.save(the_model.state_dict(), PATH)
然后:
the_model = TheModelClass(*args, **kwargs)
the_model.load_state_dict(torch.load(PATH))
第二次保存并加载整个模型:
torch.save(the_model, PATH)
然后:
the_model = torch.load(PATH)
但是在这种情况下,序列化数据绑定到特定 类
以及使用的确切目录结构,因此它可以以各种方式中断
在其他项目中使用,或者在一些严重的重构之后。
更新:另请参阅 PyTorch 教程中的 Save and Load the Model 部分
这取决于你想做什么。
案例#1:保存模型自己用于推理:保存模型,恢复模型,然后将模型更改为评估模式。这样做是因为您通常有 BatchNorm
和 Dropout
层,它们在构造时默认处于训练模式:
torch.save(model.state_dict(), filepath)
#Later to restore:
model.load_state_dict(torch.load(filepath))
model.eval()
案例#2:保存模型稍后恢复训练:如果你需要继续训练你即将保存的模型,你需要保存的不仅仅是模型.您还需要保存优化器的状态、时期、分数等。您可以这样做:
state = {
'epoch': epoch,
'state_dict': model.state_dict(),
'optimizer': optimizer.state_dict(),
...
}
torch.save(state, filepath)
要恢复训练,您可以执行以下操作:state = torch.load(filepath)
,然后,恢复每个单独对象的状态,操作如下:
model.load_state_dict(state['state_dict'])
optimizer.load_state_dict(state['optimizer'])
由于您正在恢复训练,一旦您在加载时恢复状态,请勿调用model.eval()
。
案例 #3:模型被无法访问您的代码的其他人使用:
在 Tensorflow 中,您可以创建一个 .pb
文件来定义模型的架构和权重。这非常方便,特别是在使用 Tensorflow serve
时。在 Pytorch 中执行此操作的等效方法是:
torch.save(model, filepath)
# Then later:
model = torch.load(filepath)
这种方法仍然不是防弹的,并且由于 pytorch 仍在进行大量更改,因此我不推荐它。
pickle Python 库实现了用于序列化和反序列化 Python 对象的二进制协议。
当你import torch
(或者当你使用 PyTorch 时)它会为你 import pickle
而你不需要直接调用 pickle.dump()
和 pickle.load()
,这是保存和加载对象的方法。
事实上,torch.save()
和 torch.load()
将为您包装 pickle.dump()
和 pickle.load()
。
A state_dict
提到的另一个答案值得再做一些说明。
我们在 PyTorch 中有什么state_dict
?
实际上有两个state_dict
。
PyTorch 模型是 torch.nn.Module
,它有 model.parameters()
调用来获取可学习的参数(w 和 b)。
这些可学习的参数一旦随机设置,就会随着我们学习的时间而更新。
可学习的参数是第一个 state_dict
.
第二个state_dict
是优化器状态字典。您还记得优化器用于改进我们的可学习参数。但是优化器 state_dict
是固定的。那里没什么可学的。
因为 state_dict
对象是 Python 字典,它们可以很容易地保存、更新、更改和恢复,从而为 PyTorch 模型和优化器增加了大量的模块化。
让我们创建一个超级简单的模型来解释这一点:
import torch
import torch.optim as optim
model = torch.nn.Linear(5, 2)
# Initialize optimizer
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
print("Model's state_dict:")
for param_tensor in model.state_dict():
print(param_tensor, "\t", model.state_dict()[param_tensor].size())
print("Model weight:")
print(model.weight)
print("Model bias:")
print(model.bias)
print("---")
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:
weight torch.Size([2, 5])
bias torch.Size([2])
Model weight:
Parameter containing:
tensor([[ 0.1328, 0.1360, 0.1553, -0.1838, -0.0316],
[ 0.0479, 0.1760, 0.1712, 0.2244, 0.1408]], requires_grad=True)
Model bias:
Parameter containing:
tensor([ 0.4112, -0.0733], requires_grad=True)
---
Optimizer's state_dict:
state {}
param_groups [{'lr': 0.001, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False, 'params': [140695321443856, 140695321443928]}]
请注意,这是一个最小模型。您可以尝试添加 stack of sequential
model = torch.nn.Sequential(
torch.nn.Linear(D_in, H),
torch.nn.Conv2d(A, B, C)
torch.nn.Linear(H, D_out),
)
请注意,只有具有可学习参数的层(卷积层、线性层等)和注册缓冲区(batchnorm 层)在模型的 state_dict
.
中有条目
不可学习的东西属于优化器对象state_dict
,它包含有关优化器状态的信息,以及使用的超参数。
故事的其余部分是一样的;在推理阶段(这是我们在训练后使用模型的阶段)进行预测;我们确实根据我们学到的参数进行预测。所以为了推断,我们只需要保存参数model.state_dict()
.
torch.save(model.state_dict(), filepath)
稍后使用
model.load_state_dict(torch.load(文件路径))
model.eval()
注意:不要忘记最后一行model.eval()
这是加载模型后的关键。
也不要试图保存 torch.save(model.parameters(), filepath)
。 model.parameters()
只是生成器对象。
另一方面,torch.save(model, filepath)
保存模型对象本身,但请记住模型没有优化器的 state_dict
。查看@Jadiel de Armas 的其他优秀答案以保存优化器的状态字典。
一个常见的 PyTorch 约定是使用 .pt 或 .pth 文件扩展名保存模型。
Save/Load 整个模型
保存:
path = "username/directory/lstmmodelgpu.pth"
torch.save(trainer, path)
加载:
(模型 class 必须在某处定义)
model.load_state_dict(torch.load(PATH))
model.eval()
如果您想保存模型并希望稍后恢复训练:
单 GPU:
保存:
state = {
'epoch': epoch,
'state_dict': model.state_dict(),
'optimizer': optimizer.state_dict(),
}
savepath='checkpoint.t7'
torch.save(state,savepath)
加载:
checkpoint = torch.load('checkpoint.t7')
model.load_state_dict(checkpoint['state_dict'])
optimizer.load_state_dict(checkpoint['optimizer'])
epoch = checkpoint['epoch']
多 GPU:
保存
state = {
'epoch': epoch,
'state_dict': model.module.state_dict(),
'optimizer': optimizer.state_dict(),
}
savepath='checkpoint.t7'
torch.save(state,savepath)
加载:
checkpoint = torch.load('checkpoint.t7')
model.load_state_dict(checkpoint['state_dict'])
optimizer.load_state_dict(checkpoint['optimizer'])
epoch = checkpoint['epoch']
#Don't call DataParallel before loading the model otherwise you will get an error
model = nn.DataParallel(model) #ignore the line if you want to load on Single GPU
Saving locally
您如何保存您的模型取决于您希望将来如何访问它。如果您可以调用 model
class 的新实例,那么您需要做的就是 save/load 具有 model.state_dict()
的模型的权重:
# Save:
torch.save(old_model.state_dict(), PATH)
# Load:
new_model = TheModelClass(*args, **kwargs)
new_model.load_state_dict(torch.load(PATH))
如果您出于某种原因不能(或更喜欢更简单的语法),那么您可以保存整个模型(实际上是对定义模型的文件的引用,以及它的state_dict) torch.save()
:
# Save:
torch.save(old_model, PATH)
# Load:
new_model = torch.load(PATH)
但由于这是对定义模型的文件位置的引用 class,此代码不可移植,除非这些文件也移植到相同的目录结构中。
保存到云端 - TorchHub
如果您希望您的模型可以移植,可以使用 torch.hub
轻松导入它。如果您将适当定义的 hubconf.py
文件添加到 github 存储库,则可以从 PyTorch 中轻松调用它以使用户能够加载您的模型 with/without 权重:
hubconf.py
(github.com/repo_owner/repo_name)
dependencies = ['torch']
from my_module import mymodel as _mymodel
def mymodel(pretrained=False, **kwargs):
return _mymodel(pretrained=pretrained, **kwargs)
正在加载模型:
new_model = torch.hub.load('repo_owner/repo_name', 'mymodel')
new_model_pretrained = torch.hub.load('repo_owner/repo_name', 'mymodel', pretrained=True)
这几天都写在官方教程里了:
https://pytorch.org/tutorials/beginner/saving_loading_models.html
关于如何保存和保存什么,您有多种选择,所有内容都在该教程中进行了说明。
pip 安装 pytorch-lightning
确保您的父模型使用 pl.LightningModule 而不是 nn.Module
Saving and loading checkpoints using pytorch lightning
import pytorch_lightning as pl
model = MyLightningModule(hparams)
trainer.fit(model)
trainer.save_checkpoint("example.ckpt")
new_model = MyModel.load_from_checkpoint(checkpoint_path="example.ckpt")
我总是喜欢使用 Torch7 (.t7) 或 Pickle (.pth, .pt) 来保存 pytorch 模型权重。
我正在寻找在 PyTorch 中保存经过训练的模型的替代方法。到目前为止,我找到了两个替代方案。
- torch.save() to save a model and torch.load() 加载模型。
- model.state_dict() to save a trained model and model.load_state_dict()加载保存的模型。
我遇到过这个 discussion 建议使用方法 2 而不是方法 1。
我的问题是,为什么第二种方法更受欢迎?难道只是因为 torch.nn 模块有这两个功能而鼓励我们使用它们吗?
在他们的 github 仓库中找到 this page,我将把内容复制粘贴到这里。
保存模型的推荐方法
序列化和恢复模型有两种主要方法。
第一种(推荐)只保存和加载模型参数:
torch.save(the_model.state_dict(), PATH)
然后:
the_model = TheModelClass(*args, **kwargs)
the_model.load_state_dict(torch.load(PATH))
第二次保存并加载整个模型:
torch.save(the_model, PATH)
然后:
the_model = torch.load(PATH)
但是在这种情况下,序列化数据绑定到特定 类 以及使用的确切目录结构,因此它可以以各种方式中断 在其他项目中使用,或者在一些严重的重构之后。
更新:另请参阅 PyTorch 教程中的 Save and Load the Model 部分
这取决于你想做什么。
案例#1:保存模型自己用于推理:保存模型,恢复模型,然后将模型更改为评估模式。这样做是因为您通常有 BatchNorm
和 Dropout
层,它们在构造时默认处于训练模式:
torch.save(model.state_dict(), filepath)
#Later to restore:
model.load_state_dict(torch.load(filepath))
model.eval()
案例#2:保存模型稍后恢复训练:如果你需要继续训练你即将保存的模型,你需要保存的不仅仅是模型.您还需要保存优化器的状态、时期、分数等。您可以这样做:
state = {
'epoch': epoch,
'state_dict': model.state_dict(),
'optimizer': optimizer.state_dict(),
...
}
torch.save(state, filepath)
要恢复训练,您可以执行以下操作:state = torch.load(filepath)
,然后,恢复每个单独对象的状态,操作如下:
model.load_state_dict(state['state_dict'])
optimizer.load_state_dict(state['optimizer'])
由于您正在恢复训练,一旦您在加载时恢复状态,请勿调用model.eval()
。
案例 #3:模型被无法访问您的代码的其他人使用:
在 Tensorflow 中,您可以创建一个 .pb
文件来定义模型的架构和权重。这非常方便,特别是在使用 Tensorflow serve
时。在 Pytorch 中执行此操作的等效方法是:
torch.save(model, filepath)
# Then later:
model = torch.load(filepath)
这种方法仍然不是防弹的,并且由于 pytorch 仍在进行大量更改,因此我不推荐它。
pickle Python 库实现了用于序列化和反序列化 Python 对象的二进制协议。
当你import torch
(或者当你使用 PyTorch 时)它会为你 import pickle
而你不需要直接调用 pickle.dump()
和 pickle.load()
,这是保存和加载对象的方法。
事实上,torch.save()
和 torch.load()
将为您包装 pickle.dump()
和 pickle.load()
。
A state_dict
提到的另一个答案值得再做一些说明。
我们在 PyTorch 中有什么state_dict
?
实际上有两个state_dict
。
PyTorch 模型是 torch.nn.Module
,它有 model.parameters()
调用来获取可学习的参数(w 和 b)。
这些可学习的参数一旦随机设置,就会随着我们学习的时间而更新。
可学习的参数是第一个 state_dict
.
第二个state_dict
是优化器状态字典。您还记得优化器用于改进我们的可学习参数。但是优化器 state_dict
是固定的。那里没什么可学的。
因为 state_dict
对象是 Python 字典,它们可以很容易地保存、更新、更改和恢复,从而为 PyTorch 模型和优化器增加了大量的模块化。
让我们创建一个超级简单的模型来解释这一点:
import torch
import torch.optim as optim
model = torch.nn.Linear(5, 2)
# Initialize optimizer
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
print("Model's state_dict:")
for param_tensor in model.state_dict():
print(param_tensor, "\t", model.state_dict()[param_tensor].size())
print("Model weight:")
print(model.weight)
print("Model bias:")
print(model.bias)
print("---")
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:
weight torch.Size([2, 5])
bias torch.Size([2])
Model weight:
Parameter containing:
tensor([[ 0.1328, 0.1360, 0.1553, -0.1838, -0.0316],
[ 0.0479, 0.1760, 0.1712, 0.2244, 0.1408]], requires_grad=True)
Model bias:
Parameter containing:
tensor([ 0.4112, -0.0733], requires_grad=True)
---
Optimizer's state_dict:
state {}
param_groups [{'lr': 0.001, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False, 'params': [140695321443856, 140695321443928]}]
请注意,这是一个最小模型。您可以尝试添加 stack of sequential
model = torch.nn.Sequential(
torch.nn.Linear(D_in, H),
torch.nn.Conv2d(A, B, C)
torch.nn.Linear(H, D_out),
)
请注意,只有具有可学习参数的层(卷积层、线性层等)和注册缓冲区(batchnorm 层)在模型的 state_dict
.
不可学习的东西属于优化器对象state_dict
,它包含有关优化器状态的信息,以及使用的超参数。
故事的其余部分是一样的;在推理阶段(这是我们在训练后使用模型的阶段)进行预测;我们确实根据我们学到的参数进行预测。所以为了推断,我们只需要保存参数model.state_dict()
.
torch.save(model.state_dict(), filepath)
稍后使用 model.load_state_dict(torch.load(文件路径)) model.eval()
注意:不要忘记最后一行model.eval()
这是加载模型后的关键。
也不要试图保存 torch.save(model.parameters(), filepath)
。 model.parameters()
只是生成器对象。
另一方面,torch.save(model, filepath)
保存模型对象本身,但请记住模型没有优化器的 state_dict
。查看@Jadiel de Armas 的其他优秀答案以保存优化器的状态字典。
一个常见的 PyTorch 约定是使用 .pt 或 .pth 文件扩展名保存模型。
Save/Load 整个模型
保存:
path = "username/directory/lstmmodelgpu.pth"
torch.save(trainer, path)
加载:
(模型 class 必须在某处定义)
model.load_state_dict(torch.load(PATH))
model.eval()
如果您想保存模型并希望稍后恢复训练:
单 GPU: 保存:
state = {
'epoch': epoch,
'state_dict': model.state_dict(),
'optimizer': optimizer.state_dict(),
}
savepath='checkpoint.t7'
torch.save(state,savepath)
加载:
checkpoint = torch.load('checkpoint.t7')
model.load_state_dict(checkpoint['state_dict'])
optimizer.load_state_dict(checkpoint['optimizer'])
epoch = checkpoint['epoch']
多 GPU: 保存
state = {
'epoch': epoch,
'state_dict': model.module.state_dict(),
'optimizer': optimizer.state_dict(),
}
savepath='checkpoint.t7'
torch.save(state,savepath)
加载:
checkpoint = torch.load('checkpoint.t7')
model.load_state_dict(checkpoint['state_dict'])
optimizer.load_state_dict(checkpoint['optimizer'])
epoch = checkpoint['epoch']
#Don't call DataParallel before loading the model otherwise you will get an error
model = nn.DataParallel(model) #ignore the line if you want to load on Single GPU
Saving locally
您如何保存您的模型取决于您希望将来如何访问它。如果您可以调用 model
class 的新实例,那么您需要做的就是 save/load 具有 model.state_dict()
的模型的权重:
# Save:
torch.save(old_model.state_dict(), PATH)
# Load:
new_model = TheModelClass(*args, **kwargs)
new_model.load_state_dict(torch.load(PATH))
如果您出于某种原因不能(或更喜欢更简单的语法),那么您可以保存整个模型(实际上是对定义模型的文件的引用,以及它的state_dict) torch.save()
:
# Save:
torch.save(old_model, PATH)
# Load:
new_model = torch.load(PATH)
但由于这是对定义模型的文件位置的引用 class,此代码不可移植,除非这些文件也移植到相同的目录结构中。
保存到云端 - TorchHub
如果您希望您的模型可以移植,可以使用 torch.hub
轻松导入它。如果您将适当定义的 hubconf.py
文件添加到 github 存储库,则可以从 PyTorch 中轻松调用它以使用户能够加载您的模型 with/without 权重:
hubconf.py
(github.com/repo_owner/repo_name)
dependencies = ['torch']
from my_module import mymodel as _mymodel
def mymodel(pretrained=False, **kwargs):
return _mymodel(pretrained=pretrained, **kwargs)
正在加载模型:
new_model = torch.hub.load('repo_owner/repo_name', 'mymodel')
new_model_pretrained = torch.hub.load('repo_owner/repo_name', 'mymodel', pretrained=True)
这几天都写在官方教程里了: https://pytorch.org/tutorials/beginner/saving_loading_models.html
关于如何保存和保存什么,您有多种选择,所有内容都在该教程中进行了说明。
pip 安装 pytorch-lightning
确保您的父模型使用 pl.LightningModule 而不是 nn.Module
Saving and loading checkpoints using pytorch lightning
import pytorch_lightning as pl
model = MyLightningModule(hparams)
trainer.fit(model)
trainer.save_checkpoint("example.ckpt")
new_model = MyModel.load_from_checkpoint(checkpoint_path="example.ckpt")
我总是喜欢使用 Torch7 (.t7) 或 Pickle (.pth, .pt) 来保存 pytorch 模型权重。