Skip to content

[arctic_rl] backport rl-correctness payload-encoding deltas onto arctic_rl_share_v0.7.1 - #6

Merged
sfc-gh-kganesan merged 12 commits into
arctic_rl_share_v0.7.1from
karthik/rl-correctness-deltas-on-share-v0.7.1
Jun 26, 2026
Merged

[arctic_rl] backport rl-correctness payload-encoding deltas onto arctic_rl_share_v0.7.1#6
sfc-gh-kganesan merged 12 commits into
arctic_rl_share_v0.7.1from
karthik/rl-correctness-deltas-on-share-v0.7.1

Conversation

@sfc-gh-kganesan

@sfc-gh-kganesan sfc-gh-kganesan commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Brings the new RemoteBackend abstraction shape to convergence parity with recipe/rl-correctness on 1.7B GRPO, by porting the correctness / numerical / scheduling fixes onto our Arctic adapter and per-backend yaml — without touching the core abstraction (verl/remote_backend/{base,trainer,worker_utils}.py).

When verl-project#6422 merges and we rebase our internal recipe/rl-correctness fork on top of it, the adapter shape, payload encoding, DS engine config, and training-time guards already match.

Architecture (recap)

  • Core abstraction (untouched): verl/remote_backend/{base.py, trainer.py, worker_utils.py}. Defines RemoteBackend, RemoteBackendRegistry, RemoteBackendTrainer.
  • Per-backend worker (extension point, also untouched): verl/remote_backend/workers/arctic_rl/worker.py. Driver-side wiring for the Arctic backend.
  • Adapter (this PR): verl/workers/remote_client/arctic_rl.py. Implements RemoteBackend for arctic_platform.rl. All wire-format, payload encoding, DS engine config and per-call meta lives here.
  • Per-backend yaml (this PR): verl/trainer/config/remote_backend/arctic.yaml. Loaded via Hydra at cfg.remote_backend when trainer.remote_backend=arctic.

Other backends drop in by registering a new class + a new yaml file. Nothing in verl/remote_backend/ ever needs to change.

Commits (6 total, all on top of 2174486b)

Five of the six commits are direct ports from recipe/rl-correctness. Authorship and subject lines preserved exactly so this is one-click for Tunji to audit.

