Skip to content

Cosmos3 Distilled support#14177

Open
yzhautouskay wants to merge 4 commits into
huggingface:mainfrom
yzhautouskay:yzhautouskay/cosmos3_distilled
Open

Cosmos3 Distilled support#14177
yzhautouskay wants to merge 4 commits into
huggingface:mainfrom
yzhautouskay:yzhautouskay/cosmos3_distilled

Conversation

@yzhautouskay

Copy link
Copy Markdown
Contributor

What does this PR do?

Cosmos3 distilled (few-step) support

Adds inference support for the distilled few-step Cosmos3 checkpoints through the
modular pipeline (Cosmos3OmniModularPipeline).

Checkpoints supported

  • nvidia/Cosmos3-Super-Text2Image-4Step (distilled T2I)
  • nvidia/Cosmos3-Super-Image2Video-4Step (distilled I2V)

Both ship a FlowMatchEulerDiscreteScheduler with a fixed sigma schedule
(scheduler.config.fixed_step_sampler_config.t_list) and bake classifier-free
guidance into the weights. They are only supported via the modular pipeline; the
task-based Cosmos3OmniPipeline does not implement the distilled contract.

Before submitting

Who can review?

Anyone in the community is free to review the PR once the tests have passed. Feel free to tag
members/contributors who may be interested in your PR.

@github-actions github-actions Bot added size/L PR with diff > 200 LOC documentation Improvements or additions to documentation modular-pipelines and removed size/L PR with diff > 200 LOC labels Jul 13, 2026

@yiyixuxu yiyixuxu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

thanks!
i left some comments

Comment thread src/diffusers/modular_pipelines/cosmos/before_denoise.py
Comment thread src/diffusers/modular_pipelines/cosmos/modular_pipeline.py Outdated
Comment thread src/diffusers/modular_pipelines/cosmos/modular_pipeline.py Outdated
Comment thread src/diffusers/modular_pipelines/cosmos/modular_pipeline.py Outdated
Comment thread src/diffusers/modular_pipelines/cosmos/denoise.py Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Hi @yzhautouskay, thanks for the PR! It does not appear to link an issue it fixes. If this PR addresses an existing issue, please add a closing keyword (e.g. Fixes #1234) to the PR description so the issue is linked. See the contribution guide for more details. If this PR intentionally does not fix a tracked issue, a maintainer can add the no-issue-needed label to silence this reminder.

@yzhautouskay

Copy link
Copy Markdown
Contributor Author

thanks @yiyixuxu! I've refactored it to have separate Cosmos3DistilledModularPipeline

@yiyixuxu

Copy link
Copy Markdown
Collaborator

@yzhautouskay can you resolve the conflict?

@yzhautouskay
yzhautouskay force-pushed the yzhautouskay/cosmos3_distilled branch from 177ee1e to 3ac7ec0 Compare July 15, 2026 09:43
@yzhautouskay
yzhautouskay force-pushed the yzhautouskay/cosmos3_distilled branch from 3ac7ec0 to abb37e7 Compare July 15, 2026 09:48

@yiyixuxu yiyixuxu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

thanks, I left some comments

Comment thread docs/source/en/api/pipelines/cosmos3.md Outdated
Comment thread src/diffusers/modular_pipelines/modular_pipeline.py Outdated
Comment thread src/diffusers/modular_pipelines/cosmos/before_denoise.py Outdated
Comment thread src/diffusers/modular_pipelines/cosmos/before_denoise.py Outdated
Comment thread src/diffusers/modular_pipelines/cosmos/encoders.py Outdated
]


def _fake_distilled_components(t_list=(1.0, 0.75, 0.5, 0.25)):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done, distilled tests now use ModularPipelineTesterMixin. For now tiny fixture lives under my personal account at yzhautouskay/tiny-cosmos3-distilled-modular-pipe
Could you create hf-internal-testing/tiny-cosmos3-distilled-modular-pipe and copy it over ? I'll then flip the TINY_DISTILLED_REPO constant in the test (and pretrained_model_name_or_path will need to be changed for components in modular_model_index.json)

@HuggingFaceDocBuilderDev

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@yiyixuxu yiyixuxu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

thanks, I left some final comments on tests & docs, we can merge after these are addressed

return SimpleNamespace(_execution_device="cpu", config=config)


def test_cosmos3_distilled_vae_encoder_select_block():

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can you move this test to TestCosmos3DistilledModularPipelineFast,
you can do something like

def test_vae_encoder_rejects_image_and_video_together(self):
      vae_encoder = Cosmos3DistilledBlocks().sub_blocks["vae_encoder"]
      vae_pipe = vae_encoder.init_pipeline(self.pretrained_model_name_or_path)
      vae_pipe.load_components(torch_dtype=torch.float32)
     
      with pytest.raises(ValueError, match="either image or video"):
          vae_pipe(image=image, video=video, num_frames=5, height=32, width=32)

