{"record":{"id":"4f7e4bb906485f31","repo":"microsoft/qlib","slug":"unknown-loss-s-4f7e4b","errorCode":null,"errorMessage":"unknown loss `%s`","messagePattern":"unknown loss `(.+?)`","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/contrib/model/pytorch_hist.py","lineNumber":160,"sourceCode":"\n        self.fitted = False\n        self.HIST_model.to(self.device)\n\n    @property\n    def use_gpu(self):\n        return self.device != torch.device(\"cpu\")\n\n    def mse(self, pred, label):\n        loss = (pred - label) ** 2\n        return torch.mean(loss)\n\n    def loss_fn(self, pred, label):\n        mask = ~torch.isnan(label)\n\n        if self.loss == \"mse\":\n            return self.mse(pred[mask], label[mask])\n\n        raise ValueError(\"unknown loss `%s`\" % self.loss)\n\n    def metric_fn(self, pred, label):\n        mask = torch.isfinite(label)\n\n        if self.metric == \"ic\":\n            x = pred[mask]\n            y = label[mask]\n\n            vx = x - torch.mean(x)\n            vy = y - torch.mean(y)\n            return torch.sum(vx * vy) / (torch.sqrt(torch.sum(vx**2)) * torch.sqrt(torch.sum(vy**2)))\n\n        if self.metric == (\"\", \"loss\"):\n            return -self.loss_fn(pred[mask], label[mask])\n\n        raise ValueError(\"unknown metric `%s`\" % self.metric)\n\n    def get_daily_inter(self, df, shuffle=False):","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/pytorch_hist.py#L142-L178","documentation":"Raised by HIST.loss_fn when self.loss is not \"mse\". HIST implements plain MSE only; any other loss name reaches the raise on the first training batch. The raise can also surface via metric_fn when the metric falls into the loss branch.","triggerScenarios":"HIST(loss=\"mae\"/\"huber\"/\"cross_entropy\", ...) then fit() on stock daily-batch data; fires at train_epoch -> loss_fn on the first daily batch.","commonSituations":"Reusing hyper-parameter configs across different qlib contrib models; custom-loss experiments attempted via config only.","solutions":["Set loss=\"mse\".","Subclass HIST and override loss_fn to add branches before the raise for a custom loss."],"exampleFix":"# before\nHIST(loss=\"mae\", ...)\n\n# after\nHIST(loss=\"mse\", ...)","handlingStrategy":"validation","validationCode":"assert params[\"loss\"] == \"mse\", \"HIST supports only loss='mse'\"","typeGuard":"def is_supported_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(\"HIST only supports loss='mse'\") from e\n    raise","preventionTips":["Default to 'mse' for HIST; subclass to extend.","Validate loss names per model class in experiment configs."],"tags":["pytorch","qlib","loss-function","configuration"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}