DiffusionNFT¶
Online RL for Cosmos world-foundation diffusion models: sample a group of generations per prompt,
score them with an image or video reward, and train the flow model on the resulting advantage.
Facts here are read from config/rl.py::NFTConfig, entrypoints/nft.py, and algorithm/nft.py.
1. When to choose it¶
Use DiffusionNFT when the thing you are improving is a diffusion generator and you have a reward that scores its output — an aesthetic or preference model on decoded images, or a video reward on decoded frames. It is the online counterpart to DPO for these models: DPO needs preference pairs collected in advance, NFT generates and scores its own samples every step.
Choose dpo.md instead when you already have preference pairs — it needs no rollout and
no reward model at training time, so it is far cheaper. NFT is for the case where you can score but
cannot pair.
NFT is the most constrained entry in the framework. Production runs are required to use one topology (see §4), so it has fewer degrees of freedom than GRPO by design.
2. Quick start¶
NFT runs are experiment= configurations, not --config recipes. The public four-GPU profile is
cosmos3_nft_t2i_public_4gpu: Cosmos3-Nano, four-rank FSDP, four prompt rows, and an HTTP
image-reward service. Set up the container and Posttrain environment from
sections 1 and 2 of the run guide, then prepare
the Nano DCP, the VAE, the prompt file, the reward-service variables and the local toy reward
service exactly as in section 7.
Check the wiring first — NFT's preflight validates far more than the manifest, including the
sampler contract, the reward provider revision, and the moving-old schedule. --validate-manifest
must come before the -- separator: cli() keeps only key=value items after it, so the flag
would be silently dropped and the command would start training instead.
"$POSTTRAIN_PY" -m cosmos_framework.posttrain.entrypoints.nft \
--validate-manifest -- experiment=cosmos3_nft_t2i_public_4gpu
"$POSTTRAIN_PY" -m cosmos_framework.posttrain.entrypoints.nft -- \
experiment=cosmos3_nft_t2i_public_4gpu \
job.name=nft_public_4gpu
The profile runs 400 steps; append rl.max_steps=5 for a short check. The
cosmos3_nft_t2i_public recipe it derives from is described in §9.
3. Data contract¶
rl.modality selects the decoded media type, image or video (default video). It identifies
the media type only; it does not implicitly select production coordinates.
The two modalities take different contracts:
| Modality | rl.profile |
Reward |
|---|---|---|
video |
Not included in this release | Not included |
image |
Must name a known T2I profile; an unknown name is rejected with the supported list | ImageRewardConfig |
rl.init_from is required — NFT always starts from a base checkpoint, and an empty value fails
preflight rather than training from scratch.
4. Topology and launch¶
Production online NFT is required to use exactly one shape. Preflight rejects anything else:
| Setting | Required value | Why |
|---|---|---|
grid.backend |
ray |
The five roles are one Ray ActorGroup |
grid.grouping |
single |
data, rollout, reward, replay, and policy share one process per rank |
grid.gpu_placement |
colocated |
That actor mesh forms one distributed FSDP world |
grid.gpus_per_role |
unset | Colocated NFT does not accept per-role GPU overrides |
Shapes are equally fixed: policy and rollout must both be (1, group_size) — one execution
replica, and one WFM member per model rank. _nft_role_shapes derives this from
grid.shapes when given, or from grid.num_replicas / grid.ranks otherwise, and rejects any
other combination.
Concretely, rl.group_size=8 means eight model ranks, one generated sample per rank.
5. Key configuration¶
Complete table: ../reference/config.md. Defaults below are read from
NFTConfig.
| Knob | Default | What it controls |
|---|---|---|
rl.group_size |
4 |
Samples per prompt — and, per §4, the model rank count |
rl.beta |
1.0 |
Objective sharpness |
rl.kl_beta |
1.0 |
KL penalty weight. The qualified T2I recipe sets this to 0 |
rl.policy_loss_scale |
5.0 |
Scale on the policy loss term |
rl.advantage_low / advantage_high |
-5.0 / 5.0 |
Advantage clamp |
rl.r_map |
"linear" |
Optimality map, linear or sigmoid |
rl.r_tau |
0.5 |
Temperature for the sigmoid map |
rl.uniform_timestep |
False |
Sample the RF timestep uniformly |
rl.sample_steps |
20 |
Sampler steps per generation |
rl.sampler_shift |
5.0 |
RF sampler shift |
rl.guidance |
3.0 |
Classifier-free guidance |
rl.rollout_seed_clock |
"source_row" |
Whether the rank-local seed set advances per source row or per optimizer step |
rl.old.update_every |
— | Moving-old refresh cadence. Must be >= 1 with build_old enabled |
rl.ref.update_every |
0 |
The reference is frozen; a nonzero value is rejected |
Guidance does not mean what it means in the reference implementation. Native OmniMoT computes
v_uncond + guidance * (v_cond - v_uncond), so guidance 1 is conditional-only and guidance 0 is unconditional. The reference sampler special-cases zero as conditional-only. Do not copy a numericguidance=0across.
The scheduler type must be unipc; preflight rejects other samplers.
6. Is it training correctly¶
NFT's objective uses MEAN reduction, not TOKEN_SUM, so its metrics aggregate as plain means.
| Metric | Read it for |
|---|---|
train/reward_mean |
The task signal |
train/policy_loss / train/kl_loss |
The two loss components separately — a KL term that dominates means the policy is being held at the reference |
train/advantage_mean |
Should stay well inside the advantage_low/advantage_high clamp; pinned at a bound means the clamp is doing the work |
train/optimality_mean / train/optimality_second_moment |
The optimality ratio's first and second moment |
train/positive_error / train/negative_error |
Error on each branch |
Full table: ../reference/metrics.md.
7. Checkpoints¶
Shared mechanics: ../reference/checkpoint.md. NFT additionally
persists the moving old policy, the prompt cursor, and the seed contract. Exact resume
rejects a changed seed contract before advancing the prompt cursor, so a run cannot silently
continue under different sampling.
rl.init_keys_to_skip_loading allows a partial load from the base checkpoint; the video contract
requires it to be empty.
8. Failure semantics and limits¶
- Preflight is strict and refuses rather than warns. Backend, grouping, GPU placement, role shapes, profile/modality agreement, reward provider revision, sampler type, moving-old cadence, and a frozen reference are all validated before any GPU work.
- Video NFT rejects a non-empty
rl.profile; image NFT rejects an unknown one. - A missing reward provider revision is fatal. The provider's declared revision participates in run identity, so an unpinned provider cannot be used.
- The topology is not configurable (§4). This is a deliberate production constraint, not an unimplemented feature.
9. Public T2I recipe¶
cosmos3_nft_t2i_public is the release-facing image NFT recipe. It replaces
internal experiment, dataset, cluster and checkpoint defaults with explicit
operator-provided artifacts while retaining the T2I model, objective, LoRA,
sampling and reward contracts. See the
public run guide.