PyTorch学习:加载模型和参数

目录

  • PyTorch学习:加载模型和参数
  • 1. 直接加载模型和参数
  • 2. 分别加载网络的结构和参数
  • 3. pytorch预训练模型
  • 序列化 Serialization
  • torch.saves[source]
  • torch.load[source]
  • 其他
  • 关于.pt、.pth与.pkl 的区别
  • 关于Python序列化

pytorch的模型和参数是分开的,可以分别保存或加载模型和参数。

pytorch有两种模型保存方式

  1. 保存整个神经网络的的结构信息和模型参数信息,save的对象是网络net
  2. 只保存神经网络的训练模型参数,save的对象是net.state_dict()

对应两种保存模型的方式,pytorch也有两种加载模型的方式

  • 第一种保存方式,加载模型时通过torch.load('.pth')直接初始化新的神经网络对象;
  • 第二种保存方式,需要首先导入对应的网络,再通过net.load_state_dict(torch.load('.pth'))完成模型参数的加载。

在网络比较大的时候,第一种方法会花费较多的时间。

1. 直接加载模型和参数

加载别人训练好的模型:

# 保存和加载整个模型
torch.save(net, 'net.pth')
model = torch.load('net.pth')

2. 分别加载网络的结构和参数

# 将my_resnet模型储存为my_resnet.pth
torch.save(net.state_dict(), "net_parameter.pth")
# 加载resnet,模型存放在my_resnet.pth
net.load_state_dict(torch.load("net_parameter.pth"))

其中my_resnet是my_resnet.pth对应的网络结构。

3. pytorch预训练模型

1)加载预训练模型和参数

resnet18 = models.resnet18(pretrained=True)

2)只加载模型,不加载预训练参数

# 导入模型结构
resnet18 = models.resnet18(pretrained=False)
# 加载预先下载好的预训练参数到resnet18
resnet18.load_state_dict(torch.load('resnet18-5c106cde.pth'))

3)加载部分预训练模型

resnet152 = models.resnet152(pretrained=True)
pretrained_dict = resnet152.state_dict()
"""加载torchvision中的预训练模型和参数后通过state_dict()方法提取参数
   也可以直接从官方model_zoo下载:
   pretrained_dict = model_zoo.load_url(model_urls['resnet152'])"""
model_dict = model.state_dict()
# 将pretrained_dict里不属于model_dict的键剔除掉
pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}
# 更新现有的model_dict
model_dict.update(pretrained_dict)
# 加载我们真正需要的state_dict
model.load_state_dict(model_dict)

这里是直接调用pytorch中的常用模型

# PyTorch中的torchvision里有很多常用的模型,可以直接调用:
import torchvision.models as models
 
resnet101 = models.resnet18()
alexnet = models.alexnet()
squeezenet = models.squeezenet1_0()
densenet = models.densenet_161()

序列化 Serialization

torch.saves[source]

torch.save(obj, f, pickle_module=<module 'pickle' from '/home/jenkins/miniconda/lib/python3.5/pickle.py'>, pickle_protocol=2)

保存一个对象到一个硬盘文件上

  • obj – 保存对象
  • f - 类文件对象 (返回文件描述符)或一个保存文件名的字符串
  • pickle_module – 用于pickling元数据和对象的模块
  • pickle_protocol – 指定pickle protocal 可以覆盖默认参数

torch.load[source]

torch.load(f, map_location=None, pickle_module=<module 'pickle' from '/home/jenkins/miniconda/lib/python3.5/pickle.py'>)

从磁盘文件中读取一个通过torch.save()保存的对象。 torch.load() 可通过参数map_location 动态地进行内存重映射,使其能从不动设备中读取文件。一般调用时,需两个参数: storage 和 location tag. 返回不同地址中的storage,或着返回None (此时地址可以通过默认方法进行解析). 如果这个参数是字典的话,意味着其是从文件的地址标记到当前系统的地址标记的映射。 默认情况下, location tags中 "cpu"对应host tensors,‘cuda:device_id’ (e.g. ‘cuda:2’) 对应cuda tensors。 用户可以通过register_package进行扩展,使用自己定义的标记和反序列化方法。

参数:

  • f – 类文件对象 (返回文件描述符)或一个保存文件名的字符串
  • map_location – 一个函数或字典规定如何remap存储位置
  • pickle_module – 用于unpickling元数据和对象的模块 (必须匹配序列化文件时的pickle_module )

例子:

>>> torch.load('tensors.pt')
# Load all tensors onto the CPU
>>> torch.load('tensors.pt', map_location=lambda storage, loc: storage)
# Map tensors from GPU 1 to GPU 0
>>> torch.load('tensors.pt', map_location={'cuda:1':'cuda:0'})

其他

关于.pt、.pth与.pkl 的区别

不存在格式上的区别,只是后缀名不同而已。在用torch.save()函数保存模型文件的时候,有些人喜欢用.pt后缀,有些人喜欢用.pth.pkl,用相同的 torch.save()语句保存出来的模型文件没有什么不同。

为什么会有 .pkl这种后缀名呢?因为Python有一个序列化模块 - pickle,使用它保存模型时,通常会起一个以 .pkl为后缀名的文件。torch.save()正是使用pickle来保存模型的。

关于Python序列化

我们把对象(变量)从内存中转换为可存储或传输的格式的过程称之为序列化,在python中称为pickle

序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上(因为硬盘或网络传输时只接受bytes)。

反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpacking

在python中,可以使用pickle和json两个模块对数据进行序列化操作

其中:

  • json可以用于字符串或者字典等与python数据类型之间的序列化与反序列化操作
  • pickle可以用于python特有类型与python数据类型之间的序列化与反序列化操作