查看: 117|回复: 10

Pytorch格式 .pt .pth .bin 详解

[复制链接]

3

主题

13

帖子

22

积分

新手上路

Rank: 1

积分
22
发表于 2023-7-21 10:02:38 | 显示全部楼层 |阅读模式
非常感谢评论区知友的指正,现在已经更新了文章,更新时间:2023/04/14
---------------------分割线-----------------------
Pytorch是深度学习领域中非常流行的框架之一,支持的模型保存格式包括.pt和.pth .bin .onnx。这几种格式的文件都可以保存Pytorch训练出的模型,但是它们的区别是什么呢?
模型的保存与加载到底在做什么?

我们在使用pytorch构建模型并且训练完成后,下一步要做的就是把这个模型放到实际场景中应用,或者是分享给其他人学习、研究、使用。因此,我们开始思考一个问题,提供哪些模型信息,能够让对方能够完全复现我们的模型?

  • 模型代码

    • (1)包含了我们如何定义模型的结构,包括模型有多少层/每层有多少神经元等等信息;
    • (2)包含了我们如何定义的训练过程,包括epoch batch_size等参数;
    • (3)包含了我们如何加载数据和使用;
    • (4)包含了我们如何测试评估模型。

  • 模型参数:提供了模型代码之后,对方确实能够复现模型,但是运行的参数需要重新训练才能得到,而没有办法在我们的模型参数基础上继续训练,因此对方还希望我们能够把模型的参数也保存下来给对方。

    • (1)包含model.state_dict(),这是模型每一层可学习的节点的参数,比如weight/bias;
    • (2)包含optimizer.state_dict(),这是模型的优化器中的参数;
    • (3)包含我们其他参数信息,如epoch/batch_size/loss等。

  • 数据集

    • (1)包含了我们训练模型使用的所有数据;
    • (2)可以提示对方如何去准备同样格式的数据来训练模型。

  • 使用文档

    • (1)根据使用文档的步骤,每个人都可以重现模型;
    • (2)包含了模型的使用细节和我们相关参数的设置依据等信息。

可以看到,根据我们提供的模型代码/模型参数/数据集/使用文档,我们就可以有理由相信对方是有手就会了,那么目的就达到了。
现在我们反转一下思路,我们希望别人给我们提供模型的时候也能够提供这些信息,那么我们就可以拿捏住别人的模型了。
为什么要约定格式?

根据上一段的思路,我们知道模型重现的关键是模型结构/模型参数/数据集,那么我们提供或者希望别人提供这些信息,需要一个交流的规范,这样才不会1000个人给出1000种格式,而 .pt .pth .bin 以及 .onnx 就是约定的格式
torch.save: Saves a serialized object to disk. This function uses Python’s pickle utility for serialization. Models, tensors, and dictionaries of all kinds of objects can be saved using this function.
不同的后缀只是用于提示我们文件可能包含的内容,但是具体的内容需要看模型提供者编写的README.md才知道。而在使用torch.load()方法加载模型信息的时候,并不是根据文件的后缀进行的读取,而是根据文件的实际内容自动识别的,因此对于torch.load()方法而言,不管你把后缀改成是什么,只要文件是对的都可以读取
torch.load: Uses pickle’s unpickling facilities to deserialize pickled object files to memory. This function also facilitates the device to load the data into (see Saving & Loading Model Across Devices).
顺便提一下,“一切皆文件”的思维才是正确打开计算机世界的思维方式,文件后缀只作为提示作用,在Windows系统中也会用于提示系统默认如何打开或执行文件,除此之外,文件后缀不应该成为我们认识和了解文件阻碍。
格式汇总

下面是一个整理了 .pt、.pth、.bin、ONNX 和 TorchScript 等 PyTorch 模型文件格式的表格:
格式解释适用场景可对应的后缀
.pt 或 .pthPyTorch 的默认模型文件格式,用于保存和加载完整的 PyTorch 模型,包含模型的结构和参数等信息。需要保存和加载完整的 PyTorch 模型的场景,例如在训练中保存最佳的模型或在部署中加载训练好的模型。.pt 或 .pth
.bin一种通用的二进制格式,可以用于保存和加载各种类型的模型和数据。需要将 PyTorch 模型转换为通用的二进制格式的场景。.bin
ONNX一种通用的模型交换格式,可以用于将模型从一个深度学习框架转换到另一个深度学习框架或硬件平台。在 PyTorch 中,可以使用 torch.onnx.export 函数将 PyTorch 模型转换为 ONNX 格式。需要将 PyTorch 模型转换为其他深度学习框架或硬件平台可用的格式的场景。.onnx
TorchScriptPyTorch 提供的一种序列化和优化模型的方法,可以将 PyTorch 模型转换为一个序列化的程序,并使用 JIT 编译器对模型进行优化。在 PyTorch 中,可以使用 torch.jit.trace 或 torch.jit.script 函数将 PyTorch 模型转换为 TorchScript 格式。需要将 PyTorch 模型序列化和优化,并在没有 Python 环境的情况下运行模型的场景。.pt 或 .pth
.pt .pth格式

