{"record":{"id":"483023b2d24d76a8","repo":"hankcs/HanLP","slug":"the-last-dimension-of-the-input-shape-must-be-equa","errorCode":null,"errorMessage":"The last dimension of the input shape must be equal to output shape. Use a linear layer if needed.","messagePattern":"The last dimension of the input shape must be equal to output shape\\. Use a linear layer if needed\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"hanlp/layers/crf/crf_layer_tf.py","lineNumber":73,"sourceCode":"    def get_config(self):\n        config = {\n            'output_dim': self.output_dim,\n            'supports_masking': self.supports_masking,\n            'transitions': tf.keras.backend.eval(self.transitions)\n        }\n        base_config = super(CRF, self).get_config()\n        return dict(list(base_config.items()) + list(config.items()))\n\n    def build(self, input_shape):\n        assert len(input_shape) == 3\n        f_shape = tf.TensorShape(input_shape)\n        input_spec = tf.keras.layers.InputSpec(min_ndim=3, axes={-1: f_shape[-1]})\n\n        if f_shape[-1] is None:\n            raise ValueError('The last dimension of the inputs to `CRF` '\n                             'should be defined. Found `None`.')\n        if f_shape[-1] != self.output_dim:\n            raise ValueError('The last dimension of the input shape must be equal to output'\n                             ' shape. Use a linear layer if needed.')\n        self.input_spec = input_spec\n        self.transitions = self.add_weight(name='transitions',\n                                           shape=[self.output_dim, self.output_dim],\n                                           initializer='glorot_uniform',\n                                           trainable=True)\n        self.built = True\n\n    def compute_mask(self, inputs, mask=None):\n        # Just pass the received mask from previous layer, to the next layer or\n        # manipulate it if this layer changes the shape of the input\n        return mask\n\n    # pylint: disable=arguments-differ\n    def call(self, inputs, sequence_lengths=None, mask=None, training=None, **kwargs):\n        sequences = tf.convert_to_tensor(inputs, dtype=self.dtype)\n        if sequence_lengths is not None:\n            assert len(sequence_lengths.shape) == 2","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/hankcs/HanLP/blob/ddb1299bddff079e447af52ec12549c50636bfa8/hanlp/layers/crf/crf_layer_tf.py#L55-L91","documentation":"The TF CRF layer requires input features whose last dimension equals output_dim (the number of tags), because the transitions matrix and emission scores are defined over exactly that axis. Unlike a wrapped CRF loss module, this layer does not project inputs; if your encoder outputs a different hidden size, you must add a projection yourself, hence the message 'Use a linear layer if needed'.","triggerScenarios":"Instantiating CRF(output_dim=num_tags) and feeding encoder outputs of hidden_size != num_tags (e.g. 768-dim BERT features straight into a CRF with 5 tags).","commonSituations":"Forgetting a Dense(num_tags) projection between transformer/LSTM encoder and the CRF layer; copying keras-contrib examples where the previous layer happened to match tag count.","solutions":["Add tf.keras.layers.Dense(num_tags) immediately before the CRF layer and set CRF's output_dim to num_tags","Or set the CRF output_dim equal to the encoder output dim only if that genuinely equals the tag count"],"exampleFix":"# before\nx = encoder(inputs)            # (B, T, 768)\nout = CRF(5)(x)                # error: 768 != 5\n# after\nx = tf.keras.layers.Dense(5)(x)  # (B, T, 5)\nout = CRF(5)(x)","handlingStrategy":"validation","validationCode":"assert inputs.shape[-1] == num_tags, f'{inputs.shape[-1]} != {num_tags}; add Dense({num_tags})'","typeGuard":"def dims_match(x: 'tf.Tensor', crf) -> bool:\n    return int(x.shape[-1]) == crf.output_dim","tryCatchPattern":null,"preventionTips":["Always end the encoder with Dense(num_tags) before CRF","Set CRF units equal to tag count, not hidden size"],"tags":["hanlp","tensorflow","keras","crf","dimension-mismatch"],"backgroundTag":"layer-dimension-mismatch","analyzedSha":"ddb1299bddff079e447af52ec12549c50636bfa8","analyzedAt":"2026-08-27T03:36:54.287Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}