huggingface / huggingface/diffusers

`FlowMatchEulerDiscreteScheduler.set_timesteps` silently ignores explicit `timesteps` since #14011 — intended semantics change or unreleased regression?

Offen
#14,461 6 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
bug schedulers
Vorherrschende Sprache
Python
Sterne
34.5k
Forks
7.3k
Ø Merge
3 T. 3 Std.
Gemergte PRs (30 T.)
91

Beschreibung

### Describe the bug

Since #14011 (merged 2026-07-07, not yet in any release — v0.39.0 predates it), `FlowMatchEulerDiscreteScheduler.set_timesteps` unconditionally recomputes timesteps from the shifted sigmas ([`scheduling_flow_match_euler_discrete.py#L367`](https://github.com/huggingface/diffusers/blob/614ae4bb9df07d102ce1187777ef1c62f8aab0e8/src/diffusers/schedulers/scheduling_flow_match_euler_discrete.py#L367)), so an explicitly passed custom `timesteps` list is silently discarded. The docstring still promises "Custom values for timesteps **to be used** for each diffusion step" ([L305-L307](https://github.com/huggingface/diffusers/blob/614ae4bb9df07d102ce1187777ef1c62f8aab0e8/src/diffusers/schedulers/scheduling_flow_match_euler_discrete.py#L305-L307)), and `FlowMatchLCMScheduler` still honors the argument ([`scheduling_flow_match_lcm.py#L376-L379`](https://github.com/huggingface/diffusers/blob/614ae4bb9df07d102ce1187777ef1c62f8aab0e8/src/diffusers/schedulers/scheduling_flow_match_lcm.py#L376-L379)), so the two flow-match schedulers now disagree on the same argument.

Concrete impact inside the library: CogView4 / CogView4-Control / GLM-Image deliberately pass integer-cast timesteps plus paired sigmas ([`pipeline_cogview4.py#L587-L606`](https://github.com/huggingface/diffusers/blob/614ae4bb9df07d102ce1187777ef1c62f8aab0e8/src/diffusers/pipelines/cogview4/pipeline_cogview4.py#L587-L606) — a mechanism the model authors added in #10649) and feed `scheduler.timesteps` to the transformer as conditioning. With the official CogView4-6B scheduler config at 1024x1024, the conditioning timesteps now deviate from the passed values by up to **285.75 / 1000** (repro below). The #14011 discussion covered the SD3/Flux pattern (deriving timesteps when only sigmas are given) and did not mention these pipelines.

**Question for the maintainers: is discarding explicit `timesteps` the intended new semantics after #14011?**

- If **intended**: the docstring, the now-dead `is_timesteps_provided` variable ([L329](https://github.com/huggingface/diffusers/blob/614ae4bb9df07d102ce1187777ef1c62f8aab0e8/src/diffusers/schedulers/scheduling_flow_match_euler_discrete.py#L329)), `FlowMatchLCMScheduler`, and the now-ineffective integer-cast in the CogView4/GLM-Image pipelines should be aligned — I'm happy to submit that PR.
- If **not intended**: restoring the explicit-`timesteps` branch (while keeping #14011's recomputation for the derived case) before v0.40 ships would avoid releasing a silent behavior change — I'm happy to submit that PR instead; a minimal fix plus regression test is already prepared on my fork.

### Reproduction

Repro 1 — exactly what `pipeline_cogview4.py` passes (CogView4-6B config, 1024x1024, 10 steps):

```python
import numpy as np
from diffusers import FlowMatchEulerDiscreteScheduler

# THUDM/CogView4-6B scheduler config; mu=3.25 is what calculate_shift() yields at 1024x1024
sched = FlowMatchEulerDiscreteScheduler(
num_train_timesteps=1000, shift=1.0, use_dynamic_shifting=True,
base_shift=0.25, max_shift=0.75, base_image_seq_len=256,
max_image_seq_len=4096, time_shift_type="linear")
timesteps = np.linspace(1000, 1.0, 10).astype(np.int64).astype(np.float32) # as pipeline_cogview4.py does
sched.set_timesteps(10, sigmas=(timesteps / 1000).tolist(), timesteps=timesteps.tolist(), mu=3.25)
print(sched.timesteps.tolist()) # expected: the passed values [1000.0, 889.0, ..., 1.0]
```

Output on `main` (614ae4b):

```
passed : [1000.0, 889.0, 778.0, 667.0, 556.0, 445.0, 334.0, 223.0, 112.0, 1.0]
got : [1000.0, 963.0, 919.29, 866.84, 802.75, 722.67, 619.75, 482.6, 290.73, 3.24]
max delta: 285.75
```

Before #14011 (all releases through v0.39.0), the output equals the passed values.

Repro 2 — divergence from FlowMatchLCMScheduler (same inputs, static shift=3.0)

```python
from diffusers import FlowMatchEulerDiscreteScheduler
from diffusers.schedulers.scheduling_flow_match_lcm import FlowMatchLCMScheduler

ts = [1000.0, 750.0, 500.0, 250.0, 1.0]
sg = [t / 1000 for t in ts]
euler = FlowMatchEulerDiscreteScheduler(num_train_timesteps=1000, shift=3.0)
lcm = FlowMatchLCMScheduler(num_train_timesteps=1000, shift=3.0)
euler.set_timesteps(sigmas=sg, timesteps=ts)
lcm.set_timesteps(sigmas=sg, timesteps=ts)
print(euler.timesteps.tolist()) # [1000.0, 900.0, 750.0, 500.0, 2.99] <- input ignored
print(lcm.timesteps.tolist()) # [1000.0, 750.0, 500.0, 250.0, 1.0] <- input honored
```

(Both produce identical `sigmas`; only `timesteps` diverge.)

### Logs

```shell
(see outputs inline above)
```

### System Info

- 🤗 Diffusers version: 0.40.0.dev0 (main @ 614ae4b)
- Platform: macOS-26.5.2-arm64-arm-64bit-Mach-O
- Running on Google Colab?: No
- Python version: 3.13.3
- PyTorch version (GPU?): 2.13.0 (False)
- Huggingface_hub version: 1.27.0
- Transformers version: 5.15.0
- Accelerate version: not installed
- PEFT version: not installed
- Safetensors version: 0.8.0
- xFormers version: not installed
- Accelerator: Apple M4
- Using GPU in script?: No
- Using distributed or parallel set-up in script?: No

### Who can help?

_No response_

---

*Disclosure: this report was prepared with AI assistance following the "AI-assisted and agentic contributions" guide; I reproduced the issue locally at 614ae4b and reviewed every claim. Per the guide, I'm coordinating here first and will wait for maintainer acknowledgment before opening any PR.*

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

Start with src/diffusers/schedulers/scheduling_flow_match_euler_discrete.py around set_timesteps and compare its explicit-timesteps handling with scheduling_flow_match_lcm.py. Run the two inline reproductions and inspect the cited CogView4 and GLM-Image pipeline call sites. Done means the intended semantics are confirmed, documented or restored consistently, and covered by a regression test.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python, pytorch
Bereich
machine-learning, testing
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Ruhig
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
45/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.