microsoft/qlib · error · NotImplementedError

optimizer {} is not supported!

Error message

optimizer {} is not supported!

What it means

Thrown in TransformerTSModel's fit setup when constructing the training optimizer. The `optimizer` hyperparameter accepts only 'adam' and 'gd' (case-insensitive), both with weight_decay=reg; any other string raises NotImplementedError before training begins.

Source

Thrown at qlib/contrib/model/pytorch_transformer_ts.py:73

        self.optimizer = optimizer.lower()
        self.loss = loss
        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("Naive 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' or optimizer='gd' in the TransformerTSModel config.
  2. Remember 'gd' means plain SGD in this codebase.
  3. Subclass TransformerTSModel to wire in another torch.optim optimizer if you need one.

Example fix

# before
model = TransformerTSModel(..., optimizer="adamw")

# after
model = TransformerTSModel(..., optimizer="adam")
Defensive patterns

Strategy: validation

Validate before calling

optimizer = model_kwargs.get("optimizer", "adam")
assert optimizer.lower() in ("adam", "gd"), f"TransformerTSModel optimizer must be 'adam' or 'gd', got {optimizer!r}"

Try / catch

try:
    model.fit(ds, valid)
except NotImplementedError as e:
    if "optimizer" in str(e):
        model_kwargs["optimizer"] = "adam"
        model = TransformerTSModel(**model_kwargs)
        model.fit(ds, valid)
    else:
        raise

Prevention

When it happens

Trigger: TransformerTSModel(..., optimizer='sgd'|'adamw'|...) then fit(); the if/elif chain falls through to the raise during model init inside fit.

Common situations: Reusing the non-ts Transformer config verbatim but editing the optimizer name to one unsupported here; 'sgd' vs 'gd' naming confusion; typos.

Related errors


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