{"record":{"id":"f4dd7e97a7a88dea","repo":"microsoft/qlib","slug":"optimizer-is-not-supported-f4dd7e","errorCode":null,"errorMessage":"optimizer {} is not supported!","messagePattern":"optimizer (.+?) is not supported!","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"qlib/contrib/model/pytorch_gru.py","lineNumber":127,"sourceCode":"        if self.seed is not None:\n            np.random.seed(self.seed)\n            torch.manual_seed(self.seed)\n\n        self.gru_model = GRUModel(\n            d_feat=self.d_feat,\n            hidden_size=self.hidden_size,\n            num_layers=self.num_layers,\n            dropout=self.dropout,\n        )\n        self.logger.info(\"model:\\n{:}\".format(self.gru_model))\n        self.logger.info(\"model size: {:.4f} MB\".format(count_parameters(self.gru_model)))\n\n        if optimizer.lower() == \"adam\":\n            self.train_optimizer = optim.Adam(self.gru_model.parameters(), lr=self.lr)\n        elif optimizer.lower() == \"gd\":\n            self.train_optimizer = optim.SGD(self.gru_model.parameters(), lr=self.lr)\n        else:\n            raise NotImplementedError(\"optimizer {} is not supported!\".format(optimizer))\n\n        self.fitted = False\n        self.gru_model.to(self.device)\n\n    @property\n    def use_gpu(self):\n        return self.device != torch.device(\"cpu\")\n\n    def mse(self, pred, label):\n        loss = (pred - label) ** 2\n        return torch.mean(loss)\n\n    def loss_fn(self, pred, label):\n        mask = ~torch.isnan(label)\n\n        if self.loss == \"mse\":\n            return self.mse(pred[mask], label[mask])\n","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/contrib/model/pytorch_gru.py#L109-L145","documentation":"Raised in GRUModel.__init__ when the `optimizer` hyper-parameter is not \"adam\" or \"gd\" (case-insensitive). Only Adam and plain SGD are wired up for the GRU model; the check happens at construction time, so a bad value fails fast before any training.","triggerScenarios":"Constructing GRUModel(optimizer=\"sgd\", ...) — note the accepted alias for SGD is \"gd\", not \"sgd\" — or optimizer=\"adamw\"/\"rmsprop\"/\"adagrad\". Lower-cased comparison means \"Adam\" works but \"adam_w\" does not.","commonSituations":"Using the conventional name \"sgd\" instead of qlib's \"gd\"; copying optimizer names from other frameworks or other qlib contrib models that support more optimizers; typos like \"adm\".","solutions":["Use optimizer=\"adam\" or optimizer=\"gd\" (the latter maps to torch.optim.SGD without momentum).","For a custom optimizer, subclass GRUModel and set self.train_optimizer yourself after calling super().__init__ with a supported placeholder value.","If you need momentum/weight decay, prefer subclassing with optim.SGD(momentum=...) rather than a new name."],"exampleFix":"# before\nGRUModel(optimizer=\"sgd\", ...)  # NotImplementedError\n\n# after\nGRUModel(optimizer=\"gd\", ...)   # plain SGD","handlingStrategy":"validation","validationCode":"assert params[\"optimizer\"].lower() in {\"adam\", \"gd\"}, \"GRUModel supports only 'adam' and 'gd'\"","typeGuard":"def is_supported_optimizer(name: str) -> bool:\n    return isinstance(name, str) and name.lower() in {\"adam\", \"gd\"}","tryCatchPattern":"try:\n    model = GRUModel(**params)\nexcept NotImplementedError as e:\n    if \"optimizer\" in str(e):\n        params[\"optimizer\"] = \"adam\"\n        model = GRUModel(**params)\n    else:\n        raise","preventionTips":["Remember qlib's SGD alias is 'gd', not 'sgd'.","Validate optimizer names against each model class before running workflows."],"tags":["pytorch","qlib","optimizer","configuration"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}