You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Libtorch(C++):保存/加载模型与优化器状态字典以重训的高效正确方法

LibTorch(C++) 模型与优化器状态保存/加载及重训最佳实践

核心问题

我需要确认在LibTorch中同时保存、加载模型与优化器状态字典并进行重训的正确流程,尤其是创建Optimizer并传入模型参数的时机——应该在加载状态字典之前、之后执行,还是两者无关?

现有代码示例

保存模型与优化器状态

// Save model state
torch::serialize::OutputArchive output_model_archive;
myModel.to(torch::kCPU);
myModel.save(output_model_archive);
output_model_archive.save_to(model_state_dict_path);
// Save optim state
torch::serialize::OutputArchive output_optim_archive;
myOptimizer->save(output_optim_archive);
output_optim_archive.save_to(optim_state_dict_path);

重训时加载状态

// Load model state
torch::serialize::InputArchive input_archive;
input_archive.load_from(state_dict);
myModel.load(input_archive);
// Load optim state
torch::serialize::InputArchive input_archive; // 注意:这里变量名重复,会编译报错
input_archive.load_from(state_dict);
myOptimizer->load(input_archive);

创建Optimizer对象

std::shared_ptr<torch::optim::Optimizer> myOptimizer;
myOptimizer.reset(new torch::optim::Adam(myModel.parameters(), torch::optim::AdamOptions(LR)));

正确流程与关键说明

优化器创建时机:必须在加载状态字典之前

优化器的状态字典(如Adam的动量缓存exp_avg、exp_avg_sq)是与模型参数一一绑定的,只有当优化器已经持有模型参数的引用时,加载状态字典才能正确将缓存关联到对应的参数上。如果先加载模型状态再创建优化器,优化器会初始化全新的状态,直接覆盖你加载的内容;反之,先创建优化器再加载模型状态,模型参数的更新会自动同步到优化器持有的引用中,后续加载优化器状态就能正确恢复之前的训练状态。

修正后的完整重训流程

// 1. 初始化模型实例
MyModel myModel;

// 2. 创建优化器(关键步骤:必须在加载状态前绑定模型参数)
std::shared_ptr<torch::optim::Optimizer> myOptimizer = 
    std::make_shared<torch::optim::Adam>(myModel.parameters(), torch::optim::AdamOptions(LR));

// 3. 加载模型状态
torch::serialize::InputArchive model_archive;
model_archive.load_from(model_state_dict_path);
myModel.load(model_archive);

// 4. 加载优化器状态(注意使用不同的变量名,避免编译错误)
torch::serialize::InputArchive optim_archive;
optim_archive.load_from(optim_state_dict_path);
myOptimizer->load(optim_archive);

// 5. (可选)将模型与优化器转移到目标训练设备(如CUDA)
myModel.to(torch::kCUDA);
// 同步优化器状态到目标设备
for (auto& group : myOptimizer->param_groups()) {
    for (auto& p : group.params()) {
        p.data() = p.data().to(torch::kCUDA);
        if (p.grad().defined()) {
            p.grad().data() = p.grad().data().to(torch::kCUDA);
        }
    }
    // 针对Adam等带额外状态的优化器,同步缓存到目标设备
    for (auto& p : group.params()) {
        auto& state = myOptimizer->state()[p];
        if (state.contains("exp_avg")) {
            state["exp_avg"] = state["exp_avg"].to(torch::kCUDA);
        }
        if (state.contains("exp_avg_sq")) {
            state["exp_avg_sq"] = state["exp_avg_sq"].to(torch::kCUDA);
        }
    }
}

// 6. 开始重训
for (int epoch = 0; epoch < num_epochs; ++epoch) {
    // 前向传播
    auto output = myModel(input.to(torch::kCUDA));
    auto loss = criterion(output, target.to(torch::kCUDA));
    
    // 反向传播与优化步骤
    myOptimizer->zero_grad();
    loss.backward();
    myOptimizer->step();
}

// 7. 保存状态(与原逻辑一致,先移模型到CPU避免设备不兼容)
myModel.to(torch::kCPU);
torch::serialize::OutputArchive model_output;
myModel.save(model_output);
model_output.save_to(model_state_dict_path);

torch::serialize::OutputArchive optim_output;
myOptimizer->save(optim_output);
optim_output.save_to(optim_state_dict_path);

关键注意事项

  • 避免变量名重复:加载模型和优化器状态时,不能重复定义InputArchive变量,否则会触发C++编译错误。
  • 设备匹配:保存前将模型移到CPU是最佳实践,避免不同设备(CPU/CUDA)之间的状态加载冲突;加载后需要手动将模型和优化器状态同步到目标训练设备。
  • 优化器与模型参数绑定:优化器必须绑定当前训练的模型参数,不能复用其他模型的优化器状态,否则会导致参数不匹配。

内容的提问来源于stack exchange,提问作者Brandon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 08:15:43