{"record":{"id":"39c61f0a6b748a09","repo":"microsoft/qlib","slug":"unknown-loss-s-39c61f","errorCode":null,"errorMessage":"unknown loss `%s`","messagePattern":"unknown loss `(.+?)`","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/contrib/model/pytorch_transformer.py","lineNumber":94,"sourceCode":"\r\n        self.fitted = False\r\n        self.model.to(self.device)\r\n\r\n    @property\r\n    def use_gpu(self):\r\n        return self.device != torch.device(\"cpu\")\r\n\r\n    def mse(self, pred, label):\r\n        loss = (pred.float() - label.float()) ** 2\r\n        return torch.mean(loss)\r\n\r\n    def loss_fn(self, pred, label):\r\n        mask = ~torch.isnan(label)\r\n\r\n        if self.loss == \"mse\":\r\n            return self.mse(pred[mask], label[mask])\r\n\r\n        raise ValueError(\"unknown loss `%s`\" % self.loss)\r\n\r\n    def metric_fn(self, pred, label):\r\n        mask = torch.isfinite(label)\r\n\r\n        if self.metric in (\"\", \"loss\"):\r\n            return -self.loss_fn(pred[mask], label[mask])\r\n\r\n        raise ValueError(\"unknown metric `%s`\" % self.metric)\r\n\r\n    def train_epoch(self, x_train, y_train):\r\n        x_train_values = x_train.values\r\n        y_train_values = np.squeeze(y_train.values)\r\n\r\n        self.model.train()\r\n\r\n        indices = np.arange(len(x_train_values))\r\n        np.random.shuffle(indices)\r\n\r","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/pytorch_transformer.py#L76-L112","documentation":"Thrown by TransformerModel.loss_fn. Only loss='mse' is implemented (computed on the non-NaN label mask); every other value of the `loss` hyperparameter reaches the terminal ValueError on the first training or validation batch.","triggerScenarios":"TransformerModel(..., loss='mae'|'huber'|'MSE') then fit(); train_epoch immediately calls loss_fn and raises.","commonSituations":"Assuming uppercase 'MSE' matches (it does not — comparison is exact lowercase); porting loss names from other frameworks or qlib models.","solutions":["Set loss='mse' exactly (lowercase) in the TransformerModel config.","For custom losses, subclass TransformerModel and extend loss_fn, preserving the ~torch.isnan(label) mask."],"exampleFix":"# before\nmodel = TransformerModel(..., loss=\"MSE\")\n\n# after\nmodel = TransformerModel(..., loss=\"mse\")","handlingStrategy":"validation","validationCode":"assert model_kwargs.get(\"loss\", \"mse\") == \"mse\", \"TransformerModel supports only loss='mse'\"","typeGuard":null,"tryCatchPattern":"try:\n    model.fit(dataset, evals_result)\nexcept ValueError as e:\n    if \"unknown loss\" in str(e):\n        model_kwargs[\"loss\"] = \"mse\"\n        model = TransformerModel(**model_kwargs)\n        model.fit(dataset, evals_result)\n    else:\n        raise","preventionTips":["Lowercase-normalize loss/metric strings when loading yaml configs.","Keep loss vocabulary per-model, not global."],"tags":["qlib","pytorch","transformer","loss-function","hyperparameter"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}