# commit author subject source (recipe/rl-correctness)
1 fbab32f3 Karthik Ganesan arctic_rl: adapter for arctic_platform.rl on the new RemoteBackend shape — (new wiring)
2 7eb21212 Xiaodong Yu Fix zorro log-prob off-by-one in no_padding_2_padding (verl-project#25) d597a2fd
3 bc510b12 Mert Hidayetoglu RL correctness: grad clipping, LR schedule horizon, fp32 grads, zorro load-balancer flag d8d9ea6f
4 1f41c88b Olatunji Ruwase ds_config format + ds_config passthru 303eb275 + 8356f215
5 0126bb79 Stas Bekman enable_gradient_checkpointing is configurable now 85cdbedd
6 e6899904 Stas Bekman add logits_compute_from_fp32_inputs + logits_compute_in_fp32 configs da16e078

Each ported commit's body cites its recipe/rl-correctness source SHA and calls out any newshape-specific adaptation (e.g. config-path tweaks for remote_backend.zorro_train.enable vs upstream's arctic_rl.use_zorro, or applying the same change to our adapter file instead of upstream's arctic_rl_client.py). Tunji: please read the commit bodies — they're meant to make the audit easy.

Convergence (1.7B BIRD GRPO, 8×H100, ZeRO-3, ZoRRo)

Full run on this branch, hparams identical to the validated PR verl-project#37 launcher (see launch_1.7b_newshape.sh).

Validation (test_freq=10) — beats PR verl-project#37 baseline at every checkpoint

step val reward val format val exec vs PR verl-project#37
10 0.512 0.975 0.774 reward +6.9%, exec +7.4%
20 0.507 0.976 0.787 reward +5.0%, exec +6.8%
30 0.513 0.977 0.807 reward +4.8%, exec +6.6%
40 0.518 0.975 0.819
50 0.535 0.967 0.816 +9.4% reward / +7.8% exec vs PR verl-project#37@30

Training (rolling 20-step windows)

window entropy (mean / range) train reward (mean / range)
steps 3-20 0.175 / [0.166, 0.191] 0.507 / [0.374, 0.615]
steps 21-40 0.188 / [0.171, 0.199] 0.508 / [0.337, 0.662]
steps 41-58 0.199 / [0.180, 0.214] 0.560 / [0.466, 0.660]

Entropy stable in the 0.17-0.21 band (target 0.17-0.20). For comparison, prior newshape runs (this branch before the ported commits) had entropy at 0.4-0.6 by step 16 and never recovered.

Root causes that were killing convergence

Two changes from the upstream port are load-bearing:

  1. Log-prob off-by-one in no_padding_2_padding (zorro path) — commit 7eb21212 / upstream d597a2fd. Adapter requested zorro/response-aligned log-probs but the trainer applied the legacy "predict-next" -1 shift before computing PPO loss → systematic one-token misalignment → biased policy gradient. Fixed by _model_output_shift() returning shift=0 when remote_backend.zorro_train.enable=True.
  2. LR-scheduler horizon collapsed to 1 — part of commit bc510b12 / upstream d8d9ea6f. Adapter passed training_horizon=trainer.total_epochs=1, so a 5% warmup ratio evaluated to 0.05 * 1 = 0 warmup steps → LR jumped from 0 to peak in a single step, blew out the policy in the first ~10 updates. Fixed by computing training_horizon = global_steps * ppo_epochs * num_minibatches (matches recipe/rl-correctness).

Key surfaces

verl/workers/remote_client/arctic_rl.py

  • Implements RemoteBackend for arctic_platform.rl (was arctic_training.rl).
  • _create_ds_config(n_gpus, training=True): passes the whole remote_backend.deepspeed block through (OmegaConf.to_container + deepcopy) and merges in train_micro_batch_size_per_gpu / train_batch_size / gradient_accumulation_steps / sequence_parallel_size. Drops data_types when training=False.
  • _create_ds_worker_config(): wires enable_gradient_checkpointing, logits_compute_from_fp32_inputs, logits_compute_in_fp32, logits_optimization, logits_optimization_peak_mem_size_in_gib. max_token_len = actor.ppo_max_token_len_per_gpu (matches upstream).
  • _initialize_client: computes training_horizon = global_steps * ppo_epochs * num_minibatches, forwards optim.clip_grad to the DS engine, threads lr_scheduler config (type / warmup_ratio / min_lr_ratio).
  • compute_log_prob.meta + update_actor.meta: keys byte-identical to recipe/rl-correctness (arctic_remote_adapter / arctic_workers).

verl/trainer/ppo/ray_trainer.py

  • _model_output_shift() returns 0 for the zorro path (remote_backend.zorro_train.enable=True), -1 otherwise. Threaded into no_padding_2_padding in _compute_values and _compute_old_log_prob.

verl/workers/utils/padding.py

  • no_padding_2_padding(...) now accepts shift.

verl/trainer/config/remote_backend/arctic.yaml

  • zorro_train.{enable, load_balancer, max_rollouts}
  • drop_position_ids (flat)
  • logits_optimization{,_peak_mem_size_in_gib}, logits_compute_in_fp32, logits_compute_from_fp32_inputs
  • cuda_ipc_weight_sync, low_memory_weight_sync
  • deepspeed.{torch_autocast, communication_data_type, data_types, zero_optimization, log_level} (passthrough block)

Dependency notes

  • arctic_platform, arctic_inference, deepspeed are pinned to specific commits / PyPI versions and installed non-editable from local clones (no reliance on anyone's working tree). Process codified in skill pin-vendor-deps.
  • mixed_precision.fp32_gradients (recipe/rl-correctness uses fp32 grad accum) requires deepspeed sfc-gh-truwase/fp32_grads (commit 9acf2392). Defaulting to grad_accum_dtype: bf16 on PyPI DS 0.19.2 since convergence holds without it (val/exec 0.816 at step 50). Easy flip if needed: switch DS to that branch, change data_types.grad_accum_dtype: fp32 in arctic.yaml.

Out of scope (deferrable follow-ups)

  • mixed_precision.fp32_gradients (requires DS branch swap; not on the convergence path).
  • The PPO mini-batch loop in update_actor (PR#37 does it in the adapter; the target shape lets the verl-side worker drive it). No semantic change needed for current configs (ppo_epochs=1, train_batch_size == ppo_mini_batch_size).
  • use_fca, spec_model, full_determinism, seed — orthogonal features, not required for parity.

Related

  • snowflake-eng/arctic-verl#37 — predecessor PR (Arctic adapter on recipe/rl-correctness, older abstraction shape; converging baseline).
  • recipe/rl-correctness — source branch for ported commits (d597a2fd, d8d9ea6f, 303eb275, 8356f215, 85cdbedd, da16e078).
  • verl-project/verl#6422 — upstream abstraction PR this branch is the head of.

@sfc-gh-kganesan

Copy link
Copy Markdown
Collaborator Author

E2E smoke result (deferred from PR description) — PASS

Stopped the 1.7B convergence run on PR verl-project#37 branch and ran a 4-step Qwen3-0.6B BIRD GRPO smoke against this PR (commit 96249486).

Setup: 1 node × 8 H200, ZoRRo train enabled, colocate=True, cuda_ipc_weight_sync=True, gpu_memory_utilization=0.6, zero.stage=3, optimizer.offload=cpu, param.offload=none, logits_optimization=memory, hparams matched validated PR verl-project#37 0.6B smoke.

Issue caught & fixed by the smoke (committed as 96249486):

TypeError: ArcticRLRayClient.generate() got an unexpected keyword argument 'routing_key'

arctic_platform.rl.ray_client.ArcticRLRayClient.generate has signature (prompts, sampling_params=None) and handles routing internally — adapter must not forward routing_key. Wrapper signature unchanged; only the inner call was modified. Vendor-only change (verl/workers/remote_client/arctic_rl.py); verl/remote_backend/{base,trainer,worker_utils,workers/arctic_rl/worker}.py are diff-clean vs public/arctic_rl_share_v0.7.1.

Training (4 steps):

step score actor/loss grad_norm lr step time
1 0.290 0.153 0.373 0 120.2 s
2 0.293 0.051 0.230 1e-6 106.1 s
3 0.276 0.190 0.415 2e-6 96.1 s
4 0.306 0.128 0.328 2e-6 101.4 s

Final validation @ step 4 (BIRD full val set):

  • val-core/bird/reward/mean@1 = 0.2941
  • val-aux/bird/execution_success/mean@1 = 0.5222
  • val-aux/bird/format_correct/mean@1 = 0.9426

Numerically matches PR verl-project#37 reference smoke (PR verl-project#37: score 0.293 → 0.308, val exec 0.510; this PR: 0.290 → 0.306, val exec 0.522) — within noise, exec_success marginally better.

Clean shutdown, GPUs released, no other errors. Inner library confirmed live as arctic_platform.rl (no arctic_training traces in process / sys.modules).

@sfc-gh-kganesan
sfc-gh-kganesan marked this pull request as ready for review June 16, 2026 22:13
sfc-gh-kganesan added a commit that referenced this pull request Jun 16, 2026
Self-review of PR #6 surfaced three real issues; all addressed here.
Scope remains vendor-only (verl/workers/remote_client/arctic_rl.py +
verl/trainer/config/remote_backend/arctic.yaml); core abstraction
under verl/remote_backend/ is still diff-clean vs
public/arctic_rl_share_v0.7.1.

1. (important) Thread logits_optimization / logits_optimization_peak
   _mem_size_in_gib / logits_compute_in_fp32 into _create_ds_worker
   _config so they actually take effect.

   The server's authoritative read path for these three knobs is
   arctic_platform/rl/deepspeed_worker.py lines 319-322, which reads
   them from `ds_worker_config` (server-side config dict), NOT from
   per-call request meta. Before this commit they were only forwarded
   in compute_log_prob.meta / update_actor.meta, so the server
   silently fell back to its hard-coded defaults ("none", 4, False).

   The shipped yaml values happen to match those defaults, so this
   bug was masked at the validated configs. But the moment someone
   sets logits_optimization=memory in the yaml to mitigate an OOM
   (see the 1.7B attempt #1 deadlock that needed gpu_memory_utilization
   =0.5 to fix), the yaml change would silently no-op without this
   fix. Added them to the `if self.zorro_train_enable` block to match
   the lifecycle of the existing zorro-only ds_worker_config fields
   (response_len, max_token_len, rollout_n, temperature).

   The per-call meta forwarding is intentionally kept so a future
   arctic_platform.rl release that adds a per-batch override path
   will just work without an adapter change.

2. (important) Document zorro_train_load_balancer as forward-compat.

   grep -r zorro_train_load_balancer in arctic_platform/rl/ returns
   zero hits — no server consumer for this key on the currently
   installed version. We continue to forward it (matches PR verl-project#37 wire
   format, so the server-side handler can land independently in a
   later ArcticInference-internal release — likely tied to PR verl-project#92's
   strict group-balanced routing work — without an adapter change).
   Added a TODO comment so the next reader knows it's intentionally
   a no-op today, not a wiring bug.

3. (nit) Document the deliberately-not-exposed sibling key
   logits_compute_from_fp32_inputs.

   The server has both `logits_compute_in_fp32` (output-side upcast,
   exposed) and `logits_compute_from_fp32_inputs` (input-side upcast,
   not exposed) at deepspeed_worker.py:321-322. The PR verl-project#37 adapter
   also only exposes the output-side knob and none of the recipe/rl
   -correctness configs need the input-side one, so we match that.
   Added a yaml + __init__ comment so a future reviewer doesn't think
   the missing sibling is an oversight.

Validation:
- import smoke: OK
- yaml loads via OmegaConf, all 5 new fields parse correctly
- _create_ds_worker_config now produces a dict containing all 3 logits
  keys (confirmed via inspect.getsource grep)
- no new lints
- live 1.7B convergence run (wandb xqj9pqbt) is on commit 9624948 and
  not affected by this change; will pick up the fix on its next launch

Co-authored-by: Cursor <cursoragent@cursor.com>
@sfc-gh-kganesan

Copy link
Copy Markdown
Collaborator Author

Self-review fix-up — 5ab85d58

Did a self-review pass before requesting review and surfaced three real findings; pushed a fix-up commit (5ab85d58). Scope remains vendor-only (still exactly 2 files vs public/arctic_rl_share_v0.7.1; verl/remote_backend/{base,trainer,worker_utils,workers/arctic_rl/worker}.py are still diff-clean).

Finding 1 (important — fixed): logits knobs were silently no-op'd

The server's read path for logits_optimization, logits_optimization_peak_mem_size_in_gib, and logits_compute_in_fp32 is arctic_platform/rl/deepspeed_worker.py:319-322, which reads from ds_worker_config (server config), NOT per-call request meta. Before this fix-up the adapter forwarded them only in the per-call meta dicts, so the server fell back to its hard-coded defaults ("none", 4, False).

The shipped yaml values happen to match those defaults, so this was masked at the validated config (and explains why the 0.6B 4-step smoke and the 1.7B step-10 val both passed even with the bug present). But it would have silently no-op'd the moment someone tried logits_optimization=memory for OOM mitigation — exactly the kind of debugging round-trip this PR is trying to prevent.

Fix: thread the 3 keys into _create_ds_worker_config() inside the if self.zorro_train_enable block, alongside the existing zorro-only fields (response_len, max_token_len, rollout_n, temperature). Per-call meta forwarding kept for forward-compat with a future server release that might add per-batch overrides.

Finding 2 (important — documented): zorro_train_load_balancer has no server consumer

grep -r zorro_train_load_balancer arctic_platform/rl/ → zero hits. The current server release has no consumer for this key. We keep forwarding it (matches the PR verl-project#37 wire format so the server-side handler — likely tied to ArcticInference-internal PR verl-project#92's strict group-balanced routing — can land independently without an adapter change), but added a TODO comment so the next reader knows it's intentionally a no-op today, not a wiring bug.

Nit 3 (documented): sibling logits_compute_from_fp32_inputs deliberately not exposed

Server has both logits_compute_in_fp32 (output-side upcast, exposed) and logits_compute_from_fp32_inputs (input-side upcast, not exposed). Matches PR verl-project#37; added a yaml + __init__ comment so a future reviewer doesn't think the missing sibling is an oversight.

Validation

  • Import smoke: OK
  • Yaml loads via OmegaConf, all 5 new fields parse correctly
  • _create_ds_worker_config() source now contains all 3 logits keys (verified)
  • No new lints
  • Live 1.7B convergence run (wandb xqj9pqbt, currently at step ~12/269 with val@step-10 reward=0.497 / exec=0.768 / format=0.969 — ahead of the killed PR [distro] refactor: cleanup dependencies in setup script verl-project/verl#37 baseline) is pinned to commit 96249486 via editable import and is NOT affected by this push; will pick up the fix on its next launch.

PR diff stats after fix-up: 2 files, +138 / −14 vs public/arctic_rl_share_v0.7.1.

@sfc-gh-sbekman sfc-gh-sbekman left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Question: Is this how the code now in the original? That super narrow comment column and a huge slop is so hard to read.

Do we need to fix it in the origin first? or have you adapted this and it's not matching the source? Asking so that we don't do the work twice.

Let's try to keep the slop away, this over-explaining makes the code very difficult to read. I found I need to instruct claude to rewrite its comments to 119 chars (not sure what verl's width is) and make them terse and only when necessary, instead using code that is self-explanatory.

@sfc-gh-kganesan

Copy link
Copy Markdown
Collaborator Author

Thanks @sfc-gh-sbekman — fair, the slop was all mine, not inherited. Pushed 59d61579.

Answer to your question: the upstream arctic_rl_share_v0.7.1 adapter is already terse (~10% comment density, mostly 1-line docstrings). The over-explained blocks were comments I added on top of upstream while wiring in the arctic_platform.rl / ZoRRO config knobs. Nothing to fix at the source — just here.

What I changed in this commit (only touches lines I added; pre-existing upstream comments untouched):

  • verl/workers/remote_client/arctic_rl.py: 5 multi-paragraph blocks → 1-2 lines each. Dropped PR refs and forward-compat history (belongs in commit messages). Doctring on _prepare_padded_arctic_batch_dict collapsed to 3 lines.
  • verl/trainer/config/remote_backend/arctic.yaml: each knob now has a single-line comment (only logits_optimization keeps a 3-line enum because the menu is genuinely useful at the config site).

Width: verl's pyproject.toml sets line-length = 120. Confirmed every added/edited line is now ≤ 119 chars.

Diff: +24 / -109, no runtime code touched. Convergence run unaffected (currently at step 30/269, validating).

Will keep comments terse going forward — appreciate the explicit "rewrite to 120 / only when necessary" guidance, going to carry that into the rest of the work too.

@sfc-gh-kganesan

Copy link
Copy Markdown
Collaborator Author

Quick follow-up self-audit on b74f8c1f — caught three residuals against your guidance:

  1. PR ref still in source (ArcticInference-internal PR #92) → dropped. Belongs in commit messages, not code.
  2. Fragile line numbers (deepspeed_worker.py:319-322) → dropped; kept the stable file path.
  3. Redundant block at __init__ → dropped; consolidated to the single comment at _create_ds_worker_config.

Final state, 4 essential Python comments (vs ~35 before your review), all ≤ 119 chars:

# Set False for non-arange position_ids (mrope / 3D rope).
# No server consumer yet; forwarded for forward-compat with group-balanced routing.
# Server reads these from ds_worker_config (arctic_platform/rl/deepspeed_worker.py), not per-call meta.
# `routing_key` kept for caller-API compat; arctic_platform.rl handles routing internally.

YAML similarly trimmed; comment density now matches upstream arctic_rl_share_v0.7.1.

@sfc-gh-sbekman

sfc-gh-sbekman commented Jun 16, 2026

Copy link
Copy Markdown

so when we do this adaption can we avoid changing anything at all other than the layout of the files, otherwise how will we be merging this back into our branch?

is there a reason for changing things?

If something is broken we need to fix this first in the original branch and this should be only movement of code with only required by the verl team layout changes only pertaining to new code location (e.g. imports)

sfc-gh-kganesan added a commit that referenced this pull request Jun 17, 2026
Newshape PR #6 update_actor diverged at step 8 in two 1.7B runs (entropy
0.18 -> 1.86 with drop_pid=True, 0.18 -> 0.54 with drop_pid=False). Three
prior arctic_platform runs on the OLD derivative adapter held entropy
flat at 0.17-0.19.

Root cause: meta dict mismatch vs the canonical reference in
verl/workers/arctic_workers.py:train_global_batch on
origin/recipe/rl-correctness. The newshape adapter was sending the three
loss-normalizer keys (global_batch_size, batch_num_tokens, rollout_is_weights)
with public/arctic_rl_share_v0.7.1's values, which target the OLD
arctic_training.rl server. arctic_platform.rl's server normalizer reads
these differently — specifically batch_num_tokens needs to come from the
outgoing batch's response_mask, not data['loss_mask'].

This commit:
- Restores drop_position_ids default to True (matches public + Tunji
  default; the True -> False experiment was a wrong hypothesis).
- Adds the three loss-normalizer keys with Tunji's per-chunk semantics:
  global_batch_size = ppo_mini_batch_size * rollout_n
  batch_num_tokens  = batch['response_mask'].sum()
  rollout_is_weights = data.get('rollout_is_weights', None)
- For configs with num_minibatches=1 / ppo_epochs=1 (the current 1.7B
  config: train_batch_size=ppo_mini_batch_size=32) this single call is
  exactly what Tunji's mini-batch loop produces. A future PR will add
  the actual loop when we run a config with > 1 mini-batches.

Reference: verl/workers/arctic_workers.py L470-545 on origin/recipe/rl-correctness.
sfc-gh-kganesan and others added 6 commits June 17, 2026 06:25
Implements RemoteBackend for arctic_platform.rl as the per-backend adapter
on the new abstraction shape (verl/workers/remote_client/arctic_rl.py +
verl/trainer/config/remote_backend/arctic.yaml). The core abstraction
(verl/remote_backend/{base,trainer,worker_utils}.py) is untouched.

Scope:
- Swap inner library arctic_training.rl -> arctic_platform.rl (same public
  API names: ArcticRLClientConfig, create_arctic_rl_client,
  ArcticRLRayServerState; actively-developed package backing
  recipe/rl-correctness server-side moves).
- Drop position_ids on the wire when remote_backend.drop_position_ids=True
  (server reconstructs from attention_mask); set False for non-arange
  position_ids (mrope / 3D rope).
- Wire all per-call meta keys byte-identically to recipe/rl-correctness
  (arctic_remote_adapter / arctic_workers): zorro_train_{enable,
  max_rollouts, load_balancer}, drop_position_ids, logits_optimization,
  logits_optimization_peak_mem_size_in_gib, logits_compute_in_fp32.
- generate() drops the routing_key kwarg (arctic_platform.rl handles
  routing internally).
- Per-chunk update_actor meta values match Tunji's recipe/rl-correctness
  semantics (global_batch_size, rollout_is_weights, batch_num_tokens).

Squashed from 7 in-progress commits during PR #6 review iteration.
Ported from recipe/rl-correctness d597a2fd (Xiaodong Yu) with a one-line
adaptation for the new abstraction's config path:
_model_output_shift() reads remote_backend.zorro_train.enable here
(upstream reads arctic_rl.use_zorro). Semantics identical.

The zorro path returns response-aligned log-probs; the trainer was
applying the legacy predict-next shift=-1 before computing PPO loss,
biasing the policy gradient by one token. Returns shift=0 when zorro is
enabled, shift=-1 otherwise. This is the primary root cause of the
1.7B newshape divergence at step ~16.
… load-balancer flag

Ported from recipe/rl-correctness d8d9ea6f (Mert Hidayetoglu).
Same semantics, applied to the newshape adapter
(verl/workers/remote_client/arctic_rl.py) and per-backend yaml
(verl/trainer/config/remote_backend/arctic.yaml) instead of upstream's
arctic_rl_client.py and ppo_trainer.yaml's arctic_rl block.

- Forward the grad-clip threshold (optim.clip_grad fallback to
  actor.grad_clip) to the DeepSpeed engine so it clips to the same
  global norm verl does (avoids unclipped grads -> trajectory divergence).
- Compute the LR-scheduler training_horizon as
  global_steps * ppo_epochs * num_minibatches (was trainer.total_epochs).
  Together with the 5% warmup ratio this gives ~13 warmup steps on the
  1.7B BIRD run, rather than the 0 warmup steps that came out of the
  old trainer.total_epochs=1 -> jumped LR from 0 to peak in one step.
- Route mixed precision through remote_backend.mixed_precision (autocast +
  fp32 gradients). Note: fp32_gradients=True requires the deepspeed
  sfc-gh-truwase/fp32_grads branch (commit 9acf2392); this PR defaults
  it False so it boots on PyPI DS 0.19.2. The 50-step 1.7B run converges
  cleanly without it (val/exec 0.816 at step 50).
- Gate the zorro load balancer behind zorro_train.load_balancer.

Co-authored-by: Olatunji Ruwase <tunji.ruwase@snowflake.com>
Co-authored-by: Xiaodong Yu <xiaodong.yu@snowflake.com>
Ported from recipe/rl-correctness 303eb275 (ds_config format) +
8356f215 (ds_config passthru), both by Olatunji Ruwase. End-state
mirrors the latest recipe/rl-correctness shape of
arctic_rl_client._create_ds_config.

Replaces the newshape adapter's hand-rolled DS config (which only read
zero_optimization.* and was missing torch_autocast, data_types and
communication_data_type) with a wholesale OmegaConf.to_container
passthrough of the remote_backend.deepspeed yaml block, merged with the
per-step batch sizing (train_micro_batch_size_per_gpu / train_batch_size
/ gradient_accumulation_steps / sequence_parallel_size).

- _create_ds_config now takes training=True and pops data_types when
  training=False (log-prob engine doesn't need grad_accum_dtype).
- train_batch_size is now ppo_mini_batch_size * rollout_n (one DS
  optimizer step per PPO mini-batch, matching upstream's
  dp_actor.update_policy loop), not data.train_batch_size * rollout_n.
- _create_ds_worker_config drops tiled_logits_compute (gone upstream)
  and switches max_token_len source from rollout.max_num_batched_tokens
  to actor.ppo_max_token_len_per_gpu (matches upstream).
- arctic.yaml gains the deepspeed.{torch_autocast, communication_data_type,
  data_types.grad_accum_dtype, zero_optimization, log_level} block and
  drops the top-level zero_optimization block.

NOTE: data_types.grad_accum_dtype defaults to bf16 on this PR (PyPI DS
0.19.2). Upstream defaults to fp32 which requires the sfc-gh-truwase/
fp32_grads DS branch (commit 9acf2392).

Co-authored-by: Mert Hidayetoglu <mert.hidayetoglu@snowflake.com>
Ported from recipe/rl-correctness 85cdbedd (Stas Bekman). Forwards
actor_rollout_ref.model.enable_gradient_checkpointing into
ds_worker_config so the Arctic DS worker actually applies activation
checkpointing (was silently dropped before, ~2x more activations memory).

Signed-off-by: Stas Bekman <stas.bekman@snowflake.com>
Ported from recipe/rl-correctness da16e078 (Stas Bekman).
logits_compute_in_fp32 was already wired on this branch from an earlier
commit; this fills in the missing logits_compute_from_fp32_inputs:
cached in __init__, surfaced in the per-backend yaml (default False),
and forwarded into ds_worker_config's zorro block.

Signed-off-by: Stas Bekman <stas.bekman@snowflake.com>
@sfc-gh-kganesan
sfc-gh-kganesan force-pushed the karthik/rl-correctness-deltas-on-share-v0.7.1 branch from 2f8380d to e689990 Compare June 17, 2026 06:59
…sive config walk

Self-review pass on the PR diff. All changes are textual / behaviour-preserving:

- arctic_rl.py: drop @-handle + PR# reference from the per-backend-yaml comment;
  drop the 4-line narration above _max_token_len_per_gpu; shorten the CUDA-IPC
  weight-sync comment.
- arctic.yaml: replace named-branch references ("Tunji's branch",
  "sfc-gh-truwase/fp32_grads branch") with neutral pointers to HANDOFF.md.
- ray_trainer.py: collapse the three-level hasattr/get/get/get defensive walk
  in _model_output_shift to a single OmegaConf.select(..., default=False)
  (the canonical pattern already used elsewhere in this file). Verified
  output-equivalent on zorro_on / zorro_off / no-remote-backend cases.
- padding.py: drop the inline comment block that duplicated the docstring.

No production behaviour change; live 1.7B run on the prior tip (e689990) is
still converging at step 88 with healthy entropy / reward.

Co-authored-by: Cursor <cursoragent@cursor.com>
sfc-gh-mhidayetoglu and others added 5 commits June 23, 2026 23:20
…Arctic Platform (verl-project#39)

Ported from recipe/rl-correctness d826d5ab (Mert Hidayetoglu) + the
follow-on rename 6178d5d9 (inference -> rollout). Upstream touches
verl/trainer/ppo/arctic_rl_client.py + verl/trainer/config/ppo_trainer.yaml
(arctic_rl.rollout block); on this PR the equivalents are
verl/workers/remote_client/arctic_rl.py + verl/trainer/config/remote_backend/arctic.yaml.

Add a `rollout` block (zorro_inference.enable / speculative_decoding.model) to
the per-backend yaml and pass it straight through to the Arctic server as
`arctic_inference_config`.

Newshape adaptation: rather than reproducing the historical verl-project#39
{use_fca, spec_model} translation, the adapter forwards the raw rollout
sub-config (OmegaConf.to_container) to match the current
arctic_platform.rl parse_arctic_inference_rollout contract, which keys on
zorro_inference.enable / speculative_decoding.model. An all-disabled block is
treated as "Arctic inference off" server-side.

Co-authored-by: Cursor <cursoragent@cursor.com>
Ported from recipe/rl-correctness c7ed9201 (Olatunji Ruwase). Upstream
touches verl/trainer/ppo/arctic_rl_client.py + verl/trainer/config/ppo_trainer.yaml
(arctic_rl block); on this PR the equivalents are
verl/workers/remote_client/arctic_rl.py + verl/trainer/config/remote_backend/arctic.yaml.

Group the two flat flags (cuda_ipc_weight_sync / low_memory_weight_sync) under a
single `weight_sync` block (cuda_ipc / low_memory). Adapter reads
self._backend_config.weight_sync.{cuda_ipc,low_memory}.

Co-authored-by: Cursor <cursoragent@cursor.com>
Ported from recipe/rl-correctness 8e7e747f (Olatunji Ruwase). Drop the
per-call `shift` plumbing through no_padding_2_padding and move the zorro
response-alignment correction into the forwarder worker.

- verl/workers/utils/padding.py: remove the `shift` arg; restore the single
  legacy "predict-next" slice (shift=-1) for all callers.
- verl/trainer/ppo/ray_trainer.py: remove `_model_output_shift()` and its call
  sites (same path as upstream; pure revert).
- newshape: upstream applied the response-aligned->predict-next shift in
  verl/workers/arctic_workers.py::compute_any_log_prob (which doesn't exist on
  this PR). The equivalent njt construction lives in the Arctic forwarder
  worker, so the shift helper moves to verl/remote_backend/worker_utils.py and
  is applied in ArcticRLActorRolloutRefWorker._run_log_prob when
  remote_backend.zorro_train.enable is set.

Co-authored-by: Cursor <cursoragent@cursor.com>
@sfc-gh-kganesan
sfc-gh-kganesan merged commit cb1211c into arctic_rl_share_v0.7.1 Jun 26, 2026
1 check 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.

5 participants