microsoft/qlib · error · NotImplementedError

optimizer {} is not supported!

Error message

optimizer {} is not supported!

What it means

LOCALTransformerModel's constructor only accepts two optimizers: 'adam' (torch.optim.Adam with lr and weight_decay=reg) and 'gd' (torch.optim.SGD with lr and weight_decay=reg). Any other optimizer string raises NotImplementedError('optimizer {} is not supported!') at __init__ time, before any training happens.

Source

Thrown at qlib/contrib/model/pytorch_localformer_ts.py:76

        self.n_jobs = n_jobs
        self.device = torch.device("cuda:%d" % GPU if torch.cuda.is_available() and GPU >= 0 else "cpu")
        self.seed = seed
        self.logger = get_module_logger("TransformerModel")
        self.logger.info(
            "Improved Transformer:" "\nbatch_size : {}" "\ndevice : {}".format(self.batch_size, self.device)
        )

        if self.seed is not None:
            np.random.seed(self.seed)
            torch.manual_seed(self.seed)

        self.model = Transformer(d_feat, d_model, nhead, num_layers, dropout, self.device)
        if optimizer.lower() == "adam":
            self.train_optimizer = optim.Adam(self.model.parameters(), lr=self.lr, weight_decay=self.reg)
        elif optimizer.lower() == "gd":
            self.train_optimizer = optim.SGD(self.model.parameters(), lr=self.lr, weight_decay=self.reg)
        else:
            raise NotImplementedError("optimizer {} is not supported!".format(optimizer))

        self.fitted = False
        self.model.to(self.device)

    @property
    def use_gpu(self):
        return self.device != torch.device("cpu")

    def mse(self, pred, label):
        loss = (pred.float() - label.float()) ** 2
        return torch.mean(loss)

    def loss_fn(self, pred, label):
        mask = ~torch.isnan(label)

        if self.loss == "mse":
            return self.mse(pred[mask], label[mask])

View on GitHub (pinned to 79633dd950)

Solutions

  1. Set optimizer='adam' (recommended default) or optimizer='gd' for plain SGD in the model kwargs.
  2. If you truly need another optimizer, subclass LOCALTransformerModel, override __init__ after super() and reassign self.train_optimizer with your torch.optim optimizer over self.model.parameters().
  3. Check for typos/case: matching is via optimizer.lower(), so 'Adam' works but 'adamw' does not.

Example fix

# before
model = LOCALTransformerModel(..., optimizer="sgd")  # NotImplementedError

# after
model = LOCALTransformerModel(..., optimizer="adam")
# or plain SGD:
model = LOCALTransformerModel(..., optimizer="gd")
Defensive patterns

Strategy: validation

Validate before calling

SUPPORTED = {"adam", "gd"}
opt = "adam"  # your desired optimizer
assert opt.lower() in SUPPORTED, f"optimizer must be one of {SUPPORTED}, got {opt!r}"
model = LOCALTransformerModel(..., optimizer=opt)

Type guard

def is_supported_optimizer(name: str) -> bool:
    return isinstance(name, str) and name.lower() in {"adam", "gd"}

Try / catch

try:
    model = LOCALTransformerModel(..., optimizer=opt)
except NotImplementedError as e:
    raise ValueError(f"Bad config: {e}; supported optimizers are 'adam' and 'gd'") from e

Prevention

When it happens

Trigger: Passing optimizer='sgd', 'adamw', 'rmsprop', or any non-'adam'/'gd' string (case-insensitive) to LOCALTransformerModel(...) in qlib/contrib/model/pytorch_localformer_ts.py.

Common situations: Copying a config written for another qlib model that supports more optimizers; trying to use a modern optimizer like AdamW; a typo such as 'ada' or 'SDG'; assuming 'sgd' is the name for gradient descent instead of 'gd'.

Related errors


AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15). Data as JSON: /api/errors/318fea013921abc1. Report an issue: GitHub.