Python 在PyTorch中保存训练有素的模型的最佳方法?

Python 在PyTorch中保存训练有素的模型的最佳方法?,python,serialization,deep-learning,pytorch,tensor,Python,Serialization,Deep Learning,Pytorch,Tensor,我在寻找其他方法来拯救一个在PyTorch训练过的模特。到目前为止,我已经找到了两种选择 保存模型和加载模型的步骤 保存经过训练的模型并加载保存的模型 我遇到过这样的情况,即建议使用方法2而不是方法1 我的问题是,为什么选择第二种方法?这仅仅是因为模块有这两个功能,我们被鼓励使用它们吗?我在他们的github repo上找到了,我将把内容粘贴到这里 保存模型的推荐方法 序列化和恢复模型有两种主要方法 第一个(推荐)仅保存和加载模型参数: torch.save(the_model.state_d

我在寻找其他方法来拯救一个在PyTorch训练过的模特。到目前为止,我已经找到了两种选择

  • 保存模型和加载模型的步骤
  • 保存经过训练的模型并加载保存的模型
  • 我遇到过这样的情况,即建议使用方法2而不是方法1

    我的问题是,为什么选择第二种方法?这仅仅是因为模块有这两个功能,我们被鼓励使用它们吗?

    我在他们的github repo上找到了,我将把内容粘贴到这里


    保存模型的推荐方法 序列化和恢复模型有两种主要方法

    第一个(推荐)仅保存和加载模型参数:

    torch.save(the_model.state_dict(), PATH)
    
    随后:

    the_model = TheModelClass(*args, **kwargs)
    the_model.load_state_dict(torch.load(PATH))
    
    the_model = torch.load(PATH)
    
    第二个选项保存并加载整个模型:

    torch.save(the_model, PATH)
    
    随后:

    the_model = TheModelClass(*args, **kwargs)
    the_model.load_state_dict(torch.load(PATH))
    
    the_model = torch.load(PATH)
    
    但是,在这种情况下,序列化数据绑定到特定的类 并且使用了精确的目录结构,因此当
    在其他项目中使用,或者在一些严重的重构之后使用。

    这取决于您想要做什么

    案例#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 Service
    时。在Pytorch中执行此操作的等效方法为:

    torch.save(model, filepath)
    
    # Then later:
    model = torch.load(filepath)
    
    这种方法仍然不是防弹的,而且由于pytorch仍在经历许多更改,我不推荐使用这种方法。

    Python库实现二进制协议,用于序列化和反序列化Python对象

    当您
    导入torch
    (或使用PyTorch)时,它将
    为您导入pickle
    ,您不需要直接调用
    pickle.dump()
    pickle.load()
    ,这是保存和加载对象的方法

    实际上,
    torch.save()
    torch.load()
    将为您包装
    pickle.dump()
    pickle.load()

    A
    陈述
    提到的另一个答案值得再多注意几点

    Pytork里面有什么? 实际上有两种状态

    PyTorch模型是
    torch.nn.Module
    具有
    model.parameters()
    调用以获取可学习的参数(w和b)。 这些可学习的参数一旦随机设置,就会随着时间的推移而更新。 可学习的参数是第一个
    状态_dict

    torch.save(model.state_dict(), filepath)
    
    第二个
    state\u dict
    是优化器state dict。您还记得优化器用于改进我们的可学习参数。但是优化器的状态是固定的。那里没什么可学的

    由于
    state\u 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]}]
    
    注意,这是一个最小模型。您可以尝试添加一堆连续数据

    model = torch.nn.Sequential(
              torch.nn.Linear(D_in, H),
              torch.nn.Conv2d(A, B, C)
              torch.nn.Linear(H, D_out),
            )
    
    请注意,只有具有可学习参数的层(卷积层、线性层等)和已注册缓冲区(batchnorm层)在模型的
    状态中有条目

    不可学习的内容属于优化器对象
    state\u dict
    ,它包含有关优化器状态的信息以及所使用的超参数

    故事的其余部分是相同的;在推理阶段(这是我们在训练后使用模型的阶段)进行预测;我们确实根据我们学到的参数进行预测。因此,对于推断,我们只需要保存参数
    model.state\u dict()

    以后再使用 model.load\u state\u dict(torch.load(filepath)) model.eval()

    注意:不要忘记最后一行
    model.eval()
    这在加载模型后是至关重要的

    也不要尝试保存
    torch.save(model.parameters(),filepath)
    model.parameters()
    只是生成器对象


    另一方面,
    torch.save(model,filepath)
    保存模型对象本身,但请记住,模型没有优化器的
    状态。查看@Jadiel de Armas的另一个优秀答案,以保存优化器的状态指令。

    一个常见的PyTorch约定是使用.pt或.pth文件扩展名保存模型。

    保存/加载整个模型

    保存:

    path = "username/directory/lstmmodelgpu.pth"
    torch.save(trainer, path)
    
    
    加载:

    path = "username/directory/lstmmodelgpu.pth"
    torch.save(trainer, path)
    
    
    (必须在某处定义模型类)


    如果要保存模型并希望稍后恢复培训:

    单个GPU: 保存:

    负载:

    多个GPU: 拯救

    负载:

    保存模型的方式取决于将来访问模型的方式。如果可以调用
    model
    类的新实例,那么只需保存/加载模型的权重即可
    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
    
    # Save:
    torch.save(old_model, PATH)
    
    # Load:
    new_model = torch.load(PATH)