hankcs/HanLP · error · ValueError
The last dimension of the input shape must be equal to outpu
Error message
The last dimension of the input shape must be equal to output shape. Use a linear layer if needed.
What it means
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'.
Source
Thrown at hanlp/layers/crf/crf_layer_tf.py:73
def get_config(self):
config = {
'output_dim': self.output_dim,
'supports_masking': self.supports_masking,
'transitions': tf.keras.backend.eval(self.transitions)
}
base_config = super(CRF, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
def build(self, input_shape):
assert len(input_shape) == 3
f_shape = tf.TensorShape(input_shape)
input_spec = tf.keras.layers.InputSpec(min_ndim=3, axes={-1: f_shape[-1]})
if f_shape[-1] is None:
raise ValueError('The last dimension of the inputs to `CRF` '
'should be defined. Found `None`.')
if f_shape[-1] != self.output_dim:
raise ValueError('The last dimension of the input shape must be equal to output'
' shape. Use a linear layer if needed.')
self.input_spec = input_spec
self.transitions = self.add_weight(name='transitions',
shape=[self.output_dim, self.output_dim],
initializer='glorot_uniform',
trainable=True)
self.built = True
def compute_mask(self, inputs, mask=None):
# Just pass the received mask from previous layer, to the next layer or
# manipulate it if this layer changes the shape of the input
return mask
# pylint: disable=arguments-differ
def call(self, inputs, sequence_lengths=None, mask=None, training=None, **kwargs):
sequences = tf.convert_to_tensor(inputs, dtype=self.dtype)
if sequence_lengths is not None:
assert len(sequence_lengths.shape) == 2View on GitHub (pinned to ddb1299bdd)
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
Example fix
# before x = encoder(inputs) # (B, T, 768) out = CRF(5)(x) # error: 768 != 5 # after x = tf.keras.layers.Dense(5)(x) # (B, T, 5) out = CRF(5)(x)
Defensive patterns
Strategy: validation
Validate before calling
assert inputs.shape[-1] == num_tags, f'{inputs.shape[-1]} != {num_tags}; add Dense({num_tags})' Type guard
def dims_match(x: 'tf.Tensor', crf) -> bool:
return int(x.shape[-1]) == crf.output_dim Prevention
- Always end the encoder with Dense(num_tags) before CRF
- Set CRF units equal to tag count, not hidden size
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- The last dimension of the inputs to `CRF` should be defined.
- `attn_output` should be of size {(bsz, self.num_heads, tgt_l
- the first two dimensions of emissions and tags must match, g
- the first two dimensions of emissions and mask must match, g
- mask of the first timestep must all be on
AI-assisted analysis of hankcs/HanLP@ddb1299bdd (2026-08-27).
Data as JSON: /api/errors/483023b2d24d76a8.
Report an issue: GitHub.