Skip to content

fix: Use Karras sigma schedule for Cosmos Predict2.5 SFT inference#33

Open
mvanhorn wants to merge 1 commit into
NVlabs:mainfrom
mvanhorn:fix/18-cosmos-predict2-karras-sigma-schedule
Open

fix: Use Karras sigma schedule for Cosmos Predict2.5 SFT inference#33
mvanhorn wants to merge 1 commit into
NVlabs:mainfrom
mvanhorn:fix/18-cosmos-predict2-karras-sigma-schedule

Conversation

@mvanhorn

@mvanhorn mvanhorn commented Jun 17, 2026

Copy link
Copy Markdown

Summary

Cosmos-Predict2.5-2B video2world inference under FastGen produces noticeably degraded output compared to the official cosmos-predict2.5 codebase when using the same checkpoint, prompt, image, resolution, and step count. The reporter traced the primary cause to a wrong sigma/timestep schedule: the official Cosmos uses a Karras sigma schedule (sigma_max=200, sigma_min=0.01, rho=7) in its FlowUniPCMultistepScheduler.set_timesteps(use_kerras_sigma=True), while FastGen's CosmosPredict2DiT.sample() relies on the default diffusers flow-shift linear schedule from UniPCMultistepScheduler.

Changes

In fastgen/networks/cosmos_predict2/network.py, modify the sample() method (around lines 1148-1161) so that, for the Cosmos SFT sampling path, after constructing the UniPCMultistepScheduler and calling set_timesteps, it overrides sample_scheduler.sigmas and sample_scheduler.timesteps with a Karras sigma schedule (sigma_max=200, sigma_min=0.01, rho=7) exactly as the official Cosmos does, including the sigmas/(1+sigmas) reparameterization, int64 timestep truncation, and resetting the scheduler's internal solver state (model_outputs, lower_order_nums, last_sample, _step_index, _begin_index). Gate this behind a sensible default or config flag so it only affects the SFT inference path the maintainer called out, not distillation. Update the inline example command(s) in scripts/inference/video_model_inference.py to pass the Cosmos negative-prompt file and otherwise align them with scripts/README.md. Add a focused unit test in tests/test_network.py asserting the produced sigma/timestep schedule matches the reference Karras values.

Fixes #18

Summary by CodeRabbit

  • New Features
    • Added an optional Karras sigma schedule for Cosmos Predict2 sampling, improving UniPC inference behavior and allowing the schedule to be enabled or disabled.
  • Bug Fixes
    • Sampling now resets scheduler state before generation to avoid stale values affecting results.
    • Progress reporting now matches the actual number of timesteps.
  • Documentation
    • Updated inference examples with clearer, more consistent command-line flags and model settings.
  • Tests
    • Added coverage for the new schedule behavior, scheduler reset handling, and updated example commands.

@greptile-apps

greptile-apps Bot commented Jun 17, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes degraded Cosmos Predict2.5 SFT inference quality by overriding the default linear sigma schedule with the Karras schedule (σ_max=200, σ_min=0.01, ρ=7) actually used by the official Cosmos codebase, and aligns the inference script example commands with scripts/README.md.

  • Adds _build_cosmos_predict2_karras_schedule / _apply_cosmos_predict2_karras_schedule helpers that replicate the official Karras ramp and reparameterization, then reset the UniPC solver state; gated by a use_karras_sigma_schedule flag that defaults to True.
  • Updates all inline example commands in video_model_inference.py to include --num_steps, --fps, and --neg_prompt_file; the Cosmos V2W example gains model.input_shape and the Cosmos-specific negative prompt.
  • Adds three unit tests covering sigma value correctness, scheduler state reset, and a snapshot check on the example command.

Confidence Score: 3/5

The core sigma-schedule logic is correct and the test coverage is solid, but the sigmas tensor is left on CPU after the Karras override, which will cause a device error the first time scheduler.step() is called on a GPU.

The Karras schedule math and state-reset are correctly implemented and well tested. However, _build_cosmos_predict2_karras_schedule never moves sigmas to device: it calls .to(dtype=torch.float32) but omits device=device, while the timesteps tensor is correctly moved. After the Karras override, scheduler.sigmas is a CPU tensor and scheduler.timesteps is a CUDA tensor, undoing the device placement that set_timesteps(device=noise.device) had just established. Every GPU inference run will hit a RuntimeError in scheduler.step(). The tests all use torch.device('cpu') so this is not caught.

fastgen/networks/cosmos_predict2/network.py — specifically _build_cosmos_predict2_karras_schedule (sigmas device placement) and the use_karras_sigma_schedule=True default which may affect distillation configs.

Important Files Changed

Filename Overview
fastgen/networks/cosmos_predict2/network.py Adds Karras sigma schedule for Cosmos Predict2.5 SFT inference; the sigmas tensor is not moved to the requested device, which will crash GPU inference in scheduler.step(). The default-True flag may also silently change distillation eval behavior.
scripts/inference/video_model_inference.py Updates inline example commands: adds --num_steps, --fps, and --neg_prompt_file to all examples; aligns Cosmos V2W example with scripts/README.md.
tests/test_network.py Adds three focused unit tests for the Karras schedule. Tests run on CPU only, so the device-mismatch bug is not caught.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant C as Caller
    participant S as CosmosPredict2.sample()
    participant K as _apply_cosmos_predict2_karras_schedule()
    participant B as _build_cosmos_predict2_karras_schedule()
    participant U as UniPCMultistepScheduler

    C->>S: "sample(noise, condition, num_steps=35)"
    S->>U: "set_timesteps(35, device=cuda)"
    Note over U: sigmas on cuda, timesteps on cuda
    S->>K: apply schedule(scheduler, 35, cuda)
    K->>B: build schedule(35, 1000, cuda)
    Note over B: sigmas computed on CPU
    Note over B: timesteps moved to cuda
    Note over B: sigmas NOT moved to cuda
    B-->>K: sigmas (CPU), timesteps (cuda)
    K->>U: "scheduler.sigmas = CPU tensor"
    K->>U: "scheduler.timesteps = cuda tensor"
    loop 36 denoising steps
        S->>U: step(velocity_pred, timestep, sample)
        Note over U: self.sigmas[i] is CPU
        Note over U: RuntimeError on GPU
    end
    S-->>C: denoised latents
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant C as Caller
    participant S as CosmosPredict2.sample()
    participant K as _apply_cosmos_predict2_karras_schedule()
    participant B as _build_cosmos_predict2_karras_schedule()
    participant U as UniPCMultistepScheduler

    C->>S: "sample(noise, condition, num_steps=35)"
    S->>U: "set_timesteps(35, device=cuda)"
    Note over U: sigmas on cuda, timesteps on cuda
    S->>K: apply schedule(scheduler, 35, cuda)
    K->>B: build schedule(35, 1000, cuda)
    Note over B: sigmas computed on CPU
    Note over B: timesteps moved to cuda
    Note over B: sigmas NOT moved to cuda
    B-->>K: sigmas (CPU), timesteps (cuda)
    K->>U: "scheduler.sigmas = CPU tensor"
    K->>U: "scheduler.timesteps = cuda tensor"
    loop 36 denoising steps
        S->>U: step(velocity_pred, timestep, sample)
        Note over U: self.sigmas[i] is CPU
        Note over U: RuntimeError on GPU
    end
    S-->>C: denoised latents
Loading

Reviews (1): Last reviewed commit: "fix: Use Karras sigma schedule for Cosmo..." | Re-trigger Greptile

sigmas = sigmas / (1 + sigmas)

timesteps = (sigmas * num_train_timesteps).to(device=device, dtype=torch.int64)
sigmas = torch.cat([sigmas, sigmas.new_zeros(1)]).to(dtype=torch.float32)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 sigmas never moved to device, breaking GPU inference

ramp is always created on CPU via torch.arange(...), so all derived sigmas computations stay on CPU. timesteps is correctly moved with .to(device=device, ...), but the final sigmas tensor that is returned (and ultimately stored in scheduler.sigmas) stays on CPU. When scheduler.step() is called during GPU inference it will index into the CPU sigmas tensor and use the resulting CPU 0-dim tensors in arithmetic with CUDA latent tensors, raising a RuntimeError: Expected all tensors to be on the same device. The prior set_timesteps(device=noise.device) call correctly places sigmas on device — this Karras override silently undoes that.

Suggested change
sigmas = torch.cat([sigmas, sigmas.new_zeros(1)]).to(dtype=torch.float32)
timesteps = (sigmas * num_train_timesteps).to(device=device, dtype=torch.int64)
sigmas = torch.cat([sigmas, sigmas.new_zeros(1)]).to(dtype=torch.float32, device=device)
return sigmas, timesteps

