{"record":{"id":"852818946af9b6d4","repo":"microsoft/qlib","slug":"model-is-not-fitted-yet-852818","errorCode":null,"errorMessage":"model is not fitted yet!","messagePattern":"model is not fitted yet!","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/contrib/model/pytorch_localformer_ts.py","lineNumber":205,"sourceCode":"                stop_steps = 0\r\n                best_epoch = step\r\n                best_param = copy.deepcopy(self.model.state_dict())\r\n            else:\r\n                stop_steps += 1\r\n                if stop_steps >= self.early_stop:\r\n                    self.logger.info(\"early stop\")\r\n                    break\r\n\r\n        self.logger.info(\"best score: %.6lf @ %d\" % (best_score, best_epoch))\r\n        self.model.load_state_dict(best_param)\r\n        torch.save(best_param, save_path)\r\n\r\n        if self.use_gpu:\r\n            torch.cuda.empty_cache()\r\n\r\n    def predict(self, dataset):\r\n        if not self.fitted:\r\n            raise ValueError(\"model is not fitted yet!\")\r\n\r\n        dl_test = dataset.prepare(\"test\", col_set=[\"feature\", \"label\"], data_key=DataHandlerLP.DK_I)\r\n        dl_test.config(fillna_type=\"ffill+bfill\")\r\n        test_loader = DataLoader(dl_test, batch_size=self.batch_size, num_workers=self.n_jobs)\r\n        self.model.eval()\r\n        preds = []\r\n\r\n        for data in test_loader:\r\n            feature = data[:, :, 0:-1].to(self.device)\r\n\r\n            with torch.no_grad():\r\n                pred = self.model(feature.float()).detach().cpu().numpy()\r\n\r\n            preds.append(pred)\r\n\r\n        return pd.Series(np.concatenate(preds), index=dl_test.get_index())\r\n\r\n\r","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/pytorch_localformer_ts.py#L187-L223","documentation":"The TS (time-series) LOCALTransformer variant's predict() checks self.fitted before preparing the 'test' segment. self.fitted becomes True only at the end of a successful fit(); any predict before that raises ValueError('model is not fitted yet!') without touching the dataset.","triggerScenarios":"Calling model.predict(dataset) on a LOCALTransformerTS-style model where fit() was never run, failed partway (e.g. empty data, NaN loss, OOM), or was skipped in a scripted workflow.","commonSituations":"Workflow configs where the train task failed but downstream predict/backtest tasks still executed; re-loading an unfitted pickled model; interactive notebooks jumping to evaluation.","solutions":["Run model.fit(dataset, evals_result) to completion before predict; verify it logs 'best score: ...' (the signal fit finished).","Diagnose and fix any earlier fit() failure — fitted stays False until a clean finish.","To restore a trained model: torch-saved best_param exists at save_path; recreate the model, model.model.load_state_dict(torch.load(save_path)), set model.fitted = True, then predict."],"exampleFix":"# before\nmodel = LOCALTransformerModel(...)\npreds = model.predict(dataset)  # ValueError: model is not fitted yet!\n\n# after\nmodel = LOCALTransformerModel(...)\nmodel.fit(dataset, evals_result)\npreds = model.predict(dataset)","handlingStrategy":"validation","validationCode":"if not getattr(model, \"fitted\", False):\n    raise RuntimeError(\"model not fitted; run fit() (or restore checkpoint + set fitted=True) first\")\npreds = model.predict(dataset)","typeGuard":"def is_fitted(model) -> bool:\n    return bool(getattr(model, \"fitted\", False))","tryCatchPattern":"try:\n    preds = model.predict(dataset)\nexcept ValueError as e:\n    if \"not fitted\" in str(e):\n        model.fit(dataset, evals_result)\n        preds = model.predict(dataset)\n    else:\n        raise","preventionTips":["Assert model.fitted before every predict in production code.","Treat checkpoint restore as two steps: load_state_dict AND fitted = True.","Abort workflows on fit failure so predict is never reached."],"tags":["pytorch","qlib","model-lifecycle","transformer","validation"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}