microsoft/qlib · error · ValueError

unknown loss `%s`

Error message

unknown loss `%s`

What it means

Raised by DNNModelPytorch.loss_fn when the configured `loss` hyper-parameter is anything other than the literal string "mse". The class only implements a weighted MSE loss; the dispatch is a simple if-chain, so any other value (e.g. "mae", "cross_entropy", "MSE" with different case) reaches the terminal raise. This fires at the first training batch, not at construction, so config errors surface late.

Source

Thrown at qlib/contrib/model/pytorch_general_nn.py:164

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

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

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

        if weight is None:
            weight = torch.ones_like(label)

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

        raise ValueError("unknown loss `%s`" % self.loss)

    def metric_fn(self, pred, label):
        mask = torch.isfinite(label)

        if self.metric in ("", "loss"):
            return self.loss_fn(pred[mask], label[mask])

        raise ValueError("unknown metric `%s`" % self.metric)

    def _get_fl(self, data: torch.Tensor):
        """
        get feature and label from data
        - Handle the different data shape of time series and tabular data

        Parameters
        ----------
        data : torch.Tensor
            input data which maybe 3 dimension or 2 dimension

View on GitHub (pinned to 79633dd950)

Solutions

  1. Set loss="mse" in the model init args / workflow YAML handler parameters (this is the only supported value).
  2. If you need another loss, subclass DNNModelPytorch, override loss_fn (and mse) to add your branch before the raise.
  3. Check for stray whitespace or case differences in the YAML value (e.g. loss: ' mse ' will not match).

Example fix

# before
model = DNNModelPytorch(loss="mae", lr=0.001, ...)  # ValueError at first batch

# after
model = DNNModelPytorch(loss="mse", lr=0.001, ...)
Defensive patterns

Strategy: validation

Validate before calling

from qlib.contrib.model.pytorch_general_nn import DNNModelPytorch
allowed = {"mse"}
assert params["loss"] in allowed, f"loss must be one of {allowed}, got {params['loss']!r}"

Type guard

def is_supported_loss(loss: str) -> bool:
    return isinstance(loss, str) and loss in {"mse"}

Try / catch

try:
    model.fit(dataset)
except ValueError as e:
    if "unknown loss" in str(e):
        raise ValueError(f"DNNModelPytorch only supports loss='mse'; got {model.loss!r}") from e
    raise

Prevention

When it happens

Trigger: Calling model.fit(dataset) on a DNNModelPytorch whose init args include loss="mse"-anything-else, e.g. loss="mae" or loss="MSE". The error is thrown from train_epoch -> loss_fn on the first forward pass, and from metric_fn when metric is "" or "loss" since that path delegates to loss_fn.

Common situations: Copying a workflow YAML from another qlib model (e.g. ALSTM or TabNet) that supports other loss names; passing a capitalized "MSE"; upgrading qlib versions where loss names changed; hand-rolling a custom loss name without subclassing.

Related errors


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