{"record":{"id":"519ab9f83913cdb9","repo":"microsoft/qlib","slug":"unknown-metric-s-519ab9","errorCode":null,"errorMessage":"unknown metric `%s`","messagePattern":"unknown metric `(.+?)`","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/contrib/model/pytorch_general_nn.py","lineNumber":172,"sourceCode":"\n    def loss_fn(self, pred, label, weight=None):\n        mask = ~torch.isnan(label)\n\n        if weight is None:\n            weight = torch.ones_like(label)\n\n        if self.loss == \"mse\":\n            return self.mse(pred[mask], label[mask].view(-1, 1), weight[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 in (\"\", \"loss\"):\n            return self.loss_fn(pred[mask], label[mask])\n\n        raise ValueError(\"unknown metric `%s`\" % self.metric)\n\n    def _get_fl(self, data: torch.Tensor):\n        \"\"\"\n        get feature and label from data\n        - Handle the different data shape of time series and tabular data\n\n        Parameters\n        ----------\n        data : torch.Tensor\n            input data which maybe 3 dimension or 2 dimension\n            - 3dim: [batch_size, time_step, feature_dim]\n            - 2dim: [batch_size, feature_dim]\n\n        Returns\n        -------\n        Tuple[torch.Tensor, torch.Tensor]\n        \"\"\"\n        if data.dim() == 3:","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/pytorch_general_nn.py#L154-L190","documentation":"Raised by DNNModelPytorch.metric_fn when the `metric` hyper-parameter is neither \"\" nor \"loss\". The metric used for early-stopping/validation scoring is hard-coded: only the (negated implicit) training loss is available via those two aliases. Any other string (\"ic\", \"auc\", ...) falls through to the raise during validation of the first epoch.","triggerScenarios":"Constructing DNNModelPytorch(metric=\"ic\") and calling fit() with a validation segment; metric_fn is called per validation batch and raises on the first one. Note also the mask here uses torch.isfinite on the label and then passes pred[mask], label[mask] into loss_fn, so shape mismatches can occur before this raise if labels contain non-finite values.","commonSituations":"Porting a workflow config from GRU/LSTM models where metric=\"ic\" is valid; assuming the generic-sounding `metric` arg accepts standard qlib metrics like \"ic\" or \"icir\"; leaving metric unset in one model but copying \"ic\" from a benchmark config.","solutions":["Set metric to \"\" or \"loss\" in the model parameters (validation score becomes the loss).","If you need \"ic\" or another metric, subclass DNNModelPytorch and extend metric_fn with your branch before the raise.","Verify the YAML key is under the correct model handler so the value actually reaches the constructor."],"exampleFix":"# before\nDNNModelPytorch(metric=\"ic\", ...)  # ValueError: unknown metric `ic`\n\n# after\nDNNModelPytorch(metric=\"loss\", ...)","handlingStrategy":"validation","validationCode":"allowed = {\"\", \"loss\"}\nassert params.get(\"metric\", \"\") in allowed, f\"metric must be one of {allowed} for DNNModelPytorch\"","typeGuard":"def is_supported_metric(metric: str) -> bool:\n    return isinstance(metric, str) and metric in {\"\", \"loss\"}","tryCatchPattern":"try:\n    model.fit(dataset)\nexcept ValueError as e:\n    if \"unknown metric\" in str(e):\n        # fall back to loss-based scoring\n        params[\"metric\"] = \"loss\"\n        model = DNNModelPytorch(**params)\n        model.fit(dataset)\n    else:\n        raise","preventionTips":["Validate metric names per model class before launching long training jobs.","Prefer leaving metric unset (defaults to loss scoring) unless you know the model supports a named metric."],"tags":["pytorch","qlib","configuration","metrics"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}