invoke-ai/InvokeAI · error · ValueError
PiD student schedule for num_steps={num_steps} is not strict
Error message
PiD student schedule for num_steps={num_steps} is not strictly decreasing (got {t.tolist()}); the schedule has only 4 transitions, so num_steps must be between 1 and 4. What it means
The PiD student sampler uses a fixed 5-point schedule (4 transitions), and _get_t_list sub-samples it with linspace for a requested num_steps. If num_steps > 4, distinct linspace indices collapse onto the same timestep, producing duplicates; duplicates are not strictly decreasing and would waste a network forward while degrading output. The function therefore raises ValueError (not assert, so the check survives python -O) when the derived schedule is not strictly decreasing.
Source
Thrown at invokeai/backend/pid/decode.py:320
"""Distill-student sigma schedule.
When *num_steps* differs from the trained 4 steps, linearly sub-sample
the canonical 5-point list (mirrors `PidDistillModel._get_t_list`).
"""
full = torch.tensor(_STUDENT_T_LIST, device=device, dtype=torch.float32)
if num_steps is None or num_steps == 4:
t = full
else:
idx = torch.linspace(0, len(full) - 1, num_steps + 1).round().long()
t = full[idx]
assert abs(t[-1].item()) < 1e-6, "t_list must end at 0"
# The student schedule has only 4 transitions (a 5-point list). Sub-sampling to more
# than 4 steps rounds distinct linspace indices onto the same point, yielding duplicate
# timesteps that _student_sample_loop would waste a full network forward on (and which
# degrade rather than refine the output). Callers cap num_steps at 4; raise (not assert, so the
# guard survives `python -O`) if an invalid step count ever produces a non-strictly-decreasing schedule.
if t.numel() >= 2 and not bool((t[1:] < t[:-1]).all()):
raise ValueError(
f"PiD student schedule for num_steps={num_steps} is not strictly decreasing (got {t.tolist()}); "
"the schedule has only 4 transitions, so num_steps must be between 1 and 4."
)
return t
def _velocity_to_x0(x_t: Tensor, net_output: Tensor, t: Tensor, *, pid_memory_optimization: bool = False) -> Tensor:
"""Convert the network's velocity prediction back to x0 at time *t*.
The optimized branch is a genuine precision reduction, not just a cheaper spelling, so it is worth
being explicit about what it buys. Measured on an RTX 4090 (B=1, 3xHxW, ``x_t`` fp32 / ``net_output``
bf16), transient peak for this call alone:
====== ========== ============== ==============
size fp64 (dflt) fused fp64 fused fp32
====== ========== ============== ==============
1024px 72 MiB 72 MiB 24 MiB
2048px 288 MiB 288 MiB 96 MiBView on GitHub (pinned to 0b6a024f2f)
Solutions
- Set num_steps to a value between 1 and 4 for the PiD decoder
- Clamp steps = min(steps, 4) in the calling pipeline/UI before decode
- Use a different sampler/model if more steps are required
Example fix
// before decode(image, num_steps=user_steps) # user_steps may be 20 // after decode(image, num_steps=max(1, min(user_steps, 4)))
Defensive patterns
Strategy: validation
Validate before calling
if not 1 <= num_steps <= 4:
raise ValueError(f"PiD decoder supports 1-4 steps, got {num_steps}") Try / catch
try:
out = decode(x, num_steps=n)
except ValueError as e:
if "strictly decreasing" in str(e):
out = decode(x, num_steps=min(n, 4))
else:
raise Prevention
- Clamp steps to 4 in UI/config
- Document the step cap
- Test rejection under python -O
When it happens
Trigger: Calling decode (which calls _get_t_list) with num_steps greater than 4, or any num_steps that yields a non-strictly-decreasing schedule.
Common situations: Exposing a generic 'steps' UI/config field to users who set 8/16/20 as with ordinary diffusion samplers, or piping a shared sampler config across models with different step caps.
Related errors
- Unsupported model source: '{url}'
- ed_hidden_size {self.ed_hidden_size} must be divisible by ed
- Text embedding y must be [B, L, D]
- PiD decoder backbone {backbone!r} is not supported. Expected
- Streaming Wan VAE decode does not support spatial tiling.
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/5e1cea203bab83fc.
Report an issue: GitHub.