Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
118 commits
Select commit Hold shift + click to select a range
3eb2c48
Add nano-v3 config
yfw Feb 18, 2026
1503eb7
Cherry pick gym-related nano-v3 changes
yfw Dec 10, 2025
0b6757b
Update config
yfw Feb 18, 2026
b86a31f
Merge remote-tracking branch 'origin/main' into yifu/nano-v3-config
yfw Feb 19, 2026
4d35ce3
Remove unused
yfw Feb 20, 2026
e5f2e7b
Merge remote-tracking branch 'origin/main' into yifu/nano-v3-config
yfw Feb 20, 2026
8f8857b
lint
yfw Feb 20, 2026
499108c
Super model running with mcore + mbridge bumps
yfw Feb 21, 2026
c722c91
Support for ray spinup within gym
yfw Feb 21, 2026
5bbf159
add genrm rlhf to gym
yfw Feb 21, 2026
a159d65
fix min&max metric
yfw Feb 21, 2026
750bd2a
Add grpo_superv3.yaml
yfw Feb 21, 2026
6bbd083
async nemo gym (#1999)
yfw Feb 21, 2026
3f30b80
skip log probs + offload before refit
yfw Feb 21, 2026
241ddde
Use prompt length to find groups for advantage calculation
yfw Feb 21, 2026
0bb29f4
Allow replay buffer checkpointing and reloading capability
yfw Feb 21, 2026
657a1b4
custom reasoning parser
yfw Feb 21, 2026
118de81
Skip calculating prev_logprob when force_onpolicy_ratio is true
yfw Feb 21, 2026
b556e9c
super ckpt conversion
yfw Feb 21, 2026
28ecbb8
skip loading ref model when kl>0
yfw Feb 21, 2026
16b4890
only calculate loss on assistant turns generated by model
yfw Feb 21, 2026
145c744
Add seq level logprob error metrics
yfw Feb 21, 2026
5c6d5e4
Fix for ray state API usage (list_nodes with limit). Enable debug log…
yfw Feb 22, 2026
1693cc1
effort work
yfw Feb 22, 2026
48fe510
fix genrm reasoning off
yfw Feb 22, 2026
b856899
don't count fully masked sequences
yfw Feb 22, 2026
57bf919
add overlong filtering for gym rollout + configurable advantage clipping
yfw Feb 22, 2026
3186fb4
increase last_target_weight_already_generated only when whole batch i…
yfw Feb 22, 2026
3fa3e32
merge swe openhands + fix misc env issues + fix nemo skills sandbox
yfw Feb 22, 2026
ae1ab08
Respect external VLLM_CACHE_ROOT and add cache optimization guide
yfw Feb 22, 2026
2da2585
penalize invalid toolcall + log TIS clipped fraction
yfw Feb 22, 2026
d667613
POC ray put
yfw Feb 22, 2026
6439707
Update grpo_superv3.yaml with latest `main` changes
yfw Feb 23, 2026
d6b27b5
Fix penalize invalid toolcall with prorl changes
yfw Feb 23, 2026
8106050
MTP changes
yfw Feb 23, 2026
eb401ba
overlap NeMo Gym init with vLLM init
yfw Feb 23, 2026
6efed5b
fix missing logger
yfw Feb 23, 2026
46e5ec5
Pass explicit PG to gym
yfw Feb 23, 2026
b941004
penalize toolcall in reasoning when it should be outside + invalid th…
yfw Feb 23, 2026
855550a
fix: add support to configure RL+Gym+vLLM port ranges to avoid port c…
yfw Feb 23, 2026
d9a212c
feat: add [GPU_DIAG] memory diagnostics logging during worker init
yfw Feb 23, 2026
e95ea74
Fix setuptools error
yfw Dec 6, 2025
5f87e2b
Update ray.sub
yfw Feb 24, 2026
234df47
Update gym
yfw Feb 24, 2026
ec81c6b
Update Megatron setup.py
yfw Feb 24, 2026
fdf34df
Remove vllm version check
yfw Feb 24, 2026
471bf18
Update uv.lock
yfw Feb 24, 2026
ab77301
Bump mbridge for mtp fix
yfw Feb 24, 2026
f4163a6
Add stage 1 recipe
yfw Feb 24, 2026
13559c7
bump mcore for mtp detach fix
yfw Feb 24, 2026
76ddd97
effort level updates
haifengqian Feb 27, 2026
3f391da
Fix genrm for async gym
yfw Feb 27, 2026
5417b36
Bump Megatron-Bridge to copy reasoning parser in conversion
yfw Mar 2, 2026
55880f1
Bump mbridge to fix fp32 expert bias
yfw Mar 3, 2026
05eb916
feat: caching gym venvs and apptainer for super branch (#2050)
terrykong Mar 3, 2026
01d0f5d
build: Bump dependencies to address CVEs (#2082)
chtruong814 Mar 7, 2026
92208dc
SWE stage changes + update recipes / docs (#2083)
yfw Mar 7, 2026
df4d391
Update doc
yfw Mar 7, 2026
279f2e4
Remove auto mount
yfw Mar 7, 2026
211dc1f
Point gym to public super-v3
yfw Mar 7, 2026
f7fe11c
build: Ensure xgrammar==0.1.32 in vllm and gym venvs (#2086)
chtruong814 Mar 8, 2026
7b30253
Use super configs for prefetch envs
yfw Mar 9, 2026
ddf2d9b
Handle partial download
yfw Mar 9, 2026
c6702b2
Address Terry's feedback
yfw Mar 9, 2026
0a7b1d3
Update swe2
yfw Mar 9, 2026
a90de92
100 samples for validation
yfw Mar 10, 2026
c21c87e
Fix penalize_invalid_tool_call and penalize_malformed_thinking
yfw Mar 11, 2026
3ab7a2c
Rebuild swe prefetch container
yfw Mar 11, 2026
7933ea6
Update dataset name
yfw Mar 11, 2026
61cb0f3
Update launch script
yfw Mar 11, 2026
298fea1
Fix: apptainer download script (#2101)
sdevare-nv Mar 12, 2026
347ac6a
Remove unused configs
yfw Mar 12, 2026
9c77bef
docs(super): Add note about vllm bug prior to 0.17.0 (#2127)
yfw Mar 19, 2026
b46b4cc
sft: allow pluggable loss_fn / dataloader / checkpoint-save hooks
xrsrke May 27, 2026
9607c6e
dtensor_policy_worker_v2: support multi-LoRA per-row routing + merge …
xrsrke May 27, 2026
5df7138
worker+train: multi-LoRA per-row routing via adapter_ids tensor + CP …
xrsrke May 27, 2026
0925aa0
sft: add 1-step debug instrumentation for token_mask=0 diagnosis on S…
xrsrke May 28, 2026
a79ce1e
bit-eq diag: NLLLoss + worker + train fingerprints (symmetric with no…
May 29, 2026
d769538
worker: thread dump_phase + step to aggregate_lora_fingerprints
May 29, 2026
7ee631a
fix(automodel/train): skip non-numeric metrics in per-mb division
xrsrke May 29, 2026
d64656d
debug(multi-lora): NOUSNET_DUMP_EVERYTHING hooks in dtensor worker v2
xrsrke Jun 11, 2026
9d927fc
diag: add exact-init and per-adapter clip probes
xrsrke Jul 17, 2026
1da6d85
diag: log worker source hash for exact-init probes
xrsrke Jul 17, 2026
8625745
fix: preserve masked SFT rows in bit-equivalence probes
xrsrke Jul 17, 2026
fff22a9
fix: match stock norm semantics for per-adapter clipping
xrsrke Jul 17, 2026
1e5189b
fix: per-adapter clip in-place scaling with correct norm
xrsrke Jul 17, 2026
2e06046
diag: emit compact single-adapter loss traces
xrsrke Jul 17, 2026
4c3c1b8
diag: support lightweight pairwise loss tracing
xrsrke Jul 17, 2026
ca95312
fix: compute per-adapter global valid-token counts for DP>1
xrsrke Jul 17, 2026
c323e67
fix: all-reduce dense adapter token counts
xrsrke Jul 17, 2026
7400de2
fix: stripe multi-adapter rows across DP ranks
xrsrke Jul 17, 2026
2456200
diag: support trace-only single-adapter loss capture
xrsrke Jul 17, 2026
e551316
multi-lora: vendor nousnet multi-adapter LoRA natively into nemo_rl.m…
xrsrke Jul 23, 2026
9ea46b4
multi-lora: add 10-step smoke config (runtime-captured campaign confi…
xrsrke Jul 23, 2026
bfac375
multi-lora: native 8-GPU launcher (overlays this branch only; asserts…
xrsrke Jul 23, 2026
4e19b0e
multi-lora launcher: fix CPUS_PER_WORKER=64 (ray.sub default 112 > al…
xrsrke Jul 23, 2026
e485954
multi-lora smoke config: fill hard-required keys (checkpointing.metri…
xrsrke Jul 23, 2026
0ff12d4
multi-lora smoke config: full-complete against stock sft.yaml (deep-m…
xrsrke Jul 23, 2026
b9c6161
run_sft_multi_lora: register omegaconf resolvers (mul/max) before loa…
xrsrke Jul 23, 2026
ff31fd7
launcher: vendor parallelizer_utils/parallelizer/checkpointing into p…
xrsrke Jul 23, 2026
c587f1e
native100 battery: 10 configs (noclip+clip1 x multi+4 singles) from c…
xrsrke Jul 23, 2026
c206905
native100: pairwise verdicts both modes — 8/8 step-1 bit-identical, s…
xrsrke Jul 23, 2026
d70da1b
charts: native100 per-adapter loss curves + match-vs-campaign |delta|…
xrsrke Jul 23, 2026
127dbd5
native100 FIX: drop chat_template leaked from stock sft.yaml — campai…
xrsrke Jul 23, 2026
69e7128
battery v2: rename jobs n100v2-* (results dirs keyed by job name)
xrsrke Jul 23, 2026
4d51589
native100 v2: require fresh checkpoint paths before rerun
xrsrke Jul 23, 2026
b9c87f1
native100 v3: restore campaign COT preprocessing explicitly
xrsrke Jul 23, 2026
0c9ed59
native100 v3: persist exact-preprocessing final verdict
xrsrke Jul 24, 2026
5d48b1f
launcher: fully repo-contained — vendor cluster ray.sub (pmi2/dynamic…
xrsrke Jul 24, 2026
46211eb
standalone: remove residual nousnet references — nemo_env resolves co…
xrsrke Jul 24, 2026
f3cce63
cleanup: remove dead debug instrumentation and untrack result artifacts
xrsrke Jul 24, 2026
8f59a0f
config: single base.yaml + tiny overlays; retire v1/v2/v3 config forks
xrsrke Jul 24, 2026
b8d4032
audit: exclude self from forbidden-token scan (was flagging its own l…
xrsrke Jul 24, 2026
7fdc01e
launcher: ship base.yaml next to the EXP_DIR config copy
xrsrke Jul 24, 2026
226517f
cleanup(multi-lora): remove unused native config surface
xrsrke Jul 24, 2026
c0841cb
multi-lora: fail closed on adapter-axis FSDP sharding + parity report
xrsrke Jul 28, 2026
9db1502
multi-lora: add final evidence reproduction bundle
xrsrke Jul 28, 2026
000d2ac
multi-lora: make reproduction reruns collision-safe
xrsrke Jul 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,29 @@ ckpts/
coverage.json
.coverage*
test_assets/
.nrl_remote_map.json
.nrl_remote_state.json
# Test biproducts
tests/functional/*/

# Gym
/3rdparty/Gym-workspace/Gym/cache/uv/
/3rdparty/Gym-workspace/Gym/res*/*/.venv/
/3rdparty/Gym-workspace/Gym/res*/*/.venv/
/3rdparty/Gym-workspace/Gym/.venv/

# Cache
uv_cache/
hf_home/
hf_datasets_cache/
*logs/
datasets/
/datasets/
wandb/
checkpoints/
results/
code_snapshots/
code_snapshots*/
.cache/

# Runtime env
*runtime_env.yaml
!default_runtime_env.yaml
11 changes: 5 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,20 @@ ckpts/
# Test
coverage.json
.coverage*
unit_results.json
unit_results/
test_assets/
tests/unit/unit_results.json
tests/unit/unit_results/
.nrl_remote_map.json
.nrl_remote_state.json
# Test biproducts
tests/functional/*/

# Cache
uv_cache/
hf_home/
hf_datasets_cache/
*logs/
/datasets/
docker/*
!docker/Dockerfile
!docker/Dockerfile.ngc_pytorch
!docker/README.md
wandb/
checkpoints/
results/
Expand All @@ -46,3 +44,4 @@ code_snapshots*/
# Runtime env
*runtime_env.yaml
!default_runtime_env.yaml
charts_native100/
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[submodule "3rdparty/Megatron-LM"]
path = 3rdparty/Megatron-LM-workspace/Megatron-LM
url = https://github.com/yaoyu-33/Megatron-LM.git
branch = yifu/remove_do_not_average_loss
branch = yifu/superv3
shallow = true
[submodule "3rdparty/Megatron-Bridge"]
path = 3rdparty/Megatron-Bridge-workspace/Megatron-Bridge
url = https://github.com/NVIDIA-NeMo/Megatron-Bridge.git
branch = main
branch = yifu/superv3
shallow = true
[submodule "3rdparty/Automodel-workspace/Automodel"]
path = 3rdparty/Automodel-workspace/Automodel
Expand All @@ -16,5 +16,5 @@
[submodule "3rdparty/Gym-workspace/Gym"]
path = 3rdparty/Gym-workspace/Gym
url = https://github.com/NVIDIA-NeMo/Gym.git
branch = main
branch = super-v3
shallow = true
2 changes: 1 addition & 1 deletion 3rdparty/Gym-workspace/Gym
Submodule Gym updated 397 files
2 changes: 1 addition & 1 deletion 3rdparty/Megatron-Bridge-workspace/Megatron-Bridge
Submodule Megatron-Bridge updated 386 files
7 changes: 4 additions & 3 deletions 3rdparty/Megatron-Bridge-workspace/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

CACHED_DEPENDENCIES = [
"transformers<5.0.0",
"datasets",
"datasets>=2.20.0",
"accelerate",
"omegaconf>=2.3.0",
"tensorboard>=2.19.0",
Expand All @@ -41,13 +41,14 @@
"hydra-core>1.3,<=1.3.2",
"megatron-core[dev,mlm]>=0.15.0a0,<0.17.0",
"qwen-vl-utils",
"transformer-engine[pytorch]>=2.10.0a0,<2.12.0",
"transformer-engine[pytorch,core_cu13]>=2.10.0a0,<2.13.0",
"mamba-ssm",
"nvidia-resiliency-ext",
"nvidia-resiliency-ext~=0.4.1",
"causal-conv1d",
"flash-linear-attention",
"timm",
"open-clip-torch>=3.2.0",
"mlflow>=3.5.0",
]

# If the bridge source exists, compare cached dependencies with the submodule's pyproject
Expand Down
2 changes: 1 addition & 1 deletion 3rdparty/Megatron-LM-workspace/Megatron-LM
Submodule Megatron-LM updated 425 files
4 changes: 2 additions & 2 deletions 3rdparty/Megatron-LM-workspace/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
# VCS dependencies use full "pkg @ git+URL@rev" format matching pyproject.toml [tool.uv.sources]
CACHED_DEPENDENCIES = [
# Default dependencies from pyproject.toml
"torch",
"torch>=2.6.0",
"numpy",
"packaging>=24.2",
# Dev dependencies from pyproject.toml
Expand All @@ -58,7 +58,7 @@
"opentelemetry-api~=1.33.1",
"mamba-ssm~=2.2",
"causal-conv1d~=1.5",
"flash-linear-attention~=0.3.2",
"flash-linear-attention~=0.4.0",
"nv-grouped-gemm~=1.1",
"megatron-energon[av_decode]~=6.0",
"av",
Expand Down
122 changes: 81 additions & 41 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
# Local NeMo RL source override:
# docker buildx build --build-context nemo-rl=. -f docker/Dockerfile --tag <registry>/nemo-rl:latest --push .
#
# Custom setup:
# docker buildx build --build-context custom-setup=my-setup-dir/ --build-arg CUSTOM_SETUP_FNAME=my_script.sh -f docker/Dockerfile ...
#
# To skip custom setup:
# docker buildx build --build-arg CUSTOM_SETUP_FNAME= -f docker/Dockerfile ...
#
# Optional build args to skip vLLM or SGLang dependencies:
# --build-arg SKIP_VLLM_BUILD=1 # Skip vLLM dependencies
# --build-arg SKIP_SGLANG_BUILD=1 # Skip SGLang dependencies
Expand All @@ -21,6 +27,11 @@ FROM scratch AS nemo-rl
ARG NRL_GIT_REF=main
ADD --keep-git-dir=true https://github.com/NVIDIA-NeMo/RL.git#${NRL_GIT_REF} /

# Default custom-setup stage: installs apptainer.
# Override with: --build-context custom-setup=<your-dir>
FROM scratch AS custom-setup
COPY docker/install_apptainer.sh /

FROM ${BASE_IMAGE} AS base
# An environment variable to indicate that we are in a container.
ENV NRL_CONTAINER=1
Expand Down Expand Up @@ -83,7 +94,10 @@ ENV RAY_USAGE_STATS_ENABLED=0
# need to be compiled, so NeMo RL has an implementation in nemo_rl/utils/venv.py that does it once per node as opposed to once per task.
ENV RAY_ENABLE_UV_RUN_RUNTIME_ENV=0
ENV NEMO_RL_VENV_DIR=/opt/ray_venvs

ENV NEMO_GYM_VENV_DIR=/opt/gym_venvs
# Config paths (relative to repo root) whose NeMo Gym venvs should be prefetched.
# Override to prefetch venvs for different configs, or set to empty to skip.
ARG NEMO_GYM_PREFETCH_CONFIGS="examples/configs/super/stage1_rlvr.yaml examples/configs/super/stage3_rlhf.yaml"

FROM base AS hermetic

Expand Down Expand Up @@ -112,23 +126,22 @@ ENV UV_LINK_MODE=copy
# Ensure DeepEP is built for H100 and B200 (also mcore inference unified memory API now invokes a torch API that requires these to be set)
ENV TORCH_CUDA_ARCH_LIST="9.0 10.0"

# First copy only the dependency files
COPY --from=nemo-rl pyproject.toml uv.lock ./
# Copy in the top level __init__.py/package_info.py since build-custom-vllm.sh needs the nemo_rl package to exist.
COPY --from=nemo-rl nemo_rl/__init__.py nemo_rl/package_info.py ./nemo_rl/
COPY --from=nemo-rl tools/build-custom-vllm.sh ./tools/build-custom-vllm.sh
COPY --from=nemo-rl tools/build-custom-flashinfer.sh ./tools/build-custom-flashinfer.sh
COPY --from=nemo-rl --link research/ ./research/
COPY --from=nemo-rl --link 3rdparty/ ./3rdparty/
# Copy in source from build context (defaults to cloned repo, can be overridden)
COPY --from=nemo-rl . /opt/nemo-rl
# Unshallow the repo to get the full history (in the case it was from the scratch layer).
# Potentially not necessary if the repo is passed in as a complete repository (w/ full git history),
# so do a quick check before trying to unshallow.
RUN git rev-parse --is-shallow-repository | grep -q true && git fetch --unshallow || true

RUN --mount=type=ssh <<"EOF" bash -exu
uv venv --seed
# The custom build scripts will alter the pyproject.toml and uv.lock
if [[ -n "${BUILD_CUSTOM_VLLM:-}" ]]; then
bash tools/build-custom-vllm.sh ${BUILD_CUSTOM_VLLM_URL} ${BUILD_CUSTOM_VLLM_REF} ${BUILD_CUSTOM_VLLM_PRECOMPILED_WHEEL_LOCATION}
UV_LINK_MODE=hardlink bash tools/build-custom-vllm.sh ${BUILD_CUSTOM_VLLM_URL:-} ${BUILD_CUSTOM_VLLM_REF:-} ${BUILD_CUSTOM_VLLM_PRECOMPILED_WHEEL_LOCATION:-}
source 3rdparty/vllm/nemo-rl.env
fi
if [[ -n "${BUILD_CUSTOM_FLASHINFER:-}" ]]; then
bash tools/build-custom-flashinfer.sh ${BUILD_CUSTOM_FLASHINFER_URL} ${BUILD_CUSTOM_FLASHINFER_REF}
bash tools/build-custom-flashinfer.sh ${BUILD_CUSTOM_FLASHINFER_URL:-} ${BUILD_CUSTOM_FLASHINFER_REF:-}
fi
# uv sync has a more reliable resolver than simple uv pip install which can fail

Expand All @@ -137,25 +150,76 @@ fi
# Do everything in one layer to prevent large layers.

# The venv is symlinked to avoid bloating the layer size
uv sync --link-mode symlink --locked --no-install-project
UV_LINK_MODE=hardlink uv sync --locked --no-install-project
if [[ -z "${SKIP_VLLM_BUILD:-}" ]]; then
uv sync --link-mode symlink --locked --extra vllm --no-install-project
UV_LINK_MODE=hardlink uv sync --locked --extra vllm --no-install-project
fi
if [[ -z "${SKIP_SGLANG_BUILD:-}" ]]; then
uv sync --link-mode symlink --locked --extra sglang --no-install-project
UV_LINK_MODE=hardlink uv sync --locked --extra sglang --no-install-project
fi
uv sync --link-mode symlink --locked --extra mcore --no-install-project
uv sync --link-mode symlink --locked --extra automodel --no-install-project
uv sync --link-mode symlink --locked --all-groups --no-install-project
UV_LINK_MODE=hardlink uv sync --locked --extra mcore --no-install-project
UV_LINK_MODE=hardlink uv sync --locked --extra automodel --no-install-project
UV_LINK_MODE=hardlink uv sync --locked --all-groups --no-install-project

# Remove the aiohttp in this uv cache dir to fully address CVE GHSA-mqqc-3gqh-h2x8
# The ray install will include the older aiohttp version in its cache
# Symlink the venv's newer aiohttp package to the ray runtime env directory
find /root/.cache/uv -type d -path "*ray/_private/runtime_env/agent/thirdparty_files/aiohttp*" -exec rm -rf {} +
find /opt/nemo_rl_venv/ -type d -path "*ray/_private/runtime_env/agent/thirdparty_files/aiohttp*" -exec rm -rf {} +
ln -s /opt/nemo_rl_venv/lib/python3.12/site-packages/aiohttp \
/opt/nemo_rl_venv/lib/python3.12/site-packages/ray/_private/runtime_env/agent/thirdparty_files/aiohttp

ln -s /opt/nemo_rl_venv/lib/python3.12/site-packages/aiohttp-*.dist-info \
/opt/nemo_rl_venv/lib/python3.12/site-packages/ray/_private/runtime_env/agent/thirdparty_files/

# Prefetch NeMo Gym internal venvs (for gym servers like code_gen, math, etc.)
if [[ -n "${NEMO_GYM_PREFETCH_CONFIGS:-}" ]]; then
# Infer the index from RL's pyproject.toml. This ensures all venv creation that needs torch will use the RL prescribed version for consistency since RL dictates the container CUDA version.
UV_TORCH_BACKEND=$(uv run python -c "import tomllib,pathlib; indexes=tomllib.loads(pathlib.Path('pyproject.toml').read_text())['tool']['uv']['index']; print(next(i['name'].removeprefix('pytorch-') for i in indexes if i['name'].startswith('pytorch-')))") \
UV_LINK_MODE=hardlink uv run python examples/nemo_gym/prefetch_venvs.py $NEMO_GYM_PREFETCH_CONFIGS
fi

# Remove /tmp/ray because the previous script starts up a local ray cluster which creates a session
# that we can just clean up.
rm -rf /tmp/ray

NEGATIVE_FILTERS=""
if [[ -n "${SKIP_VLLM_BUILD:-}" ]]; then
NEGATIVE_FILTERS="$NEGATIVE_FILTERS vllm"
fi
if [[ -n "${SKIP_SGLANG_BUILD:-}" ]]; then
NEGATIVE_FILTERS="$NEGATIVE_FILTERS sglang"
fi
if [[ -n "$NEGATIVE_FILTERS" ]]; then
UV_LINK_MODE=hardlink uv run nemo_rl/utils/prefetch_venvs.py --negative-filters $NEGATIVE_FILTERS
else
UV_LINK_MODE=hardlink uv run nemo_rl/utils/prefetch_venvs.py
fi

# Address CVE GHSA-7rgv-gqhr-fxg3 by forcing xgrammar 0.1.32 in custom vllm and gym venvs
# It is not possible to use uv overrides with how we install these venvs
/opt/nemo-rl/3rdparty/vllm/.venv/bin/pip install xgrammar==0.1.32
/opt/gym_venvs/responses_api_models/vllm_model/.venv/bin/pip install xgrammar==0.1.32

# Prune unreachable cache entries
uv cache clean
EOF

ENV PATH="/opt/nemo_rl_venv/bin:$PATH"
ENV NEMO_RL_VENV_DIR=/opt/ray_venvs

# Custom setup layer (override with: --build-context custom-setup=<dir> --build-arg CUSTOM_SETUP_FNAME=<script>)
# To skip: --build-arg CUSTOM_SETUP_FNAME=
ARG CUSTOM_SETUP_FNAME=install_apptainer.sh
RUN --mount=from=custom-setup,src=/,dst=/tmp/custom-setup <<"EOF" bash -exu
if [[ -z "${CUSTOM_SETUP_FNAME}" ]]; then
echo "CUSTOM_SETUP_FNAME is empty, skipping custom setup"
exit 0
fi
cp /tmp/custom-setup/${CUSTOM_SETUP_FNAME} /opt/${CUSTOM_SETUP_FNAME}
bash -x /opt/${CUSTOM_SETUP_FNAME}
EOF

WORKDIR /opt/nemo-rl

FROM hermetic AS release
Expand All @@ -174,30 +238,6 @@ ENV NVIDIA_BUILD_REF=${NVIDIA_BUILD_REF:-<unknown>}
LABEL com.nvidia.build.id="${NVIDIA_BUILD_ID}"
LABEL com.nvidia.build.ref="${NVIDIA_BUILD_REF}"

ENV NEMO_RL_VENV_DIR=/opt/ray_venvs

# Copy in source from build context (defaults to cloned repo, can be overridden)
# Exclude pyproject.toml and uv.lock since those may be altered by build-custom-vllm.sh
COPY --from=nemo-rl --exclude=pyproject.toml --exclude=uv.lock . /opt/nemo-rl
# Unshallow the repo to get the full history (in the case it was from the scratch layer).
# Potentially not necessary if the repo is passed in as a complete repository (w/ full git history),
# so do a quick check before trying to unshallow.
RUN git rev-parse --is-shallow-repository | grep -q true && git fetch --unshallow || true
RUN <<"EOF" bash -exu
NEGATIVE_FILTERS=""
if [[ -n "${SKIP_VLLM_BUILD:-}" ]]; then
NEGATIVE_FILTERS="$NEGATIVE_FILTERS vllm"
fi
if [[ -n "${SKIP_SGLANG_BUILD:-}" ]]; then
NEGATIVE_FILTERS="$NEGATIVE_FILTERS sglang"
fi
if [[ -n "$NEGATIVE_FILTERS" ]]; then
UV_LINK_MODE=symlink uv run nemo_rl/utils/prefetch_venvs.py --negative-filters $NEGATIVE_FILTERS
else
UV_LINK_MODE=symlink uv run nemo_rl/utils/prefetch_venvs.py
fi
EOF

# Generate container fingerprint for frozen environment support
# Store outside /opt/nemo-rl to avoid being overwritten by user mounts
RUN python tools/generate_fingerprint.py > /opt/nemo_rl_container_fingerprint
Expand Down
10 changes: 10 additions & 0 deletions docker/install_apptainer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
set -euo pipefail
apt-get update
apt-get install -y --no-install-recommends software-properties-common
add-apt-repository -y ppa:apptainer/ppa
apt-get update
CODENAME=$(. /etc/os-release && echo "$VERSION_CODENAME")
apt-get install -y --no-install-recommends apptainer=1.4.5-1~${CODENAME}
ln -sf /usr/bin/apptainer /usr/bin/singularity
apt-get clean && rm -rf /var/lib/apt/lists/*
31 changes: 31 additions & 0 deletions docs/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,34 @@ When these build arguments are set, the corresponding `uv sync --extra` commands

> [!NOTE]
> If you skip vLLM or SGLang during the build but later try to use those backends at runtime, the dependencies will be fetched and built on-demand. This may add significant setup time on first use.

## Custom Setup Commands

By default, the Docker image installs [apptainer](https://apptainer.org/) (with a `singularity` symlink) via a pluggable `custom-setup` build stage. The default script is `docker/install_apptainer.sh`. You can override or skip this step at build time.

### Override with a custom script

Create a directory containing your setup script(s), then pass it as a build context along with the script filename:

```sh
# my-setup-dir/my_script.sh
#!/bin/bash
set -euo pipefail
apt-get update && apt-get install -y my-custom-package
apt-get clean && rm -rf /var/lib/apt/lists/*
```

```sh
docker buildx build \
--build-context custom-setup=my-setup-dir/ \
--build-arg CUSTOM_SETUP_FNAME=my_script.sh \
-f docker/Dockerfile --tag <registry>/nemo-rl:latest .
```

### Skip custom setup entirely

To build without any custom setup commands, set `CUSTOM_SETUP_FNAME` to empty:

```sh
docker buildx build --build-arg CUSTOM_SETUP_FNAME= -f docker/Dockerfile --tag <registry>/nemo-rl:latest .
```
2 changes: 2 additions & 0 deletions docs/guides/nemotron-3-nano.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

This guide explains how to post-train the [Nemotron 3 Nano model](https://research.nvidia.com/labs/nemotron/files/NVIDIA-Nemotron-3-Nano-Technical-Report.pdf) using NeMo RL.

**Note:** vLLM versions prior to 0.17.0 have a bug that causes logprob values to diverge between vLLM and Megatron for certain sequences, which can lead to training instability. To work around this, the recipe below sets `seq_logprob_error_threshold: 2` to mask out sequences where the logprob mismatch exceeds the threshold. This bug is fixed in vLLM 0.17.0 and will be incorporated in the Nemotron 3 Ultra release.

## Download and prepare the data

```bash
Expand Down
Loading
Loading