Skip to content

perf(r3): accelerate routed-expert transport with packed arrays - #1909

Merged
erictang000 merged 3 commits into
NovaSky-AI:mainfrom
dyurk-lila:upstream/r3-packed-transport
Aug 3, 2026
Merged

perf(r3): accelerate routed-expert transport with packed arrays#1909
erictang000 merged 3 commits into
NovaSky-AI:mainfrom
dyurk-lila:upstream/r3-packed-transport

Conversation

@dyurk-lila

@dyurk-lila dyurk-lila commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Note on the diff: This is the bottom of the routed-expert-replay / sampler-support series; it applies directly to main. Later PRs in the series stack on top of it.

Problem

The routed-expert (R3) generation path returns one expert ID for every generated token, MoE layer, and top-k slot. Serializing that integer tensor as nested JSON lists creates a large HTTP payload and substantial Python/JSON overhead before training sees the data.

Implementation

  • Compact routed-expert IDs to the smallest safe uint8, int16, or int32 NumPy dtype.
  • Base64-encode the contiguous buffer alongside its shape and dtype, and decode it back into a validated compact NumPy array on the client.
  • Serialize the vLLM response and parse client responses with orjson.
  • Gate packed routes behind the existing routed-expert request flag, so the transport is only used when routed experts are requested.
  • Accept the decoded NumPy route arrays at preprocessing, validating dtype and shape before padding and tensor conversion.

This change is intentionally scoped to transport and preprocessing: it does not alter batching, Experience, device placement, or backend replay setup.

Also included: non-finite sampled logprobs

The /skyrl/v1/generate endpoint previously raised on any non-finite logprob, on the
assumption that orjson would refuse to serialize it. orjson actually emits JSON
null, so the guard was unnecessary — and vLLM does report a non-finite logprob for a
token it just sampled (roughly one per 42 minutes of rollouts at 192-GPU scale).
FastAPI maps the ValueError to HTTP 400, which callers treat as a fatal invariant
violation, so a single token could tear down an entire run.

Non-finite values are now floored to -9999.0, matching what vLLM itself does at its
serving boundaries, with the pre-existing missing-entry branch folded into the same
path. Note isfinite also catches NaN, which vLLM's own max() floor lets through
because max returns its first argument on a False comparison. The loop is extracted
into a vLLM-free helper (logprobs_wire.py) so it is unit-testable without a live
engine, and logs a warning identifying the request and clamp count.

Testing

CPU tests run with:

uv run --isolated --extra dev --extra fsdp pytest \
  tests/backends/skyrl_train/inference_servers/test_remote_inference_client.py \
  tests/backends/skyrl_train/inference_servers/test_routed_experts_wire.py \
  tests/backends/skyrl_train/inference_servers/test_logprobs_wire.py \
  tests/train/dataset/test_preprocess.py \
  tests/train/generators/test_generator_output_utils.py \
  tests/train/generators/test_skyrl_gym_generator.py \
  tests/train/test_trainer_utils.py -q --ignore=tests/backends/skyrl_train/gpu

The suite covers route preprocessing, dtype selection, base64 round trips, malformed payloads, the packed wire codec, and clamping of missing/-inf/NaN sampled logprobs. ruff and black (line length 120) pass on the changed files.

This is part of a small series of routed-expert transport improvements.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@dyurk-lila
dyurk-lila force-pushed the upstream/r3-packed-transport branch from fb01ce9 to fb86814 Compare July 20, 2026 20:25
@erictang000 erictang000 self-assigned this Jul 20, 2026
@dyurk-lila
dyurk-lila force-pushed the upstream/r3-packed-transport branch from fb86814 to b390bc8 Compare July 28, 2026 23:28
Serializing routed-expert IDs as nested JSON lists creates a large HTTP
payload and substantial Python/JSON overhead before training sees the data.

- Compact routed-expert IDs to the smallest safe uint8, int16, or int32 dtype.
- Base64-encode the contiguous buffer alongside its shape and dtype, and
  decode it back into a validated compact NumPy array on the client.
- Serialize the vLLM response and parse client responses with orjson.
- Gate packed routes behind the existing routed-expert request flag.
- Accept the decoded NumPy route arrays at preprocessing, validating dtype
  and shape before padding and tensor conversion.

Because orjson emits JSON null rather than raising for non-finite floats,
the sampled-token logprob path floors missing and non-finite values to
-9999.0 -- the same floor vLLM applies at its own serving boundaries. This
keeps one bad logprob from failing the whole generate request. Note the
isfinite test also catches NaN, which vLLM's max(logprob, -9999.0) misses
since max returns its first argument on a False comparison.

This change is intentionally scoped to transport and preprocessing: it does
not alter batching, Experience, device placement, or backend replay setup.
@dyurk-lila
dyurk-lila force-pushed the upstream/r3-packed-transport branch from b390bc8 to a81e61d Compare July 29, 2026 21:07
@erictang000

Copy link
Copy Markdown
Collaborator

/gemini review

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request optimizes the serialization and transmission of routed expert indices and logprobs between the vLLM server and the remote inference client by introducing a binary payload contract using base64-encoded NumPy arrays. Key feedback includes safely detaching and moving CUDA tensors to the CPU before NumPy conversion in the server actor, using more robust dictionary retrieval for logprobs to prevent potential attribute errors, and relaxing shape dimension type checks to accommodate NumPy integer types.

Comment thread skyrl/backends/skyrl_train/inference_servers/vllm_server_actor.py Outdated
Comment thread skyrl/backends/skyrl_train/inference_servers/generate_wire.py Outdated
Comment thread skyrl/backends/skyrl_train/inference_servers/generate_wire.py Outdated
@erictang000
erictang000 merged commit 42f3d44 into NovaSky-AI:main Aug 3, 2026
4 of 6 checks passed
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.

2 participants