{"record":{"id":"eb0a0b1829618d8c","repo":"hankcs/HanLP","slug":"activation-must-be-callable-type","errorCode":null,"errorMessage":"activation must be callable: type={}","messagePattern":"activation must be callable: type=(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"hanlp/components/srl/span_rank/layer.py","lineNumber":119,"sourceCode":"\n    def forward(self, x):\n        if self.training:\n            return torch.mul(x, self.drop_mask.to(x.device))\n        else:  # eval\n            return x * (1.0 - self.dropout_rate)\n\n\nclass NonLinear(nn.Module):\n    def __init__(self, input_size, hidden_size, activation=None):\n        super(NonLinear, self).__init__()\n        self.input_size = input_size\n        self.hidden_size = hidden_size\n        self.linear = nn.Linear(in_features=input_size, out_features=hidden_size)\n        if activation is None:\n            self._activate = lambda x: x\n        else:\n            if not callable(activation):\n                raise ValueError(\"activation must be callable: type={}\".format(type(activation)))\n            self._activate = activation\n\n        self.reset_parameters()\n\n    def forward(self, x):\n        y = self.linear(x)\n        return self._activate(y)\n\n    def reset_parameters(self):\n        nn.init.xavier_uniform_(self.linear.weight)\n        nn.init.zeros_(self.linear.bias)\n\n\nclass Biaffine(nn.Module):\n    def __init__(self, in1_features, in2_features, out_features,\n                 bias=(True, True)):\n        super(Biaffine, self).__init__()\n        self.in1_features = in1_features","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/hankcs/HanLP/blob/ddb1299bddff079e447af52ec12549c50636bfa8/hanlp/components/srl/span_rank/layer.py#L101-L137","documentation":"The span-ranking SRL layer accepts an `activation` argument that must be callable (a function/nn.Module like torch.sigmoid or F.relu). Passing a string such as 'relu' or 'tanh' (a common convention in other libraries like sklearn/transformers) raises ValueError. None is allowed and means identity.","triggerScenarios":"Constructing the SRL span-rank layer (or a config-driven model build) with activation='relu' or activation=\"tanh\" instead of a callable; also passing a class (torch.nn.ReLU) without instantiating when the code expects an instance/function.","commonSituations":"Config files where activation is a string; porting hyperparameters from Keras/sklearn-style configs into HanLP training scripts.","solutions":["Pass a callable: activation=torch.relu (or F.relu, torch.sigmoid); import torch first","For identity, pass activation=None","If config uses strings, map them: {'relu': torch.relu, 'tanh': torch.tanh}.get(cfg)"],"exampleFix":"# before\nlayer = Scorer(input_size=100, hidden_size=50, activation='relu')\n# after\nimport torch\nlayer = Scorer(input_size=100, hidden_size=50, activation=torch.relu)","handlingStrategy":"type-guard","validationCode":"import torch\nACT = {'relu': torch.relu, 'tanh': torch.tanh, 'sigmoid': torch.sigmoid, 'identity': None}\nactivation = ACT[activation] if isinstance(activation, str) else activation\nassert activation is None or callable(activation)","typeGuard":"def is_callable_activation(a) -> bool:\n    return a is None or callable(a)","tryCatchPattern":null,"preventionTips":["Map config strings to callables at load time","Add unit tests for layer construction from config"],"tags":["python","pytorch","activation-function","argument-validation"],"backgroundTag":"invalid-argument-type","analyzedSha":"ddb1299bddff079e447af52ec12549c50636bfa8","analyzedAt":"2026-08-27T03:36:54.287Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}