Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/ar/qwen3_5_grpo_9b_base_dapo_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ rollout:
chat_template_kwargs:
enable_thinking: true
engine_kwargs:
# Colocate, but a larger KV/graph budget than the 4B full-FT preset
# (0.5 / cuda_graph_max_bs 128 vs 0.3 / 16). Retune if the FSDP all-gather OOMs.
# See unirl/rollout/README.md (SGLang AR knobs).
mem_fraction_static: 0.5
skip_server_warmup: true
attention_backend: triton
Expand Down
1 change: 1 addition & 0 deletions examples/ar/qwen3_5_grpo_9b_geo3k_mc_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ rollout:
chat_template_kwargs:
enable_thinking: false
engine_kwargs:
# Colocate full-FT preset — see unirl/rollout/README.md (SGLang AR knobs).
mem_fraction_static: 0.3
skip_server_warmup: true
attention_backend: triton
Expand Down
2 changes: 2 additions & 0 deletions examples/ar/qwen3_5_moe_grpo_35b_a3b_base_dapo_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ rollout:
chat_template_kwargs:
enable_thinking: true
engine_kwargs:
# Colocate MoE: tighter KV than the 4B dense preset (0.15 vs 0.3) and
# cuda_graph_max_bs=64. See unirl/rollout/README.md (SGLang AR knobs).
mem_fraction_static: 0.15
attention_backend: triton
disable_cuda_graph: false
Expand Down
3 changes: 3 additions & 0 deletions examples/ar/qwen3_5_moe_grpo_35b_a3b_geo3k_mc_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ rollout:
chat_template_kwargs:
enable_thinking: false
engine_kwargs:
# Colocate MoE + geo3k: cuda graph OFF and mem_fraction_static 0.15
# (4B dense preset is 0.3 + cuda graph ON @ bs 16).
# See unirl/rollout/README.md (SGLang AR knobs).
mem_fraction_static: 0.15
disable_cuda_graph: true
enable_lora: false
Expand Down
3 changes: 3 additions & 0 deletions examples/ar/qwen3_cppo_30b_a3b_base_dapo_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ rollout:
chat_template_kwargs:
enable_thinking: true
engine_kwargs:
# Colocate full-FT preset (same KV/graph knobs as the 4B dense recipes;
# tp_size=8 is the MoE fit, not an engine_kwargs change).
# See unirl/rollout/README.md (SGLang AR knobs).
mem_fraction_static: 0.3
skip_server_warmup: true
attention_backend: triton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,10 @@ rollout:
chat_template_kwargs:
enable_thinking: true
engine_kwargs:
# Leaves room for FSDP offload/onload and staged SGLang wake on this
# 8-GPU 30B MoE recipe; retune when changing the model or TP layout.
# Colocate 30B MoE: tighter than the 4B dense preset (0.15 / cuda_graph_max_bs
# 64 vs 0.3 / 16) to leave room for FSDP offload/onload and staged SGLang
# wake. Retune when changing the model or TP layout.
# See unirl/rollout/README.md (SGLang AR knobs).
mem_fraction_static: 0.15
attention_backend: triton
disable_cuda_graph: false
Expand Down
6 changes: 4 additions & 2 deletions examples/ar/qwen3_cppo_30b_a3b_base_dapo_sglang_lora.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,10 @@ rollout:
chat_template_kwargs:
enable_thinking: true
engine_kwargs:
# Value used for the reported LoRA run; retune when changing the model,
# the TP layout, or the FSDP offload settings above.
# LoRA exception to the colocate full-FT preset (enable_lora: true + pool
# knobs; LocalLoraWeightSync). Value used for the reported LoRA run; retune
# when changing the model, the TP layout, or the FSDP offload settings.
# See unirl/rollout/README.md (SGLang AR knobs).
mem_fraction_static: 0.5
attention_backend: triton
disable_cuda_graph: false
Expand Down
1 change: 1 addition & 0 deletions examples/ar/qwen3_dppo_4b_base_dapo_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ rollout:
chat_template_kwargs:
enable_thinking: true
engine_kwargs:
# Colocate full-FT preset — see unirl/rollout/README.md (SGLang AR knobs).
# FULL fine-tuning: lower the SRT KV reservation to give FSDP headroom for
# the per-rollout full-weight all-gather. No LoRA pool — full dense weights
# pushed via TensorWeightSync. CUDA graph ON for decode speed, but capped at
Expand Down
1 change: 1 addition & 0 deletions examples/ar/qwen3_drgrpo_4b_base_dapo_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ rollout:
chat_template_kwargs:
enable_thinking: true
engine_kwargs:
# Colocate full-FT preset — see unirl/rollout/README.md (SGLang AR knobs).
# FULL fine-tuning: lower the SRT KV reservation to give FSDP headroom for
# the per-rollout full-weight all-gather. No LoRA pool — full dense weights
# pushed via TensorWeightSync. CUDA graph ON for decode speed, but capped at
Expand Down
1 change: 1 addition & 0 deletions examples/ar/qwen3_drpo_4b_base_dapo_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ rollout:
# FSDP trainer. Without it, rollout logprobs drift from replay and
# SGLang 0.5.12.post1 also tries to JIT an incompatible activation kernel.
rl_on_policy_target: fsdp
# Colocate full-FT preset — see unirl/rollout/README.md (SGLang AR knobs).
# FULL fine-tuning: lower the SRT KV reservation to give FSDP headroom for
# the per-rollout full-weight all-gather. No LoRA pool — full dense weights
# pushed via TensorWeightSync. CUDA graph ON for decode speed, but capped at
Expand Down
5 changes: 3 additions & 2 deletions examples/ar/qwen3_drpo_4b_base_dapo_sglang_async.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,9 @@ rollout:
enable_thinking: true
engine_kwargs:
# Disaggregated: the engine owns the GPU (no colocated FSDP shard), so it
# can reserve more KV than the colocate recipe's 0.3. Leave headroom for
# the NCCL weight-receive buffers during the broadcast.
# can reserve more KV than the colocate full-FT preset's 0.3. Leave
# headroom for the NCCL weight-receive buffers during the broadcast.
# Other knobs match the colocate preset — see unirl/rollout/README.md.
mem_fraction_static: 0.8
skip_server_warmup: true
attention_backend: triton
Expand Down
1 change: 1 addition & 0 deletions examples/ar/qwen3_drpo_4b_veomni_sp_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ rollout:
chat_template_kwargs:
enable_thinking: true
engine_kwargs:
# Colocate full-FT preset — see unirl/rollout/README.md (SGLang AR knobs).
# FULL fine-tuning: lower the SRT KV reservation to give FSDP headroom for
# the per-rollout full-weight all-gather. No LoRA pool — full dense weights
# pushed via TensorWeightSync. CUDA graph ON for decode speed, but capped at
Expand Down
1 change: 1 addition & 0 deletions examples/ar/qwen3_grpo_4b_base_dapo_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ rollout:
chat_template_kwargs:
enable_thinking: true
engine_kwargs:
# Colocate full-FT preset — see unirl/rollout/README.md (SGLang AR knobs).
# FULL fine-tuning: lower the SRT KV reservation to give FSDP headroom for
# the per-rollout full-weight all-gather. No LoRA pool — full dense weights
# pushed via TensorWeightSync. CUDA graph ON for decode speed, but capped at
Expand Down
5 changes: 3 additions & 2 deletions examples/ar/qwen3_grpo_4b_base_dapo_sglang_async.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,9 @@ rollout:
enable_thinking: true
engine_kwargs:
# Disaggregated: the engine owns the GPU (no colocated FSDP shard), so it
# can reserve more KV than the colocate recipe's 0.3. Leave headroom for
# the NCCL weight-receive buffers during the broadcast.
# can reserve more KV than the colocate full-FT preset's 0.3. Leave
# headroom for the NCCL weight-receive buffers during the broadcast.
# Other knobs match the colocate preset — see unirl/rollout/README.md.
mem_fraction_static: 0.8
skip_server_warmup: true
attention_backend: triton
Expand Down
1 change: 1 addition & 0 deletions examples/ar/qwen3_grpo_4b_veomni_sp_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ rollout:
chat_template_kwargs:
enable_thinking: true
engine_kwargs:
# Colocate full-FT preset — see unirl/rollout/README.md (SGLang AR knobs).
# FULL fine-tuning: lower the SRT KV reservation to give FSDP headroom for
# the per-rollout full-weight all-gather. No LoRA pool — full dense weights
# pushed via TensorWeightSync. CUDA graph ON for decode speed, but capped at
Expand Down
1 change: 1 addition & 0 deletions examples/ar/qwen3_grpo_vanilla_4b_base_dapo_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ rollout:
chat_template_kwargs:
enable_thinking: true
engine_kwargs:
# Colocate full-FT preset — see unirl/rollout/README.md (SGLang AR knobs).
# FULL fine-tuning: lower the SRT KV reservation to give FSDP headroom for
# the per-rollout full-weight all-gather. No LoRA pool — full dense weights
# pushed via TensorWeightSync. CUDA graph ON for decode speed, but capped at
Expand Down
2 changes: 2 additions & 0 deletions examples/ar/qwen3_moe_grpo_30b_a3b_veomni_ep_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ rollout:
chat_template_kwargs:
enable_thinking: true
engine_kwargs:
# Colocate MoE at tp_size=1: slightly more KV than the 4B dense preset
# (0.4 vs 0.3); other knobs match. See unirl/rollout/README.md (SGLang AR knobs).
mem_fraction_static: 0.4
skip_server_warmup: true
attention_backend: triton
Expand Down
9 changes: 9 additions & 0 deletions examples/ar/qwen3_ppo_4b_base_dapo_sglang.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,16 @@ rollout:
chat_template_kwargs:
enable_thinking: true
engine_kwargs:
# SGLang's FSDP on-policy mode is part of the rollout/replay contract,
# not merely a performance switch. It selects deterministic PyTorch
# sampling/log-softmax and native activations/layernorms that match the
# FSDP trainer. Without it, rollout logprobs drift from replay and
# SGLang 0.5.12.post1 also tries to JIT an incompatible activation kernel.
rl_on_policy_target: fsdp
# Colocate full-FT preset (unirl/rollout/README.md): lower the SRT KV
# reservation so FSDP can all-gather full dense weights. enable_lora must
# stay false for TensorWeightSync. CUDA graph ON, cuda_graph_max_bs=16
# (SGLang default 256 would balloon server memory + compete with the push).
mem_fraction_static: 0.3
skip_server_warmup: true
attention_backend: triton
Expand Down
32 changes: 32 additions & 0 deletions unirl/rollout/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,38 @@ change surface:
`pipelines/<model>/pipeline.py`; if the AR/DiT worker needs new behavior, add a
`worker/` extension or `patches/compat_<model>.py`.

## SGLang AR knobs

Qwen3 AR recipes (`examples/ar/qwen3_*_sglang*.yaml`) share one **colocate
full-FT** `engine_kwargs` preset. Async/separate and larger-model recipes keep
the same keys and change the memory numbers. Typed `SGLangEngineConfig` fields
overlay `engine_kwargs`; reserved ports always win. Keys that are not live
SGLang `ServerArgs` fields warn at boot (or raise if
`UNIRL_SGLANG_STRICT_SERVER_ARGS=1`) — see [`engine/README.md`](engine/README.md).

**Colocate full-FT preset** (FSDP train shard time-shares the GPU; TensorWeightSync):

| Knob | Preset | Why |
|---|---|---|
| `mem_fraction_static` | `0.3` | Lower SRT KV reservation so FSDP can all-gather full dense weights. `server_intent()` defaults to `0.88` if omitted — too high for colocate. |
| `enable_lora` | `false` | TensorWeightSync pushes full dense weights; a LoRA pool would be the wrong receive path. |
| `cuda_graph_max_bs` | `16` | CUDA graph stays on (`disable_cuda_graph: false`); SGLang's default `256` captures buffers that fight the weight push. |
| `skip_server_warmup` | `true` | Skip SRT warmup on every colocated boot/wake. |
| `attention_backend` | `triton` | Matches the in-tree 4B full-FT recipes. |

