在 SageMaker HyperPod 上用 SkyRL 和 GRPO 后训练 Qwen3-VL-8B

2026-09-26 18 预计阅读时间: 1 分钟
来源: aws.amazon.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:13 分钟

多模态模型完成监督微调后,往往已经“能回答”,但距离稳定地遵循视觉指令、按要求输出格式、解决复杂推理任务仍有差距。一个可行方向是使用 SkyRL,在 Amazon SageMaker HyperPod 提供的集群资源上,通过 GRPO 对 Qwen3-VL-8B 进行强化学习后训练,并把最终产出的 LoRA 适配器部署为推理服务。

这条链路不只是启动一个训练脚本。真正影响效率和稳定性的环节包括:容器与 GPU 环境是否一致、Ray 集群能否正确调度训练进程、奖励函数是否可靠,以及基础模型与 LoRA 是否能在服务端正确组合。

整条链路如何拆分

可以把工作流拆成五个相互独立的阶段:

  1. 构建包含 CUDA、PyTorch、Ray、SkyRL 和模型依赖的容器镜像。
  2. 将镜像推送到 Amazon ECR,供 HyperPod 节点统一拉取。
  3. 从 SageMaker Studio 连接或启动 Ray 集群,再提交 GRPO 训练任务。
  4. 通过 Ray Dashboard、CloudWatch 和训练日志观察吞吐、显存与奖励变化。
  5. 保存 LoRA 适配器,并在推理端与原始 Qwen3-VL-8B 基础模型组合。

这里有一个很重要的工程边界:LoRA 目录不是完整模型。部署时仍需要访问与训练阶段兼容的基础模型、处理器和 tokenizer。只复制 adapter 权重而忽略基础模型版本,常常会导致加载失败,或者更隐蔽的推理质量变化。

构建可复现的训练镜像

强化学习训练对依赖组合非常敏感。PyTorch、CUDA、Flash Attention、Transformers、Ray 和 SkyRL 任意一层发生变化,都可能引入编译错误或运行时差异。因此,生产镜像不应长期使用不固定版本的 latest 标签。

下面给出一个可以直接改造的最小项目结构。由于不同 SkyRL 版本的安装方式和训练入口可能变化,示例通过构建参数传入仓库地址与提交版本;运行前应替换为团队验证过的版本。

skyrl-hyperpod/
├── Dockerfile
├── requirements.txt
├── train.yaml
└── submit.sh

Dockerfile:

FROM pytorch/pytorch:2.5.1-cuda12.4-cudnn9-runtime

ARG SKYRL_REPO
ARG SKYRL_COMMIT

ENV PIP_NO_CACHE_DIR=1 \
    PYTHONUNBUFFERED=1 \
    HF_HOME=/opt/ml/checkpoints/huggingface

