{"record":{"id":"41e995eb2fd2a4b0","repo":"microsoft/qlib","slug":"unknown-loss-s-41e995","errorCode":null,"errorMessage":"unknown loss `%s`","messagePattern":"unknown loss `(.+?)`","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/contrib/model/pytorch_tabnet.py","lineNumber":372,"sourceCode":"                loss = self.pretrain_loss_fn(label, f, S_mask)\n            losses.append(loss.item())\n\n        return np.mean(losses)\n\n    def pretrain_loss_fn(self, f_hat, f, S):\n        \"\"\"\n        Pretrain loss function defined in the original paper, read \"Tabular self-supervised learning\" in https://arxiv.org/pdf/1908.07442.pdf\n        \"\"\"\n        down_mean = torch.mean(f, dim=0)\n        down = torch.sqrt(torch.sum(torch.square(f - down_mean), dim=0))\n        up = (f_hat - f) * S\n        return torch.sum(torch.square(up / down))\n\n    def loss_fn(self, pred, label):\n        mask = ~torch.isnan(label)\n        if self.loss == \"mse\":\n            return self.mse(pred[mask], label[mask])\n        raise ValueError(\"unknown loss `%s`\" % self.loss)\n\n    def metric_fn(self, pred, label):\n        mask = torch.isfinite(label)\n        if self.metric in (\"\", \"loss\"):\n            return -self.loss_fn(pred[mask], label[mask])\n        raise ValueError(\"unknown metric `%s`\" % self.metric)\n\n    def mse(self, pred, label):\n        loss = (pred - label) ** 2\n        return torch.mean(loss)\n\n\nclass FinetuneModel(nn.Module):\n    \"\"\"\n    FinuetuneModel for adding a layer by the end\n    \"\"\"\n\n    def __init__(self, input_dim, output_dim, trained_model):","sourceCodeStart":354,"sourceCodeEnd":390,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/pytorch_tabnet.py#L354-L390","documentation":"Raised by TabNet model loss_fn in qlib/contrib/model/pytorch_tabnet.py:372 when self.loss is not 'mse'. TabNet's supervised loss supports only masked MSE (labels that are NaN are excluded via mask); the pretrain loss (the paper's self-supervised objective) is separate and not selected through this kwarg. Any other loss string raises ValueError on first use.","triggerScenarios":"Setting loss to anything but 'mse' in TabNet kwargs and calling fit(); triggered during train/test epoch loss computation. Note metric ('', 'loss') also calls loss_fn.","commonSituations":"Copying loss names from the original pytorch-tabnet library (e.g. its classification losses) into qlib kwargs; typos in YAML.","solutions":["Set loss: 'mse' (the only supported supervised loss).","Subclass the qlib TabNet model and override loss_fn() for custom supervised losses; keep the NaN mask."],"exampleFix":"# before\nkwargs:\n  loss: binary_crossentropy\n\n# after\nkwargs:\n  loss: mse","handlingStrategy":"validation","validationCode":"assert config.get(\"loss\", \"mse\") == \"mse\", \"qlib TabNet supports only loss='mse' (pretrain loss is separate)\"","typeGuard":"def is_supported_tabnet_loss(loss: str) -> bool:\n    return loss == \"mse\"","tryCatchPattern":"try:\n    model.fit(dataset)\nexcept ValueError as e:\n    if \"unknown loss\" in str(e):\n        raise ValueError(\"TabNet's supervised loss is 'mse' only; override loss_fn() for custom losses\") from e\n    raise","preventionTips":["Do not port loss names from the upstream pytorch-tabnet library into qlib kwargs.","Keep supervised loss and pretrain objective conceptually separate when configuring."],"tags":["qlib","pytorch","loss-function","config","tabnet"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}