**Async / separate** (`*_sglang_async.yaml`): the engine owns the GPU (no colocated
FSDP shard). Raise `mem_fraction_static` to `0.8` and leave the other preset keys
as-is; keep headroom for NCCL weight-receive buffers. Sync is `NCCLWeightSync`.

**LoRA colocate** (`*_sglang_lora.yaml`): `enable_lora: true` plus the SGLang LoRA
pool knobs. This is the exception to the full-FT `enable_lora: false` receive path
(`LocalLoraWeightSync` instead of TensorWeightSync). Memory numbers are recipe-specific.

**Reserved ports:** `SGLangPorts.reserve()` binds HTTP `port` and `nccl_port` on
the engine's node. Server port is capped at 35535 because SGLang derives
`grpc_port = port + 30000`. Do not set `port` / `nccl_port` in `engine_kwargs` —
the reserved sockets overwrite them.

## Gotchas

- **Never recompute σ inside an engine** — the generated Part's pinned sigmas are
Expand Down
6 changes: 6 additions & 0 deletions unirl/rollout/engine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ handler in `../../distributed/weight_sync`.
- **An engine that will serve as an agentic inner must make `generate` safe for
concurrent callers** — the agentic coordinator drives one trajectory per drain
thread.
- **Unknown SGLang `engine_kwargs` are dropped at boot.** HTTP/native backends
filter intent against live `ServerArgs`. Typos used to fail silently; they now
warn, or raise if `UNIRL_SGLANG_STRICT_SERVER_ARGS=1`. UniRL-only keys
(`concurrency`, `advertise_host`, `health_timeout_s`) are expected drops.
Recipe-facing colocate/async knobs live in [`../README.md`](../README.md)
(SGLang AR knobs).
- **One SGLang `MultiprocessingSerializer` LoRA payload is TP1-only.** Stock
upstream serializes with `ForkingPickler`, whose `resource_sharer` file
descriptors are one-shot: broadcasting the same payload to TP>1 scheduler
Expand Down
34 changes: 33 additions & 1 deletion unirl/rollout/engine/sglang/backends/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import base64
import io
import logging
import os
import pickle
from typing import (
Any,
Expand All @@ -15,7 +17,18 @@
runtime_checkable,
)

