Stability-AI/generative-models · error · NotImplementedError

Unknown optimizer_idx {optimizer_idx}

Error message

Unknown optimizer_idx {optimizer_idx}

What it means

The discriminator loss module's forward computes either the generator loss (optimizer_idx 0) or discriminator loss (optimizer_idx 1); any other value hits the else and raises this NotImplementedError. Like error 6, it means the training loop is invoking the loss with an unexpected optimizer index.

Source

Thrown at sgm/modules/autoencoding/losses/discriminator_loss.py:292

            return loss, log
        elif optimizer_idx == 1:
            # second pass for discriminator update
            logits_real = self.discriminator(inputs.contiguous().detach())
            logits_fake = self.discriminator(reconstructions.contiguous().detach())

            if global_step >= self.discriminator_iter_start or not self.training:
                d_loss = self.disc_factor * self.disc_loss(logits_real, logits_fake)
            else:
                d_loss = torch.tensor(0.0, requires_grad=True)

            log = {
                f"{split}/loss/disc": d_loss.clone().detach().mean(),
                f"{split}/logits/real": logits_real.detach().mean(),
                f"{split}/logits/fake": logits_fake.detach().mean(),
            }
            return d_loss, log
        else:
            raise NotImplementedError(f"Unknown optimizer_idx {optimizer_idx}")

    def get_nll_loss(
        self,
        rec_loss: torch.Tensor,
        weights: Optional[Union[float, torch.Tensor]] = None,
    ) -> Tuple[torch.Tensor, torch.Tensor]:
        nll_loss = rec_loss / torch.exp(self.logvar) + self.logvar
        weighted_nll_loss = nll_loss
        if weights is not None:
            weighted_nll_loss = weights * nll_loss
        weighted_nll_loss = torch.sum(weighted_nll_loss) / weighted_nll_loss.shape[0]
        nll_loss = torch.sum(nll_loss) / nll_loss.shape[0]

        return nll_loss, weighted_nll_loss

View on GitHub (pinned to e8cd657656)

Solutions

  1. Pass optimizer_idx 0 (generator) or 1 (discriminator) only when calling the loss.
  2. Ensure the Lightning module's configure_optimizers returns exactly two optimizers when using this dual-objective loss.
  3. If manual optimization is used, loop over exactly [0, 1] and pass the matching index into each forward call.

Example fix

// before
for idx in range(3):
    loss, log = disc_loss(inputs, reconstructions, split="train", optimizer_idx=idx)
// after
for idx in (0, 1):
    loss, log = disc_loss(inputs, reconstructions, split="train", optimizer_idx=idx)
Defensive patterns

Strategy: validation

Validate before calling

# before each loss call in manual optimization
assert optimizer_idx in (0, 1), f"optimizer_idx must be 0 (gen) or 1 (disc), got {optimizer_idx}"

Try / catch

try:
    loss, log = disc_loss(x, rec, split="train", optimizer_idx=idx)
except NotImplementedError as e:
    if "Unknown optimizer_idx" in str(e):
        raise RuntimeError("Loss supports optimizer_idx 0/1 only") from e

Prevention

When it happens

Trigger: Calling LPIPSWithDiscriminator(..., optimizer_idx=2) directly, or training a Lightning module whose loop passes an optimizer_idx outside {0,1} into this loss's forward.

Common situations: Older-Lightning-style manual optimization loops passing optimizer_idx; custom training scripts iterating over more than two optimizers; copied training_step code with wrong indexing.

Related errors


AI-assisted analysis of Stability-AI/generative-models@e8cd657656 (2026-08-29). Data as JSON: /api/errors/242d976ae0f51c0d. Report an issue: GitHub.