vae_encoder.select_block(image=object(), video=object())


def test_cosmos3_distilled_set_timesteps_declares_distilled_configs():

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can you move this test to the TestCosmos3DistilledModularPipelineFast too
Also, it'd be more meaningful to test the final pipeline's config

pipe = self.pipeline_class()
assert pipe.config.is_distilled is True
assert pipe.config.distilled_sigmas is None  

Comment on lines +151 to +154
def test_cosmos3_distilled_text_encoder_requires_str_prompt():
Cosmos3DistilledTextEncoderStep._check_inputs(SimpleNamespace(prompt="a robot"))
with pytest.raises(ValueError, match="`prompt` must be a str"):
Cosmos3DistilledTextEncoderStep._check_inputs(SimpleNamespace(prompt=["a robot", "another"]))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can you move this test to the TestCosmos3DistilledModularPipelineFast too
also think it is more meaningful to test this behavior on final pipeline, instead of the _check_inputs

  def test_rejects_batched_prompts(self):
      pipe = self.get_pipeline()
      inputs = self.get_dummy_inputs()
      inputs["prompt"] = ["a robot", "another"]

      with pytest.raises(ValueError, match="..."):
          pipe(**inputs, output=self.output_name)

Comment on lines +145 to +148
def test_cosmos3_distilled_text_encoder_omits_negative_prompt():
input_names = {inp.name for inp in Cosmos3DistilledTextEncoderStep().inputs}
assert "prompt" in input_names
assert "negative_prompt" not in input_names

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can you remove this test for now? we can extend our base test here to support a "not_params"
https://github.com/huggingface/diffusers/blob/main/tests/modular_pipelines/test_modular_pipelines_common.py#L165

Comment on lines +126 to +128
def _fake_distilled_components(sigmas=(1.0, 0.9375, 0.8333333333333334, 0.625)):
config = SimpleNamespace(distilled_sigmas=list(sigmas))
return SimpleNamespace(_execution_device="cpu", config=config)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
def _fake_distilled_components(sigmas=(1.0, 0.9375, 0.8333333333333334, 0.625)):
config = SimpleNamespace(distilled_sigmas=list(sigmas))
return SimpleNamespace(_execution_device="cpu", config=config)

Cosmos3DistilledTextEncoderStep._check_inputs(SimpleNamespace(prompt=["a robot", "another"]))


def test_cosmos3_distilled_set_timesteps_rejects_step_count_override():

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

same comment https://github.com/huggingface/diffusers/pull/14177/changes#r3598260664
I think it's more meaningful to test all the behavior on final pipeline (not individual steps)

  def test_rejects_num_inference_steps_override(self):
      pipe = self.get_pipeline()
      inputs = self.get_dummy_inputs()
      inputs["num_inference_steps"] = 10
      
      with pytest.raises(..."):
          pipe(**inputs, output=self.output_name)

step(_fake_distilled_components(), state)


def test_cosmos3_distilled_set_timesteps_rejects_guidance_override():

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

 def test_rejects_guidance_scale_override(self):
      pipe = self.get_pipeline()
      inputs = self.get_dummy_inputs()
      inputs["guidance_scale"] = 3.0
      
      with pytest.raises(ValueError, match="`guidance_scale` must be 1.0"):
          pipe(**inputs, output=self.output_name)

step(_fake_distilled_components(), state)


def test_cosmos3_distilled_set_timesteps_requires_distilled_sigmas():

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe remove this one?

Load a distilled repo and call the pipeline **without** `num_inference_steps` or
`guidance_scale`; `Cosmos3DistilledSetTimestepsStep` reads the fixed step count from the
scheduler config and forces `guidance_scale=1.0`. Because classifier-free guidance is baked
into the weights, `negative_prompt` is not supported (passing one raises an error).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
into the weights, `negative_prompt` is not supported (passing one raises an error).
into the weights, `negative_prompt` is not supported (passing one raises a warning and get ignored).

### Distilled (few-step) text-to-image and image-to-video

Few-step distilled checkpoints ship a fixed sigma schedule in
`scheduler.config.fixed_step_sampler_config.t_list` and bake classifier-free guidance into

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we need to udpate the doc here, no? now it is a pipeline config


# TODO: move this fixture to `hf-internal-testing/tiny-cosmos3-distilled-modular-pipe` and update the
# repo name here. Hosted on a personal account for now so the PR can be tested.
TINY_DISTILLED_REPO = "yzhautouskay/tiny-cosmos3-distilled-modular-pipe"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation modular-pipelines size/L PR with diff > 200 LOC tests utils

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants