食谱:自博弈微调 (SPIN)

最后更新:2025/05/31。

verl 提供了一个受论文 “自博弈微调将弱语言模型转化为强语言模型” (SPIN) 启发的食谱。SPIN 是一种语言模型微调算法,可通过受博弈论启发的自博弈机制实现迭代式自我改进。

核心思想: 模型通过与自身博弈来学习,减少对外部偏好数据集或更强教师模型的依赖:

  1. 合成数据生成: 当前模型生成响应,从之前的迭代中创建自己的训练数据。

  2. 两玩家博弈设置: 一个涉及由单个 LLM 扮演的两个玩家的博弈。

  3. 迭代训练: 模型通过改进其策略逐步提高,每一轮的获胜模型成为下一轮的对手。

论文作者:Zixiang Chen*, Yihe Deng*, Huizhuo Yuan*, Kaixuan Ji, Quanquan Gu

[网页] [Huggingface] [论文] [原始实现]

verl 实现作者:Chendong Wang, Chenyang Zhao


关键函数 (compute_online_dpo_loss) 及相关工作

SPIN (Chen et al., 2024) 提出了一种迭代自博弈机制来微调语言模型。在每一轮迭代中,SPIN 的训练目标(在使用逻辑损失函数时)等同于直接偏好优化 (DPO) 损失 (Rafailov et al., 2023)。

verl 食谱通过迭代使用 DPO 损失 (Xu et al., 2023; Xiong et al., 2023; Snorkel AI, 2024) 来实现 SPIN 的核心概念。这意味着在每一轮迭代中,我们使用 DPO 损失来微调 LLM 以进行偏好优化。值得注意的是,Xu et al. (2023) 探讨了使用成对的 cringe 损失进行迭代偏好优化,而 Xiong et al. (2023) 讨论了如何通过迭代训练在 KL 约束下弥合 RLHF 的理论与实践。迭代偏好学习的概念也在在线 DPO (Guo et al., 2024) 中进行了探讨,该研究侧重于从在线 AI 反馈进行直接对齐。在在线 DPO 中,偏好数据在训练期间动态更新,使模型能够从自身生成的数据中学习。

具体来说,我们开发了 compute_online_dpo_loss 函数,并在此基础上构建了此 SPIN 食谱。通过整合在线偏好生成,此方法能够在不依赖固定外部偏好数据集的情况下,持续改进语言模型。

参考论文:

我们的在线 DPO 实现

我们的 compute_online_dpo_loss 函数改编了 verl 现有的 PPO 基础设施(基于 verl v0.3.0.post1),用于此迭代在线 DPO。我们实现的关键方面包括:

  • 无 Critic: 与 PPO 不同,我们省略了价值函数 critic。

  • 动态参考模型: 使用显式的参考策略 (ref_policy_wg) 进行 DPO 损失计算。此参考模型的权重可以根据 ref_update_freq 参数定期从 actor 中更新,从而提供动态基线。

  • 在线偏好生成: compute_onlineDPO_pref 函数(在 core_algos.py 中)基于奖励源(例如,数学问题的基于规则的排名)动态创建选定/拒绝的配对。

  • DPO 损失集成: 我们在 actor 更新 (dp_actor.py) 中,用 compute_online_dpo_loss(在 core_algos.py 中)替换了 PPO 的策略损失,直接使用生成的偏好来优化策略。

  • 迭代训练编排: SpinTrainer(在 spin_trainer.py 中)管理整个自博弈循环:生成、偏好标记、可选的参考模型更新和策略更新,从而根据 SPIN 的原则实现持续的自我改进。


算法

此食谱实现了改编自 verl 强化学习框架的在线算法,为微调语言模型提供了 PPO 的替代方案。

在线循环: 该方法不以最大化标量奖励信号(如 PPO)为目标,而是直接优化策略模型,使其与训练期间 在线 生成的偏好数据对齐:

  1. 生成: 当前模型为批次中的每个提示生成多个响应。

  2. 偏好标记: 一个函数评估这些生成的响应,以确定哪个是首选(选定)哪个是不太好(拒绝)。这可以通过奖励函数或基于特定规则的隐式排名来完成。(在此食谱中,我们使用数学问题的基于规则的排名)。

  3. 更新: 此偏好元组 (prompt, chosen_response, rejected_response) 用于使用 compute_online_dpo_loss 更新 actor 模型,并与参考模型进行比较。

与 SPIN 的联系: 在线生成循环在步骤 2 中,不只使用固定的目标数据分布,还会通过使用某种偏好标记方法(在此食谱中,通过选择更好的数学问题进行基于规则的排名)动态更改目标数据分布。这探索了 SPIN 论文第 7 节中提到的“动态更改目标数据分布”的方向,以期将 LLM 的性能提升到固定人工标注数据的上限之上。


复现实验(示例设置)

以下步骤概述了如何基于提供的测试日志(使用 GSM8K 和 Qwen2.5-3B-Instruct)设置环境并运行 SPIN 食谱。

  1. 设置环境(以 Docker 为例):

    # 启动一个具有 GPU 访问和共享内存的容器
    docker run -it --name spin_test --gpus all \
        --shm-size=32g \
        --ipc=host \
        -v /path/to/host/.cache:/root/.cache \
        -e HF_TOKEN=<YOUR_HUGGINGFACE_TOKEN> \
        lmsysorg/sglang:latest \
        /bin/bash
    
    # 在容器内或主机上:
    # 确保 /tmp 可写
    mkdir -p /tmp
    chmod 1777 /tmp
    
    # 安装 Python 3.10(如果不存在)和 venv
    sudo apt update
    sudo apt install -y python3.10 python3.10-venv tmux
    python3 -m ensurepip --upgrade
    
    # 创建并激活虚拟环境
    python3 -m venv ~/.python/spin_env
    source ~/.python/spin_env/bin/activate
    
    # 安装 uv(快速包安装程序)
    python3 -m pip install uv
    
  2. 安装 verl 和依赖项:

    # 克隆 verl 仓库并切换到 spin 分支
    cd ~
    git clone git@github.com:volcengine/verl.git && cd verl
    
    # 安装 flash-attn(处理潜在的构建问题)
    python3 -m uv pip install wheel packaging
    python3 -m uv pip install flash-attn --no-build-isolation --no-deps
    
    # 使用 sglang 附加组件安装 verl
    python3 -m uv pip install -e ".[sglang]"
    

    注意:如果 flash-attn 安装失败,请重试手动步骤或查阅其文档。

  3. 登录并下载数据/模型:

    # 登录到 Weights & Biases(可选,用于日志记录)
    export WANDB_API_KEY=<YOUR_WANDB_API_KEY>
    # wandb login
    
    # 下载 GSM8K 数据集
    python3 examples/data_preprocess/gsm8k.py --local_save_dir ~/data/gsm8k # 调整后的路径
    
    # 下载基础模型(示例:Qwen2.5-3B-Instruct)
    huggingface-cli download Qwen/Qwen2.5-3B-Instruct --local-dir $HOME/models/Qwen2.5-3B-Instruct
    
  4. 配置:

    • 使用下载的模型、数据、所需的超参数(dpo_beta、学习率等)以及分布式训练设置(节点、每个节点的 GPU 数量)修改配置文件(例如 config/spin_trainer.yaml 或运行脚本中指定的配置文件)。

    • 重点关注 actor_rollout_ref.model_pathdata 路径、reward_model 配置(如果使用)、以及 trainer.ref_update_freq

  5. 运行训练:

    # 设置 CUDA 可见设备(根据您的硬件和配置调整)
    export CUDA_VISIBLE_DEVICES=0,1,2,3
    
    # 启动训练脚本(例如 test.sh 或自定义脚本)
    # 确保 test.sh 指向正确的配置和主脚本
    bash recipe/spin/run_spin.sh
    

配置

  • 主要配置通常通过启动脚本中指定的 YAML 文件(例如 config/spin_trainer.yaml)进行管理。

  • 关键配置部分:

    • data: 训练/验证提示文件的路径、批次大小、序列长度。

    • actor_rollout_ref: 基础模型(用于 actor 和初始参考)的路径、FSDP 设置、优化参数(学习率、调度器)。

    • reward_model: 用于在线偏好标记的奖励模型的配置(路径、批次大小等)。如果使用简单的奖励函数,则可省略。

    • algorithm: DPO 特定超参数,如 dpo_betadpo_loss_type

    • trainer: 分布式训练设置(节点、每节点 GPU 数量)、日志记录(WandB)、检查点频率以及 ref_update_freq(设置为 > 0 以启用从 actor 定期更新参考模型)。


关键文件

  • main_spin.py: 主入口点,使用 Hydra 加载配置并启动 SpinTrainer

  • spin_trainer.py: 定义 SpinTrainer 类,编排在线 DPO 训练循环。

  • fsdp_workers.py: 实现 Ray 工作进程(Actor、Reference),可能使用 FSDP。

  • dp_actor.py: 包含 actor 类,其中包含 DPO 策略更新逻辑。

  • core_algos.py: 包含 compute_online_dpo_losscompute_onlineDPO_pref 的辅助函数。

  • config/spin_trainer.yaml(或类似文件):该食谱的主要 Hydra 配置文件。

  • run_spin.sh(或类似文件):启动训练运行的示例 bash 脚本。

  • README.md: 本文件。


致谢

我们衷心感谢 verl 社区和顾问的贡献和指导,包括(改编自 SPPO):