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 MiB

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Set num_steps to a value between 1 and 4 for the PiD decoder
  2. Clamp steps = min(steps, 4) in the calling pipeline/UI before decode
  3. 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

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


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/5e1cea203bab83fc. Report an issue: GitHub.