{"record":{"id":"a764a3c5d3a5f752","repo":"microsoft/qlib","slug":"mode-is-not-supported","errorCode":null,"errorMessage":"mode {} is not supported!","messagePattern":"mode (.+?) is not supported!","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"qlib/contrib/model/pytorch_tcts.py","lineNumber":132,"sourceCode":"                loss,\n                GPU,\n                self.use_gpu,\n                seed,\n            )\n        )\n\n    def loss_fn(self, pred, label, weight):\n        if self.mode == \"hard\":\n            loc = torch.argmax(weight, 1)\n            loss = (pred - label[np.arange(weight.shape[0]), loc]) ** 2\n            return torch.mean(loss)\n\n        elif self.mode == \"soft\":\n            loss = (pred - label.transpose(0, 1)) ** 2\n            return torch.mean(loss * weight.transpose(0, 1))\n\n        else:\n            raise NotImplementedError(\"mode {} is not supported!\".format(self.mode))\n\n    def train_epoch(self, x_train, y_train, x_valid, y_valid):\n        x_train_values = x_train.values\n        y_train_values = np.squeeze(y_train.values)\n\n        indices = np.arange(len(x_train_values))\n        np.random.shuffle(indices)\n\n        task_embedding = torch.zeros([self.batch_size, self.output_dim])\n        task_embedding[:, self.target_label] = 1\n        task_embedding = task_embedding.to(self.device)\n\n        init_fore_model = copy.deepcopy(self.fore_model)\n        for p in init_fore_model.parameters():\n            p.requires_grad = False\n\n        self.fore_model.train()\n        self.weight_model.train()","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/pytorch_tcts.py#L114-L150","documentation":"Thrown by TCTSModel.loss_fn when scoring predictions against labels. The `mode` hyperparameter selects how the label-weighting head is applied: 'hard' (argmax over per-step weights) or 'soft' (weighted average over future steps). Any other value falls to the else-branch NotImplementedError at fit time.","triggerScenarios":"Constructing TCTSModel (trend-cascade time-series model) with mode='mixed', mode='median', or any string besides 'hard'/'soft', then calling fit(); train_epoch's loss_fn call raises on the first batch.","commonSituations":"Copying hyperparameters from the TRA paper/baselines where other mode names appear; typo like 'Hard'; assumption that a default exists — check that mode was actually passed, since an unset/None value also fails.","solutions":["Set mode='hard' or mode='soft' in the TCTSModel config — the only supported branches.","Pick 'hard' to mimic selecting the single most-likely horizon step, 'soft' for probability-weighted aggregation across steps.","For a custom weighting scheme, subclass TCTSModel and extend loss_fn with a new branch before the else."],"exampleFix":"# before\nmodel = TCTSModel(..., mode=\"weighted\")\n\n# after\nmodel = TCTSModel(..., mode=\"soft\")","handlingStrategy":"validation","validationCode":"assert model_kwargs.get(\"mode\") in (\"hard\", \"soft\"), f\"TCTSModel mode must be 'hard' or 'soft', got {model_kwargs.get('mode')!r}\"","typeGuard":null,"tryCatchPattern":"try:\n    model.fit(dataset)\nexcept NotImplementedError as e:\n    if \"mode\" in str(e):\n        model_kwargs[\"mode\"] = \"soft\"\n        model = TCTSModel(**model_kwargs)\n        model.fit(dataset)\n    else:\n        raise","preventionTips":["Treat mode as a required enum for TCTSModel — always set it explicitly in configs.","Validate TCTS hyperparameters in a config schema before starting the long fit loop."],"tags":["qlib","pytorch","tcts","hyperparameter","loss-function"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}