RUN apt-get update && apt-get install -y --no-install-recommends \
    git curl build-essential && \
    rm -rf /var/lib/apt/lists/*

COPY requirements.txt /tmp/requirements.txt
RUN pip install -r /tmp/requirements.txt

RUN test -n "$SKYRL_REPO" && test -n "$SKYRL_COMMIT" && \
    git clone "$SKYRL_REPO" /opt/skyrl && \
    cd /opt/skyrl && git checkout "$SKYRL_COMMIT" && \
    pip install -e .

WORKDIR /workspace
COPY . /workspace

requirements.txt 可以从保守的基础依赖开始,再根据 SkyRL 对 PyTorch 和 Transformers 的约束进行调整:

ray[default]==2.40.0
transformers>=4.51.0
accelerate>=1.2.0
peft>=0.14.0
safetensors>=0.4.5
boto3>=1.35.0
pillow>=10.4.0

以下命令创建 ECR 仓库、登录、构建并推送镜像。运行前需要设置 SkyRL 仓库地址和经过测试的提交哈希:

#!/usr/bin/env bash
set -euo pipefail

export AWS_REGION="us-west-2"
export AWS_ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
export ECR_REPOSITORY="skyrl-grpo"
export IMAGE_TAG="qwen3-vl-8b-$(date +%Y%m%d)"
export IMAGE_URI="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPOSITORY}:${IMAGE_TAG}"

# 替换为项目实际使用的 SkyRL 仓库及固定提交。
export SKYRL_REPO="https://github.com/your-org/SkyRL.git"
export SKYRL_COMMIT="replace-with-tested-commit"

aws ecr describe-repositories \
  --region "$AWS_REGION" \
  --repository-names "$ECR_REPOSITORY" >/dev/null 2>&1 || \
aws ecr create-repository \
  --region "$AWS_REGION" \
  --repository-name "$ECR_REPOSITORY" >/dev/null

aws ecr get-login-password --region "$AWS_REGION" | \
docker login --username AWS --password-stdin \
  "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"

docker build \
  --build-arg SKYRL_REPO="$SKYRL_REPO" \
  --build-arg SKYRL_COMMIT="$SKYRL_COMMIT" \
  -t "$IMAGE_URI" .

docker push "$IMAGE_URI"
echo "$IMAGE_URI"

如果构建机器不是 NVIDIA 架构对应的平台,可以使用 docker buildx build --platform,但必须确认目标实例架构与镜像平台一致。Flash Attention 一类原生扩展最好在与训练节点相近的 CUDA 环境中构建和验证。

用 Ray 提交 GRPO 任务

Ray 负责把训练、生成和奖励计算分发到 HyperPod 集群。SageMaker Studio 可以作为控制入口:开发者在 Studio 中准备配置、连接 Ray Dashboard 地址,然后使用 Ray Jobs API 提交任务,而不是依赖一个长期存活的终端会话。

下面的配置是一个通用骨架,不代表 SkyRL 所有版本都使用完全相同的字段。需要根据所固定的 SkyRL 版本,把字段映射到真实训练入口。

# train.yaml
model:
  name_or_path: Qwen/Qwen3-VL-8B-Instruct
  trust_remote_code: true
  gradient_checkpointing: true

adapter:
  type: lora
  rank: 32
  alpha: 64
  dropout: 0.05
  target_modules:
    - q_proj
    - k_proj
    - v_proj
    - o_proj

algorithm:
  name: grpo
  group_size: 8
  learning_rate: 1.0e-6
  max_prompt_tokens: 2048
  max_completion_tokens: 1024
  kl_coefficient: 0.02

runtime:
  mixed_precision: bf16
  per_device_batch_size: 1
  gradient_accumulation_steps: 16
  checkpoint_interval: 100
  output_dir: /opt/ml/checkpoints/qwen3-vl-grpo

data:
  train_manifest: s3://replace-me/datasets/train.jsonl

GRPO 会针对同一输入生成一组候选响应,再利用组内相对奖励更新策略。对视觉语言任务而言,奖励不能只检查最终文本是否包含某个词。更稳妥的组合通常包括:

  • 任务正确性,例如选择题答案、可验证数值或结构化字段;
  • 输出格式约束,例如合法 JSON、固定标签或坐标格式;
  • 视觉依据检查,避免响应与图像内容脱节;
  • 长度或冗余惩罚,防止模型通过堆叠文本获取偏高奖励;
  • 安全规则,阻止奖励函数鼓励危险或越权输出。

假设 Ray Dashboard 或 Jobs API 已经从 Studio 环境可访问,可以这样提交任务:

#!/usr/bin/env bash
set -euo pipefail

export RAY_ADDRESS="http://replace-with-ray-head:8265"
export TRAIN_ENTRY="python -m skyrl.train --config train.yaml"

ray job submit \
  --address "$RAY_ADDRESS" \
  --working-dir . \
  --runtime-env-json '{"env_vars":{"TOKENIZERS_PARALLELISM":"false"}}' \
  -- "$TRAIN_ENTRY"

如果当前 SkyRL 版本的模块入口不是 skyrl.train,只需修改 TRAIN_ENTRY。集群若要求认证或只开放私有网络,还需要通过 Studio VPC、端口转发或平台提供的 Ray 连接方式访问,而不应直接把 8265 端口暴露到公网。

任务提交后,可使用以下命令查看状态和日志:

ray job list --address "$RAY_ADDRESS"
ray job status --address "$RAY_ADDRESS" JOB_ID
ray job logs --address "$RAY_ADDRESS" JOB_ID --follow

除了“任务是否运行”,还应持续观察四组指标:每秒生成 token 数、GPU 利用率与显存、每类奖励分量,以及 KL 散度。总奖励上升并不一定代表模型变好;如果格式奖励快速上涨而视觉正确性不变,模型可能只学会了迎合奖励函数。

托管 LoRA:基础模型和适配器必须成对管理

训练完成后,建议分别记录以下资产:

  • 基础模型的精确版本或提交哈希;
  • LoRA adapter 权重和配置;
  • processor、tokenizer 及聊天模板;
  • 推理依赖镜像的 digest;
  • GRPO 配置、奖励代码和训练数据版本。

如果推理框架能够动态加载 LoRA,可以共享一份基础模型,并为不同任务挂载不同 adapter,从而减少存储和冷启动成本。如果服务框架不支持 Qwen3-VL 的动态 LoRA,则可以在发布前合并权重,但合并后的模型体积更大,也失去了快速切换 adapter 的优势。

下面是一个最小加载检查。它适合在制作推理镜像前验证 adapter 与基础模型是否兼容。运行前设置模型和 adapter 路径,并确认当前 Transformers 版本支持目标 Qwen3-VL 架构。

import os
import torch
from peft import PeftModel
from transformers import AutoModelForImageTextToText, AutoProcessor

base_model_id = os.environ.get(
    "BASE_MODEL_ID", "Qwen/Qwen3-VL-8B-Instruct"
)
adapter_path = os.environ.get(
    "ADAPTER_PATH", "/opt/ml/model/adapter"
)

processor = AutoProcessor.from_pretrained(
    base_model_id,
    trust_remote_code=True,
)
base_model = AutoModelForImageTextToText.from_pretrained(
    base_model_id,
    torch_dtype=torch.bfloat16,
    device_map="auto",
    trust_remote_code=True,
)
model = PeftModel.from_pretrained(base_model, adapter_path)
model.eval()

print("Base model:", base_model_id)
print("Adapter:", adapter_path)
print("Adapter loaded successfully")

在 SageMaker 推理端点中,可以把 adapter 打包到模型制品,将基础模型预置在镜像中,或在容器启动时从受控存储下载。选择哪一种方式取决于模型许可、启动时间和制品大小。无论采用哪种方式,都应固定基础模型 revision,避免端点重启后静默加载了新版本。

上线前的检查清单

HyperPod、Ray、SkyRL、GRPO 和 LoRA 组合起来,可以把大规模多模态后训练拆成可管理的层次,但每增加一层也会增加排障面。建议按以下顺序推进:

  • 先在单节点、少量样本上验证图像预处理、生成和奖励函数;
  • 再用两个 Ray worker 验证对象存储、进程调度和 checkpoint 恢复;
  • 固定镜像 digest、SkyRL 提交版本和基础模型 revision;
  • 为奖励各分量单独记录指标,不只看总奖励;
  • 定期把 checkpoint 同步到持久存储,验证从中断点恢复;
  • 部署前运行一套同时包含文本、单图和多图输入的回归集;
  • 对比基础模型、监督微调模型与 GRPO 模型,确认提升不是奖励投机;
  • 对推理端点执行冷启动、并发、显存和超时测试。

最值得优先投入的通常不是扩大 GPU 数量,而是让一个小规模训练闭环完全可复现:相同镜像、相同数据、相同奖励代码和相同基础模型能够产生可比较的结果。闭环稳定后,再借助 HyperPod 和 Ray 扩展规模,成本和故障风险都会更容易控制。


相关推荐