{"record":{"id":"9078e69c1a86e050","repo":"microsoft/qlib","slug":"model-is-not-fitted-yet-9078e6","errorCode":null,"errorMessage":"model is not fitted yet!","messagePattern":"model is not fitted yet!","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/contrib/model/pytorch_tcn_ts.py","lineNumber":268,"sourceCode":"                stop_steps = 0\n                best_epoch = step\n                best_param = copy.deepcopy(self.TCN_model.state_dict())\n            else:\n                stop_steps += 1\n                if stop_steps >= self.early_stop:\n                    self.logger.info(\"early stop\")\n                    break\n\n        self.logger.info(\"best score: %.6lf @ %d\" % (best_score, best_epoch))\n        self.TCN_model.load_state_dict(best_param)\n        torch.save(best_param, save_path)\n\n        if self.use_gpu:\n            torch.cuda.empty_cache()\n\n    def predict(self, dataset):\n        if not self.fitted:\n            raise ValueError(\"model is not fitted yet!\")\n\n        dl_test = dataset.prepare(\"test\", col_set=[\"feature\", \"label\"], data_key=DataHandlerLP.DK_I)\n        dl_test.config(fillna_type=\"ffill+bfill\")\n        test_loader = DataLoader(dl_test, batch_size=self.batch_size, num_workers=self.n_jobs)\n        self.TCN_model.eval()\n        preds = []\n\n        for data in test_loader:\n            feature = data[:, :, 0:-1].to(self.device)\n\n            with torch.no_grad():\n                pred = self.TCN_model(feature.float()).detach().cpu().numpy()\n\n            preds.append(pred)\n\n        return pd.Series(np.concatenate(preds), index=dl_test.get_index())\n\n","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/pytorch_tcn_ts.py#L250-L286","documentation":"Thrown by TCNTSModel.predict when its `fitted` flag is False. The flag flips to True only after a fully successful fit() (including best-weight reload and checkpoint save), so prediction is blocked until the time-series TCN has actually been trained in this object's lifetime.","triggerScenarios":"Calling model.predict(dataset) on a TCNTSModel whose fit() was never invoked or raised before completion (e.g. during a failed retrain loop triggered by lowest_valid_performance).","commonSituations":"Long benchmark scripts where fit silently fails on one seed and the driver still calls predict; interactive sessions re-running only the predict cell; unpickling a model object saved before fit finished.","solutions":["Run fit(ds, valid) to completion before predict(ds).","Wrap fit/predict sequencing so predict is skipped when fit raises; fix the underlying fit failure.","To reuse trained weights across processes, load the saved state dict into the model AND set model.fitted = True explicitly."],"exampleFix":"# before\nmodel = TCNTSModel(**kwargs)\nmodel.predict(dataset)  # ValueError\n\n# after\nmodel = TCNTSModel(**kwargs)\nmodel.fit(dataset, valid)\nmodel.predict(dataset)","handlingStrategy":"validation","validationCode":"if not getattr(model, \"fitted\", False):\n    raise RuntimeError(\"TCNTSModel not fitted — run fit(ds, valid) before predict(ds)\")","typeGuard":"def tcnts_ready(model) -> bool:\n    return getattr(model, \"fitted\", False) and hasattr(model, \"TCCN_model\" if False else \"TCN_model\")","tryCatchPattern":"try:\n    preds = model.predict(ds)\nexcept ValueError as e:\n    if \"not fitted\" in str(e):\n        model.fit(ds, valid)\n        preds = model.predict(ds)\n    else:\n        raise","preventionTips":["In retrain-loop code, only proceed to predict when fit returned without raising.","Save/load fitted checkpoints and set fitted=True on restore."],"tags":["qlib","pytorch","tcn","lifecycle","state"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}