{"record":{"id":"f684247c7afe0b5c","repo":"microsoft/qlib","slug":"model-is-not-fitted-yet-f68424","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_tcts.py","lineNumber":353,"sourceCode":"                if stop_round >= self.early_stop:\n                    print(\"early stop\")\n                    break\n\n        print(\"best loss:\", best_loss, \"@\", best_epoch)\n        best_param = torch.load(save_path + \"_fore_model.bin\", map_location=self.device)\n        self.fore_model.load_state_dict(best_param)\n        best_param = torch.load(save_path + \"_weight_model.bin\", map_location=self.device)\n        self.weight_model.load_state_dict(best_param)\n        self.fitted = True\n\n        if self.use_gpu:\n            torch.cuda.empty_cache()\n\n        return best_loss\n\n    def predict(self, dataset):\n        if not self.fitted:\n            raise ValueError(\"model is not fitted yet!\")\n\n        x_test = dataset.prepare(\"test\", col_set=\"feature\")\n        index = x_test.index\n        self.fore_model.eval()\n        x_values = x_test.values\n        sample_num = x_values.shape[0]\n        preds = []\n\n        for begin in range(sample_num)[:: self.batch_size]:\n            if sample_num - begin < self.batch_size:\n                end = sample_num\n            else:\n                end = begin + self.batch_size\n\n            x_batch = torch.from_numpy(x_values[begin:end]).float().to(self.device)\n\n            with torch.no_grad():\n                if self.use_gpu:","sourceCodeStart":335,"sourceCodeEnd":371,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/pytorch_tcts.py#L335-L371","documentation":"Thrown by TCTSModel.predict when the model's `fitted` flag is still False. fitted becomes True only at the very end of a successful fit (after reloading best fore/weight state dicts), so this guards prediction against an untrained or incompletely trained trend-cascade model.","triggerScenarios":"Calling predict(dataset) on a TCTSModel that never ran fit(), or whose fit() aborted (empty data, unsupported optimizer, failed retrain loop vs lowest_valid_performance) before setting fitted=True.","commonSituations":"Retrain loop exhausts attempts ('Failed! Start retraining.') and the exception propagates, yet downstream code still predicts; running predict from a restored unsaved session; notebook cell reordering.","solutions":["Complete model.fit(dataset) successfully, then call model.predict(dataset).","If fit fails inside its retrain loop, lower/adjust lowest_valid_performance or fix the data so at least one run meets the bar and fitted gets set.","To serve a previously trained model, load both saved checkpoints (fore_model.bin / *_weight_model.bin), call load_state_dict, and set model.fitted = True."],"exampleFix":"# before\nmodel = TCTSModel(**kwargs)\nmodel.predict(dataset)  # ValueError\n\n# after\nmodel = TCTSModel(**kwargs)\nmodel.fit(dataset)\nmodel.predict(dataset)","handlingStrategy":"validation","validationCode":"if not getattr(model, \"fitted\", False):\n    raise RuntimeError(\"TCTSModel not fitted — run fit(dataset) before predict(dataset)\")","typeGuard":"def tcts_ready(model) -> bool:\n    return getattr(model, \"fitted\", False) and getattr(model, \"fore_model\", None) is not None","tryCatchPattern":"try:\n    preds = model.predict(dataset)\nexcept ValueError as e:\n    if \"not fitted\" in str(e):\n        model.fit(dataset)\n        preds = model.predict(dataset)\n    else:\n        raise","preventionTips":["Skip predict when the fit/retrain loop raises; log the fold as failed instead.","After loading fore/weight checkpoints manually, set model.fitted = True."],"tags":["qlib","pytorch","tcts","lifecycle","state"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}