use_wan_fp32_strategy: bool = True,
# FPS for temporal position embeddings
fps: float = 24.0,
use_karras_sigma_schedule: bool = True,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Default True may silently change distillation inference

The PR description says to "gate this behind a sensible default or config flag so it only affects the SFT inference path, not distillation." Setting use_karras_sigma_schedule=True as the class-level default means every CosmosPredict2 instance — including distillation models — will use the Karras schedule unless the corresponding experiment config explicitly passes use_karras_sigma_schedule=False. If the distillation configs don't set that flag, evaluation of distilled checkpoints will silently start using a different sigma schedule, making before/after comparisons invalid.

)
scheduler.sigmas = sigmas
scheduler.timesteps = timesteps
scheduler.num_inference_steps = len(timesteps)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 num_inference_steps set to num_steps + 1, denoising loop runs one extra iteration

_build_cosmos_predict2_karras_schedule uses torch.arange(num_steps + 1) which produces num_steps + 1 ramp points (including both endpoints 0 and 1). This yields a timesteps tensor of length num_steps + 1, so scheduler.num_inference_steps is set to num_steps + 1 and the denoising loop in sample() iterates num_steps + 1 times. When a user passes --num_steps 35, they will actually get 36 denoising steps. If this matches the official Cosmos reference implementation this is intentional, but it should be documented explicitly.

@juliusberner

Copy link
Copy Markdown
Collaborator

@coderabbitai

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

@juliusberner I'll review the changes on this PR now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@juliusberner

Copy link
Copy Markdown
Collaborator

Hi @mvanhorn,

Thanks a lot for the fix! Is there a reason why we can't just use use_karras_sigmas in our FlowUniPCMultistepScheduler?

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Cosmos Predict2 sampling now supports an optional Karras sigma schedule, resets UniPC scheduler state before sampling, and uses the resolved timestep count for progress. The Cosmos inference examples and tests were updated to match the new schedule and CLI arguments.

Changes

Cosmos Predict2 Karras Sampling

Layer / File(s) Summary
Karras schedule helpers
fastgen/networks/cosmos_predict2/network.py
Builds the Cosmos Predict2.5 Karras sigma/timestep schedule and clears UniPC scheduler step state after the schedule is reassigned.
Sample flag and scheduler application
fastgen/networks/cosmos_predict2/network.py
Adds a default Karras toggle to CosmosPredict2, lets sample() override it, applies the schedule conditionally, and updates the progress bar to use len(timesteps).
Examples and tests
scripts/inference/video_model_inference.py, tests/test_network.py
Updates the Cosmos example commands and adds tests for the Karras schedule builder, scheduler state reset, and expected example text.

Sequence Diagram(s)

sequenceDiagram
  participant Sample as "CosmosPredict2.sample"
  participant Scheduler as "UniPCMultistepScheduler"
  participant Apply as "_apply_cosmos_predict2_karras_schedule"
  participant Progress as "tqdm"
  Sample->>Scheduler: set_timesteps(num_steps, device)
  Sample->>Apply: apply Karras sigma schedule
  Apply->>Scheduler: assign sigmas, timesteps, and reset step state
  Sample->>Progress: iterate with total=len(timesteps)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through sigmas, neat and small,
