Skip to content

fix(verl): preserve routed expert IDs above 255 - #688

Open
Zhengyang Liu (liuzhengyang699) wants to merge 1 commit into
microsoft:mainfrom
liuzhengyang699:fix/preserve-routed-expert-ids
Open

Zhengyang Liu (liuzhengyang699) wants to merge 1 commit into
microsoft:mainfrom
liuzhengyang699:fix/preserve-routed-expert-ids

Conversation

@liuzhengyang699

Copy link
Copy Markdown

Fixes #687.

The R3 adapter casts every decoded routing tensor to uint8. A valid expert ID such as 300 becomes 44, and 511 becomes 255. The replay code later converts these values to int64, but by then the original IDs have already been lost. This affects models with more than 256 experts, including the 512-expert Qwen3.5-397B-A17B configuration.

Keep the compact uint8 batch while IDs fit, and promote it to int32 when a wider ID appears. Promotion also preserves rows already written into the batch. Invalid or out-of-range IDs are rejected before conversion. Padding and one-row-at-a-time decoding are unchanged.

The regression tests cover uint16, int32, and int64 payloads, both row orders around the promotion, and IDs at and above the 255 boundary. All six high-ID cases fail numerically on unchanged main and pass with this patch. Existing small-ID and decoded-row lifetime tests still pass.

Validation

With Python 3.12 and the frozen verl-cpu development environment:

  • uv run --locked --no-sync pytest -v --durations=20 tests — 250 passed, 4 skipped.
  • uv run --locked --no-sync pyright — 0 errors, 0 warnings.
  • uv run --locked --no-sync pre-commit run --all-files --show-diff-on-failure — passed.
  • uv run --locked --no-sync ruff check ., uv run --locked --no-sync ruff format --check ., and uv run --locked --no-sync python scripts/check_headers.py — passed.
  • UV_PROJECT_ENVIRONMENT=/tmp/agent-lightning-r3-docs uv run --locked --no-sync mkdocs build --strict, uv build --no-sources, and git diff --cached --check — passed.

I checked the pinned VERL R3 path: its padding conversion only narrows IDs that fit uint8, and router replay converts the retained tensor to int64. This is a CPU adapter fix; no live GPU/Megatron training or 397B model run was performed.

This issue was found during a follow-up audit with AI assistance. AI assistance was also used for implementation, regression tests, and review.

@liuzhengyang699
Zhengyang Liu (liuzhengyang699) marked this pull request as ready for review November 7, 2026 06:31
Copilot AI balanced review requested due to automatic review settings November 7, 2026 06:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues are identified for the change that preserves expert IDs above 255 in the VERL R3 rollout adapter.

No open issues 🎉

What changed in this PR

Fixes #687 by preserving expert IDs above 255 in the VERL R3 rollout adapter, preventing training from replaying incorrect experts due to integer wrapping.

Changes:

  • Retains compact uint8 storage for small IDs and promotes the batch to int32 when needed, preserving existing rows.
  • Rejects non-integer, negative, and out-of-range IDs before conversion.
  • Adds regression tests for wider payload types, both row orders around promotion, and invalid IDs.
File Description
tests/​verl/​test_rollout_adapter.py Adds high-ID preservation and invalid-ID rejection tests.
agentlightning/​verl/​rollout_adapter.py Validates expert IDs and promotes batch storage without losing values.

Review effort: Balanced

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

R3 adapter silently wraps expert IDs above 255

2 participants