一个完整的Pytorch模型文件,包含了如下参数:

  • model_state_dict:模型参数
  • optimizer_state_dict:优化器的状态
  • epoch:当前的训练轮数
  • loss:当前的损失值
下面是一个.pt文件的保存和加载示例(注意,后缀也可以是 .pth ):

  • .state_dict():包含所有的参数和持久化缓存的字典,model和optimizer都有这个方法
  • torch.save():将所有的组件保存到文件中
模型保存
import torch
import torch.nn as nn

# 定义一个简单的模型
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(10, 5)
        self.fc2 = nn.Linear(5, 1)

    def forward(self, x):
        x = self.fc1(x)
        x = self.fc2(x)
        return x

model = Net()

# 保存模型
torch.save({
            'epoch': 10,
            'model_state_dict': model.state_dict(),
            'optimizer_state_dict': optimizer.state_dict(),
            'loss': loss,
            }, PATH)模型加载
import torch
import torch.nn as nn

# 定义同样的模型结构
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(10, 5)
        self.fc2 = nn.Linear(5, 1)

    def forward(self, x):
        x = self.fc1(x)
        x = self.fc2(x)
        return x

# 加载模型
model = Net()
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
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().bin格式

.bin文件是一个二进制文件,可以保存Pytorch模型的参数和持久化缓存。.bin文件的大小较小,加载速度较快,因此在生产环境中使用较多。
下面是一个.bin文件的保存和加载示例(注意:也可以使用 .pt .pth 后缀)
保存模型
import torch
import torch.nn as nn

# 定义一个简单的模型
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(10, 5)
        self.fc2 = nn.Linear(5, 1)

    def forward(self, x):
        x = self.fc1(x)
        x = self.fc2(x)
        return x

model = Net()
# 保存参数到.bin文件
torch.save(model.state_dict(), PATH)加载模型
import torch
import torch.nn as nn

# 定义相同的模型结构
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(10, 5)
        self.fc2 = nn.Linear(5, 1)

    def forward(self, x):
        x = self.fc1(x)
        x = self.fc2(x)
        return x

# 加载.bin文件
model = Net()
model.load_state_dict(torch.load(PATH))
model.eval().onnx格式

上述保存的文件可以通过PyTorch提供的torch.onnx.export函数转化为ONNX格式,这样可以在其他深度学习框架中使用PyTorch训练的模型。转化方法如下:
import torch
import torch.onnx

# 将模型保存为.bin文件
model = torch.nn.Linear(3, 1)
torch.save(model.state_dict(), "model.bin")
# torch.save(model.state_dict(), "model.pt")
# torch.save(model.state_dict(), "model.pth")

# 将.bin文件转化为ONNX格式
model = torch.nn.Linear(3, 1)
model.load_state_dict(torch.load("model.bin"))
# model.load_state_dict(torch.load("model.pt"))
# model.load_state_dict(torch.load("model.pth"))
example_input = torch.randn(1, 3)
torch.onnx.export(model, example_input, "model.onnx", input_names=["input"], output_names=["output"])加载ONNX格式的代码可以参考以下示例代码:
import onnx
import onnxruntime

# 加载ONNX文件
onnx_model = onnx.load("model.onnx")

# 将ONNX文件转化为ORT格式
ort_session = onnxruntime.InferenceSession("model.onnx")

# 输入数据
input_data = np.random.random(size=(1, 3)).astype(np.float32)

# 运行模型
outputs = ort_session.run(None, {"input": input_data})

# 输出结果
print(outputs)注意,需要安装onnx和onnxruntime两个Python包。此外,还需要使用numpy等其他常用的科学计算库。
直接保存完整模型

可以看出来,我们在之前的报错方式中,都是保存了.state_dict(),但是没有保存模型的结构,在其他地方使用的时候,必须先重新定义相同结构的模型(或兼容模型),才能够加载模型参数进行使用,如果我们想直接把整个模型都保存下来,避免重新定义模型,可以按如下操作:
# 保存模型
PATH = "entire_model.pt"
# PATH = "entire_model.pth"
# PATH = "entire_model.bin"
torch.save(model, PATH)加载模型
# 加载模型
model = torch.load("entire_model.pt")
model.eval()结语