Karras stars now line the crawl.
UniPC twitches, steps align,
Timesteps tick in carrot time.
FastGen ears up — sample bright!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: using a Karras sigma schedule for Cosmos Predict2.5 SFT inference.
Linked Issues check ✅ Passed The code changes align with issue #18 by matching the Karras schedule, resetting scheduler state, updating the example, and adding a focused test.
Out of Scope Changes check ✅ Passed The docstring example and added tests are directly tied to the Cosmos inference fix and do not introduce unrelated scope.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@fastgen/networks/cosmos_predict2/network.py`:
- Line 819: The shared CosmosPredict2 network default for
use_karras_sigma_schedule should not be enabled in the base sample path, because
CosmosPredict2_2B_Config and CosmosPredict2_14B_Config are reused by non-SFT
configs like DMD2 and video2world. Update CosmosPredict2.sample() and the
relevant network/config definitions so the shared default stays False, then set
use_karras_sigma_schedule to True only in the SFT-specific config path in
config_sft.py, keeping non-SFT callers on the existing behavior unless they
explicitly override it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 4e4c1b73-0452-4878-a8c4-382cb661fece

📥 Commits

Reviewing files that changed from the base of the PR and between c40fbea and c2c3ee0.

📒 Files selected for processing (3)
  • fastgen/networks/cosmos_predict2/network.py
  • scripts/inference/video_model_inference.py
  • tests/test_network.py

use_wan_fp32_strategy: bool = True,
# FPS for temporal position embeddings
fps: float = 24.0,
use_karras_sigma_schedule: bool = True,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect CosmosPredict2 call sites and config overrides for the new schedule flag.
rg -n -C2 'use_karras_sigma_schedule|CosmosPredict2|config_sft|distill|sample\(' .

Repository: NVlabs/FastGen

Length of output: 50371


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the CosmosPredict2 constructor, sample method, and config usages.
for f in \
  fastgen/networks/cosmos_predict2/network.py \
  fastgen/configs/net.py \
  fastgen/configs/experiments/CosmosPredict2/config_sft.py \
  fastgen/configs/experiments/CosmosPredict2/config_sft_14b.py \
  fastgen/configs/experiments/CosmosPredict2/config_sft_v2w.py \
  fastgen/configs/experiments/CosmosPredict2/config_dmd2.py \
  fastgen/configs/experiments/CosmosPredict2/config_dmd2_14b.py \
  fastgen/configs/experiments/CosmosPredict2/config_dmd2_v2w.py \
  scripts/inference/video_model_inference.py
do
  if [ -f "$f" ]; then
    echo "===== $f ====="
    wc -l "$f"
  fi
done

echo "===== network.py outline ====="
ast-grep outline fastgen/networks/cosmos_predict2/network.py --view expanded || true

echo "===== network.py relevant slices ====="
sed -n '740,930p' fastgen/networks/cosmos_predict2/network.py

echo "===== net.py cosmos slice ====="
sed -n '270,310p' fastgen/configs/net.py

echo "===== Cosmos SFT configs ====="
sed -n '1,120p' fastgen/configs/experiments/CosmosPredict2/config_sft.py
printf '\n'
sed -n '1,120p' fastgen/configs/experiments/CosmosPredict2/config_sft_14b.py
printf '\n'
sed -n '1,120p' fastgen/configs/experiments/CosmosPredict2/config_sft_v2w.py
printf '\n'
sed -n '1,160p' fastgen/configs/experiments/CosmosPredict2/config_dmd2.py
printf '\n'
sed -n '1,160p' fastgen/configs/experiments/CosmosPredict2/config_dmd2_14b.py
printf '\n'
sed -n '1,160p' fastgen/configs/experiments/CosmosPredict2/config_dmd2_v2w.py

echo "===== inference call sites around model.sample ====="
sed -n '660,720p' scripts/inference/video_model_inference.py

Repository: NVlabs/FastGen

Length of output: 24679


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Focused searches for explicit schedule overrides and direct CosmosPredict2 usage.
rg -n -C3 'use_karras_sigma_schedule\s*=|use_karras_sigma_schedule|CosmosPredict2\(' fastgen scripts tests

Repository: NVlabs/FastGen

Length of output: 4873


Move the Karras default to the SFT config path. CosmosPredict2_2B_Config / CosmosPredict2_14B_Config are reused by DMD2 and video2world configs unchanged, so CosmosPredict2.sample() still sends non-SFT callers down the Karras path unless they override it explicitly. Keep the shared network default False and set it to True only in fastgen/configs/experiments/CosmosPredict2/config_sft.py.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@fastgen/networks/cosmos_predict2/network.py` at line 819, The shared
CosmosPredict2 network default for use_karras_sigma_schedule should not be
enabled in the base sample path, because CosmosPredict2_2B_Config and
CosmosPredict2_14B_Config are reused by non-SFT configs like DMD2 and
video2world. Update CosmosPredict2.sample() and the relevant network/config
definitions so the shared default stays False, then set
use_karras_sigma_schedule to True only in the SFT-specific config path in
config_sft.py, keeping non-SFT callers on the existing behavior unless they
explicitly override it.

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.

[Bug] Cosmos Predict2.5 inference quality mismatch with official codebase — wrong sigma schedule

2 participants