Skip to content

Enable the SLIME GRPO test case to run end-to-end on B300 / H200 - #1164

Merged
allela-roy merged 14 commits into
awslabs:mainfrom
littlemex:epic/enable-slime-grpo-on-b300-h200
Jul 10, 2026
Merged

Enable the SLIME GRPO test case to run end-to-end on B300 / H200#1164
allela-roy merged 14 commits into
awslabs:mainfrom
littlemex:epic/enable-slime-grpo-on-b300-h200

Conversation

@littlemex

@littlemex littlemex commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Purpose

Relates to #1163.

This is the integration PR for a small epic: making the SLIME GRPO test case (3.test_cases/pytorch/slime, added in #1129) run through to training on NVIDIA B300 (p6) and H200 (p5en). Bringing the test case up surfaced a series of issues, each of which is a small, self-contained fix. Rather than one large "B300 support" change, the epic lands them as focused commits on this branch so each is easy to review, and this PR tracks the overall progress.

Thanks to the authors and reviewers of #1129 for the foundation this builds on: the container image, the reward-service split, the RayCluster manifests and the docs. The reward path works as designed, and every change here is scoped to getting training to start and run.

How this PR is organized

Each fix is one focused commit. The mechanism, reproduction commands, and evidence for a fix live in a dedicated comment on this PR, not in this description. This description only tracks the overall goal, the scope, and the progress checklist.

Scope and progress

The findings from #1163 are grouped by root cause. Most are general (they affect the documented p5/HyperPod path too — CUDA 13 and dependency issues, not GPU-generation-specific); a few are scoped to the 30B MoE recipe and are tracked separately below. Each item links to its detail comment as it lands.

General fixes (affect the documented p5/HyperPod path too; CUDA 13 / dependency issues, not GPU-generation-specific):

  • MODEL_ARGS reaches train.py as zero elements, so training never starts. Fixed by launching through a small launcher script instead of ray job submit -- bash -c "...".

  • --sglang-log-level WARN breaks uvicorn startup (uvicorn accepts lowercase log levels only), so the rollout HTTP server never binds and training hangs. Fixed by using lowercase warning (preserving the original intended verbosity).

  • The train worker dies on CUDA 13 because SLIME LD_PRELOADs a cu12-linked torch_memory_saver .so. This is a CUDA-13 issue, not GPU-generation-specific: it reproduces on any CUDA-13 image (the test case's NGC 26.02 base), on H100/H200/B300 alike. Proper fix filed upstream in SLIME (delegate .so selection to torch_memory_saver's own CUDA-aware resolver); test-case side applies the same fix in place via a self-neutralizing build-time patch (no fork, no forked URL, no-op once upstream merges it).

  • Megatron aborts on numpy 2.x pulled in transitively by sglang[all]. Fixed by pinning numpy<2 in requirements.txt (the last dependency step that touches numpy), matching upstream SLIME's own Dockerfile. numpy is a pure-CPU package, so this is GPU-generation- and CUDA-independent (identical on H100/H200/B300).

  • 30B MoE torch_dist conversion needs mbridge, which the --no-deps slime install does not pull. Fix: pip install --no-deps mbridge in slime.Dockerfile.

  • Megatron validate_args eagerly probes the CUDA device (get_device_capability for --moe-grouped-gemm; get_device_arch_version for the TP/CP note), but SLIME runs validate_args on the GPU-less Ray driver, so it crashes with Found no NVIDIA driver. Only the MoE + TP/CP>1 recipe reaches these probes. Fix: a self-neutralizing build-time patch guards both probes in SLIME's validate_args wrapper only when torch.cuda.is_available() is False (real GPU actors unchanged); the permanent fix belongs upstream in Megatron.

  • --sglang-enable-ep-moe is a dead flag on SGLang 0.5.12 (the arg was removed; SLIME parses --sglang-* leniently, so it is silently ignored, not rejected) and the recipe omits CUDA_DEVICE_MAX_CONNECTIONS=1, which Megatron asserts for TP/CP>1. Fix: drop the dead flag (SGLang defaults serve the MoE correctly, verified end-to-end — no replacement flag needed) and add CUDA_DEVICE_MAX_CONNECTIONS=1 to the recipe runtime-env.

Validation environment (common to the fixes here)

Everything above the cluster layer (image, recipe, model, versions, flags) is the test case as-is; only the cluster layer differs from the documented HyperPod/p5 target. Per-fix results are in each fix's comment.

  • AWS Service: Amazon EKS
  • Instance type: p5en.48xlarge (NVIDIA H200, 8 GPU/node)
  • Number of nodes: 2
Component This validation Test case default Same?
Container image built from this branch's slime.Dockerfile (with the fixes in this PR) base image, versions and install path unchanged fixes only
Ray 2.55.1 2.55.1 (pinned) yes
PyTorch / CUDA 2.11.0+cu130 / 13.0 NGC 26.02 (torch 2.11 / CUDA 13) yes
SGLang 0.5.12.post1 0.5.12.post1 (pinned) yes
SLIME v0.2.4 v0.2.4 (pinned) yes
Python 3.12.3 3.12 (NGC) yes
Model / data Qwen3-4B, dapo-math-17k, aime-2024 (torch_dist) same yes
GPU generation H200 (also observed on B300 per #1163) H100 cluster-layer diff
Orchestration Amazon EKS SageMaker HyperPod EKS cluster-layer diff

End-to-end result so far

With the general fixes above, the Qwen3-4B colocated GRPO recipe (recipe/run_grpo_qwen3_4b.sh, built-in reward) now runs end-to-end. On 2x p5en.48xlarge (16x H200), an image built from this branch's slime.Dockerfile completed 3 full GRPO loops (rollout generation → ref/actor log-probs → Megatron training step → weight sync back to SGLang), with no regressions (libcudart.so.12, numpy-2.x assert, uvicorn KeyError, hidden_size None all absent). Inter-node NCCL used EFA (NET/OFI Selected provider is efa, fabric is efa-direct (found 16 nics), repeated across all 16 ranks). This exercises the documented quick-start path (4B dense, colocated, in-process reward).

remote_rm HTTP reward service (reward_service/, kubernetes/reward-service.yaml): also validated. I built the CPU-only reward image from reward_service.Dockerfile, ran the service (math_verify backend) on a non-GPU node, and re-ran the 4B recipe with RM_TYPE=remote_rm / RM_URL=http://slime-reward.<ns>.svc.cluster.local:8000/score. SLIME picked up rm_type=remote_rm and the rollout reached the reward service over HTTP: 250+ POST /score requests, all 200 OK, zero non-200, and zero remote_rm retry/failure log lines on the SLIME side. The /score contract behaved as specified (correct answer -> 1.0, wrong -> 0.0). Environment delta: reward-service.yaml targets a HyperPod CPU instance group via nodeSelector: sagemaker.amazonaws.com/instance-group-name, which does not exist on plain EKS; I kept the manifest's GPU-exclusion nodeAffinity and dropped the instance-group nodeSelector so the pod lands on a non-GPU node, and added an imagePullSecrets for the cross-account ECR. These are cluster-layer adaptations; the reward service code and the recipe wiring are unchanged.

30B MoE disaggregated recipe (recipe/run_grpo_qwen3_30b_a3b.sh): also validated, on the same 2x p5en.48xlarge (16x H200), in a disaggregated topology (12 train GPUs at TP=2/EP=2/CP=2, 4 rollout GPUs). After the three 30B-only fixes above (mbridge, GPU-less driver validate guard, drop dead --sglang-enable-ep-moe + add CUDA_DEVICE_MAX_CONNECTIONS=1), the recipe reached a full GRPO loop: Final collected 96 samples from rollout to trainTimer train startTimer ref_log_probs end (27.4s)Timer actor_train end (55.4s)Timer train end (93.2s)Timer update_weights end (12.1s), with zero occurrences of Found no NVIDIA driver, not divisible by micro batch size, libcudart.so.12, or 400 Bad Request (the MoE online weight sync succeeded on SGLang's defaults). This is the disaggregated + MoE path, complementary to the 4B colocated run above.

Open questions for the maintainers

  1. Is the focused-commit approach on one [Don't merge] epic PR the shape you prefer, or would you rather each fix be its own separate PR?
  2. For the 30B MoE recipe, do you prefer env/flag deltas in the existing recipe over a separate subdir, given the feat: add Qwen3-8B pre-training sample (H200 vs B300, NeMo/Megatron) #1138 divergence discussion?
  3. For the cu13 torch_memory_saver .so, is a thin test-case-side fallback acceptable until the CUDA-major selection lands upstream in SLIME?

Checklist

  • I have read the contributing guidelines.
  • I am working against the latest main branch.
  • I have searched existing open and recently merged PRs to confirm this is not a duplicate.
  • The contribution is self-contained with documentation and scripts.
  • External dependencies are pinned to a specific version or tag (no latest).
  • A README is included or updated with prerequisites, instructions, and known issues.
  • New test cases follow the expected directory structure.

@littlemex littlemex changed the title fix(slime): deliver MODEL_ARGS to train.py (GRPO recipes launch with zero model args) [Don't merge] fix(slime): deliver MODEL_ARGS to train.py (GRPO recipes launch with zero model args) Jul 3, 2026
@littlemex littlemex changed the title [Don't merge] fix(slime): deliver MODEL_ARGS to train.py (GRPO recipes launch with zero model args) [Don't merge] Enable the SLIME GRPO test case to run end-to-end on B300 / H200 Jul 3, 2026
@littlemex

littlemex commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

First fix in this epic: MODEL_ARGS reaches train.py as zero elements

Detail for the first commit on this branch (issue #1163, item 4). This one blocks the very first step of training, so it goes first.

Running either GRPO recipe exactly as documented (bash recipe/run_grpo_qwen3_4b.sh) fails immediately with AssertionError: hf_validate_args failed: hidden_size in hf config 2560 is not equal to hidden_size None ....

A note on how this was scoped in #1163: it was originally listed there as Class C item 7 with a guess that it was plain-EKS-specific ("HyperPod's single bash -c doesn't hit this"). That guess was wrong. After reading the pinned Ray 2.55.1 source and reproducing the mechanism without SLIME, it is generation- and platform-independent: it happens on any KubeRay ray job submit path, including HyperPod. So it is really a general (Class A) bug.

Root cause — a shell-expansion boundary, not a modeling issue. The recipe builds the whole train.py invocation into one string and submits it as ray job submit ... -- bash -c "${TRAIN_CMD}", with the model config deferred as \${MODEL_ARGS[@]}:

MODEL_ARGS is a bash array defined by source scripts/models/<model>.sh (inside the image, from SLIME v0.2.4, pinned at slime.Dockerfile ARG SLIME_VERSION=v0.2.4). With Ray pinned to ray[default]==2.55.1 (3.test_cases/pytorch/slime/requirements.txt), ray job submit re-joins everything after -- with subprocess.list2cmdline and runs it through an outer shell via Popen(shell=True)/bin/sh -c (Ray 2.55.1: python/ray/dashboard/modules/job/cli.py, job_supervisor.py). That outer shell expands ${MODEL_ARGS[@]} before the inner bash -c sources the model script; MODEL_ARGS is undefined in the outer shell, so it expands to zero elements. train.py receives none of the model-shape flags and aborts in hf_validate_args (hidden_size None).

A bash array cannot survive being embedded in a string that a second shell re-parses, so the fix is to stop crossing that boundary rather than add another layer of escaping. Escaping cannot work here because list2cmdline always double-quotes the payload, so the outer shell always expands it.

The fix — follow SLIME's own launch pattern. SLIME's upstream launchers expand ${MODEL_ARGS[@]} in the same shell that sourced it and pass everything as real argv tokens after --, never as one bash -c string:

This commit adopts the same shape. A new recipe/launcher/grpo_launch.sh does cd /opt/slime, sources the model script, then exec python3 train.py "${MODEL_ARGS[@]}" "$@", and it fails fast if MODEL_ARGS is empty. Both recipes assemble train.py flags as a bash array and submit with ray job submit ... --working-dir <launcher-dir> -- bash grpo_launch.sh "${TRAIN_ARGS[@]}". The tokens after -- are just bash grpo_launch.sh <scalar flags>, so no bash array crosses the ray job submit boundary and the whole class of outer-shell expansion bug is gone. --working-dir uploads the small launcher; SLIME itself is already in the image at /opt/slime, and MODEL_SCRIPT is forwarded via the runtime env so the launcher sources the right model definition.

Only the launch mechanism changes here. train.py flags are byte-for-byte identical to main (99 tokens for 4B, 103 for 30B, including --expert-tensor-parallel-size, --rollout-num-gpus, --sglang-enable-ep-moe, and --sglang-log-level). The --sglang-log-level value itself is a separate follow-up in the checklist.

Reproduce it yourself. Set NAMESPACE first; nothing else is environment-specific.

export NAMESPACE=<your-namespace>
HEAD=$(kubectl -n "$NAMESPACE" get pod -l ray.io/node-type=head -o jsonpath='{.items[0].metadata.name}')

# 1. The array IS defined in a single shell (control) -> prints count=25
kubectl -n "$NAMESPACE" exec "$HEAD" -- bash -lc \
  'source /opt/slime/scripts/models/qwen3-4B.sh && echo count=${#MODEL_ARGS[@]}'

# 2. The same command through "ray job submit -- bash -c" loses the array. Submit it,
#    then read the job log: count is 0.
JOB=$(kubectl -n "$NAMESPACE" exec "$HEAD" -- bash -lc \
  'ray job submit --address=http://127.0.0.1:8265 -- \
     bash -c "source /opt/slime/scripts/models/qwen3-4B.sh && echo count=\${#MODEL_ARGS[@]}"' \
  2>&1 | grep -oE 'raysubmit_[A-Za-z0-9]+' | head -1)
kubectl -n "$NAMESPACE" exec "$HEAD" -- \
  ray job logs "$JOB" --address http://127.0.0.1:8265 2>&1 | grep count=   # -> count=0

# 3. With the patched recipe, the launcher logs "MODEL_ARGS count=25" and Megatron
#    prints hidden_size 2560 (no "hidden_size None").

# Static check: no bash array in the submitted entrypoint
bash -n recipe/run_grpo_qwen3_4b.sh && bash -n recipe/launcher/grpo_launch.sh

Result (H200). The same reproduction, summarized:

Launch path how ${MODEL_ARGS[@]} expands args reaching the process
single bash -c "..." one shell 25 (correct)
ray job submit -- bash -c "..." (current recipe) outer /bin/sh expands first 0 (hidden_size None)
ray job submit -- bash grpo_launch.sh ... (this fix) inside the launcher 25 (correct)

End-to-end with the real train.py, Megatron receives the config and passes hf_validate_args, so training starts:

[grpo_launch] MODEL_SCRIPT=qwen3-4B.sh MODEL_ARGS count=25
[grpo_launch] launching: python3 train.py <25 model args> 100 recipe args
  ffn_hidden_size ................................. 9728
  hidden_size ..................................... 2560      # was: None

littlemex added 2 commits July 3, 2026 04:46
… starts

The GRPO recipes passed --sglang-log-level WARN (uppercase). SLIME forwards the
value verbatim into SGLang's ServerArgs, and SGLang hands it to uvicorn, whose
LOG_LEVELS dict is keyed by lowercase names only (no 'warn' key). uvicorn raises
KeyError while building its Config, before the socket binds, so the rollout HTTP
server never comes up: the engine core idles, the port never listens, and the
RolloutManager waits on an unreachable /health_generate forever (GPU idle).

Use lowercase 'info' in both run_grpo_qwen3_4b.sh and run_grpo_qwen3_30b_a3b.sh.
The proper normalization belongs upstream in SGLang (it accepts WARN for its own
stdlib logger but not for uvicorn); this recipe change is the immediate unblock.
… of bash -c

The GRPO recipes built the whole train.py invocation into a single string and
submitted it as `ray job submit ... -- bash -c "${TRAIN_CMD}"`, with the
model config deferred as `\${MODEL_ARGS[@]}`. ray job submit re-joins the
tokens after `--` with subprocess.list2cmdline and runs them through an outer
`/bin/sh -c` (Popen(shell=True)), so that outer shell expands ${MODEL_ARGS[@]}
to zero elements before the inner bash sources the model script. train.py then
receives no model args and aborts at hf_validate_args ("hidden_size ... None").

Move the launch into recipe/launcher/grpo_launch.sh, which sources the model
script and expands "${MODEL_ARGS[@]}" in the same shell, and submit it as
`-- bash grpo_launch.sh <flags>` with --working-dir. No bash array ever crosses
the ray-submit boundary, matching how SLIME's own scripts/run-*.sh launch. The
recipes now assemble train.py flags as a bash array (argv tokens); the README
file tree lists the new launcher.

Applies to both run_grpo_qwen3_4b.sh and run_grpo_qwen3_30b_a3b.sh.
@littlemex
littlemex force-pushed the epic/enable-slime-grpo-on-b300-h200 branch 2 times, most recently from fb58e3c to 5a3777f Compare July 3, 2026 06:36
Verified that uvicorn accepts lowercase 'warning' (its LOG_LEVELS has a
'warning' key but no 'warn' key). The original recipe intent was WARN-level
verbosity, so use lowercase 'warning' rather than 'info' to keep that intent
while avoiding the uppercase KeyError that hangs the rollout HTTP server.
littlemex and others added 2 commits July 3, 2026 17:38
fix(slime): use lowercase sglang log level so the rollout HTTP server starts
…in-place

On CUDA 13 the upstream SLIME actor_group.py picks the torch_memory_saver
preload .so by filename existence (cu12, then unsuffixed), not by CUDA runtime.
Both are cu12-linked, so LD_PRELOAD makes the train worker die with
'libcudart.so.12: cannot open shared object file'; the correct cu13 build ships
in the wheel but is never enumerated.

Rather than fork SLIME or hard-code a fork URL, install upstream SLIME as-is and
run a self-neutralizing patch step that rewrites the .so selection to delegate
to torch_memory_saver's own CUDA-aware resolver (get_binary_path_from_package),
with a loadability-based fallback for older torch_memory_saver. The patch only
touches the file when the unfixed pattern is present, so once the equivalent fix
lands upstream in THUDM/slime it becomes a no-op automatically.

Verified on H200 (CUDA 13): LD_PRELOAD resolves to the cu13 build and the train
worker starts (no libcudart.so.12 error), reaching Megatron init.
littlemex and others added 3 commits July 4, 2026 06:04
fix(slime): heal the CUDA-13 torch_memory_saver LD_PRELOAD selection without forking SLIME
…orker

Megatron-LM asserts numpy 1.x at init (per NVIDIA/Megatron-LM#1563), but
sglang[all] -- installed just before requirements.txt in slime.Dockerfile --
pulls numpy 2.x transitively, so MegatronTrainRayActor dies during init with
'AssertionError: Megatron does not support numpy 2.x'.

Pin numpy<2 in requirements.txt. Because the requirements install runs after
sglang[all] and the later slime/sgl-router installs use --no-deps, this
downgrades numpy back to 1.26.4 and nothing reintroduces 2.x. Verified on H200
(CUDA 13): numpy 1.26.4, torch/megatron import cleanly, Megatron init passes and
the train worker proceeds into the rollout/train cycle.
Fixes an inaccurate comment (the later ring_flash_attn install is not --no-deps)
and records why numpy 1.x survives to runtime: the only post-pin pip steps are
slime/sgl-router (--no-deps) and ring_flash_attn 0.1.8 (declares no deps), so
none reintroduce numpy 2.x. Notes that upstream SLIME's own Dockerfile pins
numpy<2 the same way, and adds a TODO tying the pin's removal to a future
MEGATRON_LM_VERSION that drops the numpy 1.x assert. No functional change.
littlemex and others added 6 commits July 4, 2026 06:24
fix(slime): pin numpy < 2 so Megatron init does not abort the train worker
Bring up recipe/run_grpo_qwen3_30b_a3b.sh (Qwen3-30B-A3B, disaggregated) to a
full GRPO training step. The 4B colocated path already works; the 30B MoE recipe
hit several MoE/parallelism-specific walls that 4B does not:

- Checkpoint conversion needs mbridge (convert_hf_to_torch_dist.py imports it),
  not pulled by the --no-deps slime install. Install it in the Dockerfile with
  --no-deps so it cannot drag numpy 2.x back in.
- SGLang 0.5.12 removed --enable-ep-moe; use --sglang-moe-runner-backend triton
  + --sglang-expert-parallel-size instead so the rollout engine starts.
- Megatron validate_args eagerly probes the CUDA device (get_device_capability
  for moe_grouped_gemm, get_device_arch_version for the TP/CP note) on the Ray
  driver, which is intentionally GPU-less (head num-gpus:0), crashing with
  'Found no NVIDIA driver'. Guard both probes in SLIME's validate_args wrapper
  only when torch.cuda.is_available() is False (the driver); GPU actors probe
  the real device unchanged. get_device_arch_version returns 10 on the driver so
  it defers the CUDA_DEVICE_MAX_CONNECTIONS decision to the real actors rather
  than faking a pre-Blackwell arch (which would wrongly force it on B300).
- TP/CP>1 requires CUDA_DEVICE_MAX_CONNECTIONS=1; add it to the recipe runtime-env.
- Cap --sglang-cuda-graph-max-bs 8 so large-HBM capture is not pathologically slow.

The driver-probe guard is added to the existing self-neutralizing patch
mechanism (patches/apply_slime_patches.py): it edits the upstream checkout only
when the un-guarded probe is present, is idempotent, byte-compiles, and no-ops
once Megatron guards the probes upstream (issue/PR to be filed there).

Verified on H200 (2x p5en.48xlarge, CUDA 13): the 30B MoE recipe reaches a full
GRPO loop (rollout -> ref/actor log-probs -> Timer train end -> weight sync),
with no wall regressions and no MoE weight-sync 400.
…lizing

The wall-9 guard was keyed only on SLIME's validate_args wrapper shape, so it
would keep applying (harmlessly, since it is is_available()-gated) even after
Megatron guards the probe upstream. Make it detect the actual defect: inspect
the installed Megatron's validate_args and apply the SLIME-side guard only while
an eager get_device_capability() probe remains unguarded (no torch.cuda.is_available()
on or just before its line). Once Megatron guards or removes the probe, the
patch reports already-fixed-upstream and leaves SLIME untouched -- matching the
self-neutralizing behavior of the tms-preload patch. Verified all states on H200:
applied / already-applied / already-fixed-upstream (guarded same-line, guarded
enclosing-if, and probe-removed).
An audit + end-to-end retest showed two of the SGLang flags added while bringing
up the 30B MoE recipe are not needed, so remove them and keep the recipe minimal:

- --sglang-moe-runner-backend triton: redundant. On SGLang 0.5.12 the default
  moe_runner_backend=auto resolves to the same triton runner for an unquantized
  bf16 MoE on H200 (sm_90); forcing triton changes nothing.
- --sglang-expert-parallel-size (sglang ep_size): not required. The rollout
  engine's expert parallelism is independent of Megatron's training EP, and
  ep_size=1 (the SGLang default) is a valid serving mode for Qwen3-30B-A3B.

Also correct the comment about --sglang-enable-ep-moe: SGLang 0.5.12 removed the
flag, but SLIME v0.2.4 parses --sglang-* leniently (parse_known_args /
ignore_unknown_args), so the dead flag is silently ignored, not rejected. It is
dropped because it configures nothing, not because it errors.

Verified on H200: the 30B MoE disaggregated recipe reaches a full GRPO loop
(Timer train end) with none of these flags set.
… on the GPU-less driver

Return _ARCH_UNKNOWN_ON_GPULESS_DRIVER = 9999 instead of 10 from the
GPU-less-driver guard. 9999 is deliberately not any real GPU generation
(Ampere=8, Hopper=9, Blackwell=10), so the driver never mislabels the
hardware; being >= 10 it still skips the arch<10 CUDA_DEVICE_MAX_CONNECTIONS
branch and defers that decision to the real GPU actors. Matches the image
already verified end-to-end on H200 (get_device_arch_version = 9999).
fix(slime): enable the 30B MoE disaggregated recipe to run end-to-end
@littlemex littlemex changed the title [Don't merge] Enable the SLIME GRPO test case to run end-to-end on B300 / H200 Enable the SLIME GRPO test case to run end-to-end on B300 / H200 Jul 7, 2026
@KeitaW
KeitaW requested a review from allela-roy July 8, 2026 21:47

@allela-roy allela-roy 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.

@littlemex , thanks for the PR. These are clean, well-engineered fixes and verified the end-end execution on my cluster. LGTM. Approved.

@allela-roy
allela-roy merged commit d8243f1 into awslabs:main Jul 10, 2026
@littlemex

Copy link
Copy Markdown
Contributor Author

@allela-roy Thank you so much for taking the time to thoroughly verify the changes end-to-end on your cluster — I really appreciate it!

@littlemex
littlemex deleted the epic/enable-slime-grpo-on-b300-h200 branch July 12, 2026 10:42
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