microsoft/qlib · error · NotImplementedError

loss {} is not supported!

Error message

loss {} is not supported!

What it means

DNNModelPytorch's constructor validates the loss parameter against {'mse','binary'} and raises NotImplementedError('loss {} is not supported!') otherwise. The choice also selects the scorer used for logging: mean_squared_error for 'mse' and roc_auc_score for 'binary' (so 'binary' requires 0/1 labels and probability-style model output).

Source

Thrown at qlib/contrib/model/pytorch_nn.py:128

            f"\nearly_stop_rounds : {early_stop_rounds}"
            f"\neval_steps : {eval_steps}"
            f"\noptimizer : {optimizer}"
            f"\nloss_type : {loss}"
            f"\nseed : {seed}"
            f"\ndevice : {self.device}"
            f"\nuse_GPU : {self.use_gpu}"
            f"\nweight_decay : {weight_decay}"
            f"\nenable data parall : {self.data_parall}"
            f"\npt_model_uri: {pt_model_uri}"
            f"\npt_model_kwargs: {pt_model_kwargs}"
        )

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

        if loss not in {"mse", "binary"}:
            raise NotImplementedError("loss {} is not supported!".format(loss))
        self._scorer = mean_squared_error if loss == "mse" else roc_auc_score

        if init_model is None:
            self.dnn_model = init_instance_by_config({"class": pt_model_uri, "kwargs": pt_model_kwargs})

            if self.data_parall:
                self.dnn_model = DataParallel(self.dnn_model).to(self.device)
        else:
            self.dnn_model = init_model

        self.logger.info("model:\n{:}".format(self.dnn_model))
        self.logger.info("model size: {:.4f} MB".format(count_parameters(self.dnn_model)))

        if optimizer.lower() == "adam":
            self.train_optimizer = optim.Adam(self.dnn_model.parameters(), lr=self.lr, weight_decay=self.weight_decay)
        elif optimizer.lower() == "gd":
            self.train_optimizer = optim.SGD(self.dnn_model.parameters(), lr=self.lr, weight_decay=self.weight_decay)
        else:

View on GitHub (pinned to 79633dd950)

Solutions

  1. Use loss='mse' for regression or loss='binary' for binary classification/AUC scoring.
  2. For other losses, subclass DNNModelPytorch and override __init__ (skip/extend the check) and the train/loss logic as needed.
  3. Ensure labels match: 'binary' feeds roc_auc_score, which requires both classes present and labels in {0,1}.

Example fix

# before
model = DNNModelPytorch(loss="crossentropy", ...)  # NotImplementedError

# after
model = DNNModelPytorch(loss="binary", ...)  # binary classification
# or regression:
model = DNNModelPytorch(loss="mse", ...)
Defensive patterns

Strategy: validation

Validate before calling

assert loss in {"mse", "binary"}, "DNNModelPytorch supports only 'mse' and 'binary'"
model = DNNModelPytorch(loss=loss, ...)

Type guard

def is_supported_dnn_loss(name: str) -> bool:
    return name in {"mse", "binary"}

Try / catch

try:
    model = DNNModelPytorch(loss=loss, ...)
except NotImplementedError as e:
    raise ValueError(f"{e} — use 'mse' (regression) or 'binary' (AUC-scored classification)") from e

Prevention

When it happens

Trigger: Instantiating DNNModelPytorch(loss=...) in qlib/contrib/model/pytorch_nn.py with a value outside {'mse','binary'} — e.g. 'mae', 'crossentropy', 'bce'. Raised in __init__, before the pt model is built.

Common situations: Trying to add new losses by string; classification setups passing 'cross_entropy' instead of 'binary'; regression users passing 'l2' instead of 'mse'.

Related errors


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