{"record":{"id":"39a9d33bf6df58ef","repo":"microsoft/qlib","slug":"model-is-not-fitted-yet-39a9d3","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_transformer.py","lineNumber":217,"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: DatasetH, segment: Union[Text, slice] = \"test\"):\r\n        if not self.fitted:\r\n            raise ValueError(\"model is not fitted yet!\")\r\n\r\n        x_test = dataset.prepare(segment, col_set=\"feature\", data_key=DataHandlerLP.DK_I)\r\n        index = x_test.index\r\n        self.model.eval()\r\n        x_values = x_test.values\r\n        sample_num = x_values.shape[0]\r\n        preds = []\r\n\r\n        for begin in range(sample_num)[:: self.batch_size]:\r\n            if sample_num - begin < self.batch_size:\r\n                end = sample_num\r\n            else:\r\n                end = begin + self.batch_size\r\n\r\n            x_batch = torch.from_numpy(x_values[begin:end]).float().to(self.device)\r\n\r\n            with torch.no_grad():\r\n                pred = self.model(x_batch).detach().cpu().numpy()\r","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/pytorch_transformer.py#L199-L235","documentation":"Thrown by TransformerModel.predict when the `fitted` flag is False. fitted is set only after a successful fit loop (best weights reloaded, checkpoint saved), so prediction on an untrained or failed-to-train Transformer model is blocked.","triggerScenarios":"TransformerModel.predict(dataset) without a prior successful fit(dataset, evals_result); or after a fit that errored mid-training (OOM, NaN loss, early crash) leaving fitted=False.","commonSituations":"Rolling-refit scripts where one fold's fit fails but predict still runs; notebook re-execution of only the predict cell; expecting a saved .bin checkpoint alone to make a fresh model instance predict-ready.","solutions":["Call model.fit(dataset, evals_result) successfully first, then predict(dataset, segment='test').","Guard evaluation stages on fit success (try/except around fit, skip predict on failure) and fix the root fit error.","To restore a trained model: torch.load(save_path) → model.load_state_dict(...) → set model.fitted = True before predict."],"exampleFix":"# before\nmodel = TransformerModel(d_feat=6)\nmodel.predict(dataset)  # ValueError\n\n# after\nmodel = TransformerModel(d_feat=6)\nmodel.fit(dataset, evals_result)\nmodel.predict(dataset)","handlingStrategy":"validation","validationCode":"if not getattr(model, \"fitted\", False):\n    raise RuntimeError(\"TransformerModel not fitted — call fit(dataset, evals_result) first\")","typeGuard":"def transformer_ready(model) -> bool:\n    return getattr(model, \"fitted\", False) and getattr(model, \"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, evals_result)\n        preds = model.predict(dataset)\n    else:\n        raise","preventionTips":["Gate rolling-refit evaluation on fit success per fold.","On checkpoint restore: load_state_dict(torch.load(path)) and set fitted=True."],"tags":["qlib","pytorch","transformer","lifecycle","state"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}