Skip to content

[fix] Avoid inference engine initialization for the SFT code path#1878

Merged
SumanthRH merged 4 commits into
NovaSky-AI:mainfrom
avigyabb:sft-inference-engine
Jul 15, 2026
Merged

[fix] Avoid inference engine initialization for the SFT code path#1878
SumanthRH merged 4 commits into
NovaSky-AI:mainfrom
avigyabb:sft-inference-engine

Conversation

@avigyabb

@avigyabb avigyabb commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

Avoids inference engine initialization for the SFT code path in the Tinker SkyRL-Train backend (P0).

_to_training_batch — the batch-conversion step behind every forward / forward_backward request — unconditionally called _ensure_inference_engines() just to construct a VLLMRenderer. As a result, pure SFT workloads (forward_backward + optim_step, never sampling) still booted the full vLLM inference engine fleet and weight-sync state, wasting GPU memory and startup time.

Changes

  • skyrl/backends/skyrl_train_backend.py: _to_training_batch now scans the batch for ImageChunk / ImageAssetPointerChunk:
    • Text-only batches (the SFT path) render locally via render_model_input — no inference engines, no HTTP.
    • Image-bearing (VLM) batches keep the existing lazy engine init + VLLMRenderer, which needs vLLM's /render endpoint for image placeholder tokens.
  • The other _ensure_inference_engines() call sites (sample, save_sampler_checkpoint) genuinely need engines and are unchanged.

For text-only inputs VLLMRenderer is equivalent to render_model_input (already pinned by test_matches_render_model_input), so rendered output is identical.

Tests

  • New CPU test tests/tinker/skyrl_train/test_text_only_batch_no_inference.py:
    • a text-only batch converts correctly with _ensure_inference_engines stubbed to raise (proving it is never called)
    • an image batch still triggers the lazy engine init
  • Existing tests/backends/skyrl_train/test_renderer.py (5/5) and tests/tinker/skyrl_train/test_sample_session_routing.py pass.

Follow-up: CPU-only render server for VLM batches (commit 2)

Image-bearing training batches previously still initialized the inference engines just to reach vLLM's /v1/chat/completions/render. Rendering is pure CPU preprocessing, so the backend now runs vLLM's GPU-less render server (vllm launch render equivalent) in a child process and points VLLMRenderer at it via a minimal RenderServerClient.

  • New CPURenderServer forces vLLM's CPU platform + explicit cpu device in the child so it also works on GPU-less nodes (e.g. Ray head nodes) where the CUDA wheel cannot infer a device.
  • Started lazily on the first image-bearing batch; torn down in delete_model.
  • Result: forward/forward_backward never initialize inference engines for any workload — engines start only for sample and save_weights_for_sampler.
  • New end-to-end CPU test tests/tinker/skyrl_train/test_render_server.py renders a real image through the server and asserts placeholder splicing plus decoded pixel_values/image_grid_thw.

🤖 Generated with Claude Code

avigyabb and others added 2 commits July 8, 2026 23:09
_to_training_batch in the Tinker SkyRL-Train backend unconditionally
initialized the vLLM inference engines just to construct a VLLMRenderer,
so pure SFT workloads (forward_backward + optim_step, no sampling) paid
for full inference-engine startup and the GPU memory it reserves.

Only image chunks actually need vLLM's render endpoint; text-only
batches now render locally via render_model_input and never touch the
inference engines. Image-bearing (VLM) batches keep the existing lazy
engine init.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Avi Basnet <avigyabb@stanford.edu>
…n training path

Image-bearing training batches previously initialized the full vLLM
inference engines just to reach /v1/chat/completions/render. Rendering
is pure CPU preprocessing (chat template + HF processor), so run vLLM's
GPU-less render server (`vllm launch render` equivalent) in a child
process instead and point VLLMRenderer at it.

The stock CLI infers the device from the current platform, which fails
on GPU-less nodes (e.g. Ray head nodes) with the CUDA wheel; the child
process forces the CPU platform and an explicit cpu DeviceConfig so the
server runs identically everywhere.

With this, forward/forward_backward never initialize inference engines
for any workload -- engines start only for sample and
save_weights_for_sampler.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Avi Basnet <avigyabb@stanford.edu>
@avigyabb
avigyabb requested a review from SumanthRH July 9, 2026 16:37

@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 introduces a CPU-only render server (CPURenderServer) and client (RenderServerClient) to handle multi-modal preprocessing (such as rendering image chunks) on CPU without spinning up a full GPU-based inference engine. Text-only batches are rendered locally, ensuring that the training path avoids inference engine startup overhead. Comprehensive tests have been added to verify these behaviors. The review feedback highlights an opportunity to optimize RenderServerClient by reusing a single httpx.AsyncClient instance across requests to leverage connection pooling and avoid the overhead of repeatedly establishing TCP/SSL connections.

Comment thread skyrl/backends/skyrl_train/inference_servers/render_server.py Outdated

@SumanthRH SumanthRH left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looking good!

I left a comment on connection pooling and about the client used for rendering with VLM RL .

Comment thread skyrl/backends/skyrl_train_backend.py
avigyabb and others added 2 commits July 14, 2026 18:16
Per review on NovaSky-AI#1878: RenderServerClient created a fresh httpx.AsyncClient
per request, defeating connection pooling for the concurrent per-image
render calls within a batch.

Cache one pooled client, mirroring RemoteInferenceClient._get_session:
rebuild it when the running event loop changes (callers drive the
renderer via asyncio.run per batch, so a client bound to the previous
loop is unusable), cap the pool at SKYRL_HTTP_CONNECTION_LIMIT, and keep
keepalive_expiry below uvicorn's 5s server-side keep-alive to avoid
reusing connections the server already closed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Avi Basnet <avigyabb@stanford.edu>
… engines are up

Per review on NovaSky-AI#1878:

- Add RendererClientProtocol in renderer.py and retype
  VLLMRenderer.__init__ to accept it, making the "anything serving
  /v1/chat/completions/render" contract explicit. Satisfied by both
  RemoteInferenceClient and RenderServerClient.
- _create_render_client now branches: when inference engines are
  already initialized (e.g. VLM RL, where sampling brought them up),
  reuse RemoteInferenceClient so render requests fan out across all
  engine API servers; otherwise fall back to the driver-local CPU-only
  render server. SFT still never initializes engines.
- When engines come up, drop any CPU-render-backed renderer and shut
  down the CPU render server so the next image batch upgrades to the
  engine-backed client.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Avi Basnet <avigyabb@stanford.edu>
@SumanthRH

Copy link
Copy Markdown
Member

Looking good! It would be good to do an E2E test for VLM SFT against SkyRL's Tinker API and ensure that the new local render server is used as expected

@SumanthRH

Copy link
Copy Markdown
Member

@SumanthRH
SumanthRH merged commit 32a5dba into NovaSky-AI:main Jul 15, 2026
4 of 5 checks passed
@SumanthRH SumanthRH mentioned this pull request Jul 16, 2026
39 tasks
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