DPO训练过程中预训练模型权重未更新问题求助
问题分析与解决思路
核心问题在于计算图断裂,导致梯度无法传递到模型参数:
你的loss是通过独立脚本run_mpnn计算的得分得到的,这部分得分是脱离当前训练模型计算图的纯数值,没有和内存中的model建立反向传播依赖,因此loss.backward()不会产生任何梯度,optimizer.step()自然也不会更新权重。
具体解决办法
1. 整合得分计算到训练流程(最优方案)
放弃独立脚本计算得分,直接在训练函数内调用模型的前向传播生成logps,让得分计算成为计算图的一部分:
def train(model, optimizer, pref_set, dispref_set, epochs, beta, bs): model.train() for epoch in range(epochs): cur_pref=[] cur_dispref=[] for i in range(len(pref_set)): cur_pref.append(pref_set[i]) cur_dispref.append(dispref_set[i]) if (i+1) % bs == 0: # 直接用当前model计算偏好/非偏好样本的logps # 替换原有的make_fastas、run_mpnn、collect_logps流程 b_dpo = [] nb_dpo = [] for pref, dispref in zip(cur_pref, cur_dispref): # 假设model接受样本输入,返回log概率 pref_logp = model(pref) dispref_logp = model(dispref) b_dpo.append(pref_logp) nb_dpo.append(dispref_logp) # 参考模型的logps如果是固定的,可以提前预计算好 b_ref, nb_ref = get_precomputed_ref_logps(cur_pref) # 计算loss loss = calc_loss(b_dpo, nb_dpo, b_ref, nb_ref, beta) print(loss) # 反向传播与更新 optimizer.zero_grad() loss.backward() optimizer.step() # 验证参数是否更新:打印某参数的数值 print(list(model.parameters())[0].data[0]) # 保存模型 torch.save({ 'epoch': epoch+1, 'step': i, 'num_edges' : 48, 'noise_level': 0.2, 'model_state_dict': model.state_dict(), 'optimizer_state_dict': optimizer.state_dict(), }, "../ProteinMPNN/vanilla_model_weights/model-DPO.pt") cur_pref=[] cur_dispref=[]
2. 若必须使用独立脚本的折中方案
如果无法避免用独立脚本打分,需要确保每轮离线打分使用的是最新更新后的模型,并且接受这种模式下梯度是近似的(因为得分是基于上一轮模型的,不是当前计算图的一部分):
- 先完成一轮梯度更新,保存模型
- 调用独立脚本加载最新模型,计算所有样本的得分并保存
- 下一轮训练时加载这些预计算的得分,计算loss并更新模型
- 注意:这种方式相当于用离线得分做监督,不是严格的DPO在线训练,效果会受影响
额外排查点
- 检查
calc_loss函数中是否存在detach()、.numpy()或.item()操作,这些会破坏张量的可导性 - 确认
optimizer初始化时传入了model.parameters(),确保优化器关联了正确的参数 - 在
optimizer.step()前后打印模型参数的具体数值(如list(model.parameters())[0].data),直接验证内存中的模型是否更新,而不是仅依赖保存的文件
内容的提问来源于stack exchange,提问作者jeash
相关产品推荐
相关产品推荐

