huggingface/pytorch-image-models · error · RuntimeError

API has changed, `state_steps` argument must contain a list

Error message

API has changed, `state_steps` argument must contain a list of singleton tensors

What it means

The functional timm.optim.adamw.adamw() API requires state_steps to be a list of singleton torch tensors (one per parameter), matching PyTorch's modern functional optimizer API. Passing floats or ints (the pre-1.5 API) triggers this guard.

Source

Thrown at timm/optim/adamw.py:205

        foreach: Optional[bool] = None,
        capturable: bool = False,
        *,
        amsgrad: bool,
        beta1: float,
        beta2: float,
        lr: float,
        weight_decay: float,
        eps: float,
        caution: bool,
        maximize: bool,
        max_lr: Optional[float],
) -> None:
    r"""Functional API that performs AdamW algorithm computation.
      See AdamWLegacy class for details.
    """

    if not all(isinstance(t, torch.Tensor) for t in state_steps):
        raise RuntimeError(
            'API has changed, `state_steps` argument must contain a list of' +
            ' singleton tensors')

    if foreach is None:
        try:
            # cannot do foreach if this overload doesn't exist when caution enabled
            foreach = not caution or 'Scalar' in torch.ops.aten._foreach_maximum_.overloads()
            # Match native PyTorch: tensor lr without capturable mode is supported by the single-tensor path.
            if foreach and torch.is_tensor(lr) and not capturable:
                foreach = False
        except Exception:
            foreach = False

    if foreach and not torch.jit.is_scripting():
        func = _multi_tensor_adamw
    else:
        func = _single_tensor_adamw

View on GitHub (pinned to 9a5261e31b)

Solutions

  1. Convert each step count to a tensor: state_steps = [torch.tensor(float(step)) for step in state_steps]
  2. Or let the AdamW class manage state and call step() instead of the functional API
  3. If migrating from torch.optim.adamw, reuse the same tensor-based state_steps convention

Example fix

# before
adamw(params, grads, exp_avgs, exp_avg_sqs, max_exp_avg_sqs, state_steps=[0], lr=1e-3)
# after
adamw(params, grads, exp_avgs, exp_avg_sqs, max_exp_avg_sqs, state_steps=[torch.tensor(0.)], lr=1e-3)
Defensive patterns

Strategy: validation

Validate before calling

assert all(isinstance(t, torch.Tensor) and t.numel() == 1 for t in state_steps)

Type guard

def valid_state_steps(state_steps: list) -> bool:
    return all(isinstance(t, torch.Tensor) and t.numel() == 1 for t in state_steps)

Prevention

When it happens

Trigger: Calling timm.optim.adamw.adamw(..., state_steps=[0, 1, 2]) with Python numbers instead of state_steps=[torch.tensor(0.), ...]. It is also raised if any element of the list is not a torch.Tensor.

Common situations: Copying old tutorial code that used the pre-2020 functional Adam API, or hand-rolling a training loop that tracks step counts as ints and forwards them to the functional API.

Related errors


AI-assisted analysis of huggingface/pytorch-image-models@9a5261e31b (2026-08-27). Data as JSON: /api/errors/be67de4130c1ed0b. Report an issue: GitHub.