logger = logging.getLogger(__name__)

_REQUIRED_SERVER_ARGS_METADATA_KEY = "_unirl_required_server_args"
_STRICT_SERVER_ARGS_ENV = "UNIRL_SGLANG_STRICT_SERVER_ARGS"
_UNIRL_ONLY_INTENT_KEYS = frozenset(
{
_REQUIRED_SERVER_ARGS_METADATA_KEY,
"advertise_host",
"concurrency",
"health_timeout_s",
}
)


def _serialize_lora_tensors(
Expand All @@ -32,13 +45,22 @@ def _serialize_lora_tensors(
return base64.b64encode(buf.getvalue()).decode("utf-8")


def _strict_dropped_server_args() -> bool:
return os.environ.get(_STRICT_SERVER_ARGS_ENV, "").strip().lower() in {"1", "true", "yes", "on"}


def _unknown_server_arg_keys(server_intent: Dict[str, Any], allowed: set[str]) -> List[str]:
"""Intent keys that are neither live ``ServerArgs`` fields nor UniRL-only."""
return sorted(key for key in server_intent if key not in allowed and key not in _UNIRL_ONLY_INTENT_KEYS)


def _filter_server_args_or_raise(
server_intent: Dict[str, Any],
*,
allowed: set[str],
backend_name: str,
) -> Dict[str, Any]:
"""Filter ``server_intent`` against real SGLang ``ServerArgs`` fields."""
"""Filter intent against live ServerArgs; unknown keys warn or raise — see ../../README.md."""
raw_required = server_intent.get(_REQUIRED_SERVER_ARGS_METADATA_KEY, ())
if isinstance(raw_required, str):
required = [raw_required]
Expand All @@ -51,6 +73,16 @@ def _filter_server_args_or_raise(
"Upgrade SGLang to a build that supports these fields, or remove the explicit UniRL "
"rollout config that depends on them."
)
dropped = _unknown_server_arg_keys(server_intent, allowed)
if dropped:
message = (
f"SGLang {backend_name} backend dropping unknown ServerArgs keys: {dropped}. "
"They are not fields on the installed SGLang ServerArgs (typo or version skew). "
f"Set {_STRICT_SERVER_ARGS_ENV}=1 to fail closed."
)
if _strict_dropped_server_args():
raise RuntimeError(message)
logger.warning(message)
return {k: v for k, v in server_intent.items() if k != _REQUIRED_SERVER_ARGS_METADATA_KEY and k in allowed}


Expand Down
Loading