本文介绍了pytorch可以导出的模型的几种后缀格式,但是模型导出的关键并不是后缀,而是到处时候提供的信息到底是什么,只要知道了模型的model.state_dict()和optimizer.state_dict(),以及相应的epoch batch_size loss等信息,我们就能够重建出模型,至于要导出哪些信息,就取决于你了,务必在readme.md中写清楚,你导出了哪些信息。
保存场景保存方法文件后缀
整个模型model = Net()
torch.save(model, PATH)
.pt .pth .bin
仅模型参数model = Net()
torch.save(model.state_dict(), PATH)
.pt .pth .bin
checkpoints使用model = Net()
torch.save({
   'epoch': 10,
   'model_state_dict': model.state_dict(),
   'optimizer_state_dict': optimizer.state_dict(),
   'loss': loss,
}, PATH)
.pt .pth .bin
ONNX通用保存model = Net()
model.load_state_dict(torch.load("model.bin"))
example_input = torch.randn(1, 3)
torch.onnx.export(model, example_input, "model.onnx", input_names=["input"], output_names=["output"])
.onnx
TorchScript无python环境使用model = Net()
model_scripted = torch.jit.script(model) # Export to TorchScript
model_scripted.save('model_scripted.pt')

使用时:
model = torch.jit.load('model_scripted.pt')
model.eval()
.pt .pth
参考资料


  • Saving and Loading Models
  • Saving and loading models for inference in PyTorch
  • Saving and loading multiple models in one file using PyTorch
  • Saving and loading a general checkpoint in PyTorch
  • Saving and loading models across devices in PyTorch
  • https://pytorch.org/tutorials/advanced/super_resolution_with_onnxruntime.html?highlight=onnx
By the way,以上均为官方文档资料,写得非常的清晰易懂,如果想仔细学习模型的导出和加载方法,强烈推荐学习上述文档,文档内容条理清晰、易读易用。
回复

使用道具 举报

1

主题

8

帖子

12

积分

新手上路

Rank: 1

积分
12
发表于 2023-7-21 10:02:54 | 显示全部楼层
怎么看出来 pt 保存了模型结构的?
回复

使用道具 举报

1

主题

5

帖子

5

积分

新手上路

Rank: 1

积分
5
发表于 2023-7-21 10:03:04 | 显示全部楼层
bin和pth没看出来有什么区别[害羞] 都可以转onnx吧,另外onnx只能推理不能训练,不包含反向信息的
回复

使用道具 举报

2

主题

10

帖子

15

积分

新手上路

Rank: 1

积分
15
发表于 2023-7-21 10:03:11 | 显示全部楼层
bin和pth代码没看出哪里有区别呀 这篇文章存在误导吧 正确的应该是因为不同习惯所以起不同后缀 最早都是pth 之后有的人发现pytorch官网的一些demo开始用pt来命名(实际上效果一样)而bin则是另一类开发者习惯而已 而非定式

参考文献:
https://pytorch.org/tutorials/beginner/basics/saveloadrun_tutorial.html

https://pytorch.org/tutorials/recipes/recipes/saving_and_loading_models_for_inference.html
回复

使用道具 举报

3

主题

14

帖子

23

积分

新手上路

Rank: 1

积分
23
发表于 2023-7-21 10:03:24 | 显示全部楼层
文章有一定的价值,但明显的漏洞就有两个(一个是pt的加载并没有导出模型结构,另一个是pth和bin文件的实现没有体现出有什么不同),不过取其精华去其糟粕,文章条理清晰,示例代码精炼,能看出作者在该方面一定的沉淀
回复

使用道具 举报

3

主题

9

帖子

13

积分

新手上路

Rank: 1

积分
13
发表于 2023-7-21 10:03:56 | 显示全部楼层
pt哪里保存了模型文件?
回复

使用道具 举报

8

主题

16

帖子

35

积分

新手上路

Rank: 1

积分
35
发表于 2023-7-21 10:04:19 | 显示全部楼层
没有区别吧,不加后缀也可以
回复

使用道具 举报

1

主题

8

帖子

4

积分

新手上路

Rank: 1

积分
4
发表于 2023-7-21 10:05:04 | 显示全部楼层
确实是,一切皆文件,后缀只是提示作用,了解文件的内容是什么,后缀要不要都行
回复

使用道具 举报

1

主题

11

帖子

16

积分

新手上路

Rank: 1

积分
16
发表于 2023-7-21 10:05:53 | 显示全部楼层
已经更新内容,.pt文件中可以保存模型结构信息和参数信息,使用torch.save(model, "model.pt")便可以保存完整的模型。
回复

使用道具 举报

3

主题

6

帖子

11

积分

新手上路

Rank: 1

积分
11
发表于 2023-7-21 10:06:48 | 显示全部楼层
谢谢指正,文章已经更新内容,参考了你指出的参考文献,谢谢。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表