Skip to content

bug(training): GRPO 训练作业失败 There is no Stream(gpu, 6) in current thread #430

Description

@dahai80

Bug

GRPO 训练作业(POST /admin/api/fine-tune/grpo/jobs#363/PR#366)启动后立即失败:

status: failed
error: "There is no Stream(gpu, 6) in current thread."

复现

服务在跑(已加载 VL-7B 等模型),创建一个最小 GRPO 作业:

curl -X POST "http://localhost:11434/admin/api/fine-tune/grpo/jobs" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{
    "model_id": "Qwen3-0.6B-4bit",
    "prompts": ["What is 2+2?", "Say hello."],
    "adapter_name": "grpo_smoke",
    "config": {"group_size":2,"iters":2,"batch_size":1,"learning_rate":1e-5,
               "lora_layers":4,"lora_rank":4,"lora_alpha":8.0,
               "max_completion_len":16,"temperature":0.8}
  }'

status=failedfinished_at - started_at ≈ 0.4s(一进 train_step 就崩)。

根因

grpo_service._execute_grpo 通过 asyncio.to_threadgrpo_service.py:224)在 worker 线程跑训练。GRPOTrainer._sample_completions 调用 mlx_lm.generate.generate_step,其内部 with mx.stream(generation_stream) 使用的是 mlx_lm.generate 模块级的 generation_stream = mx.new_thread_local_stream(...)

该 stream 是 thread-local:在服务主线程(import 期 / 推理热路径)建立后,worker 线程拿不到同一个 Stream 对象,于是 MLX 抛 There is no Stream(gpu, 6) in current thread.(索引 6 对应服务运行期由 async eval / wired_limit 流池建立的某个 stream)。

对比:SFT / DPO / reward 训练也在 to_thread 跑,但它们只用 mx.grad + 前向(不进 generate_step 的 thread-local stream 上下文),所以不触发本 bug。GRPO 是唯一调用 generate_step 采样的训练器,因此唯一暴露此问题。

建议修复

_execute_grpo(worker 线程入口)建立该线程的默认 stream,使 generate_step 内部的 with mx.stream(generation_stream) 可用:

def _execute_grpo(self, job):
    import mlx.core as mx
    _stream = mx.new_thread_local_stream(mx.default_device())
    with mx.stream(_stream):
        # ... 原有 load / train / save 逻辑 ...

(备选:在 _sample_completions 每次 generate_step 外包 with mx.stream(mx.new_thread_local_stream(...)),但入口处一次性建立更干净,且对 mx.grad 步也无害。)

验收

  • 上述复现作业 status=completed,写出 adapter,progress.loss 有值、mean_reward 有值。
  • fusion-trainer 下游 RLSL Phase 2 可经此端点跑真实 PPO-clipped 策略更新。

关联

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions