hankcs/HanLP · error · ValueError
The last dimension of the inputs to `CRF` should be defined.
Error message
The last dimension of the inputs to `CRF` should be defined. Found `None`.
What it means
Thrown by the TensorFlow CRF layer's build() when the input tensor's last dimension is undefined (None). Keras needs a concrete feature dimension to create the transitions weight matrix of shape (output_dim, output_dim), so an undefined channel count cannot be built. This is the standard check carried over from keras-contrib's CRF implementation.
Source
Thrown at hanlp/layers/crf/crf_layer_tf.py:70
self.supports_masking = False
sequence_lengths = None
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):View on GitHub (pinned to ddb1299bdd)
Solutions
- Define a fixed last dimension in the input, e.g. Input(shape=(None, hidden_size))
- Insert a Dense(hidden_size) layer before CRF so the last dim is concrete
- If calling build manually, pass an input_shape tuple whose final element is an int
Example fix
# before inputs = tf.keras.layers.Input(shape=(None, None)) crf = CRFLayer(units) # build fails # after inputs = tf.keras.layers.Input(shape=(None, hidden_size)) crf = CRFLayer(hidden_size)
Defensive patterns
Strategy: validation
Validate before calling
assert inputs.shape[-1] is not None and isinstance(inputs.shape[-1], int)
Type guard
def has_defined_last_dim(shape) -> bool:
return len(shape) == 3 and isinstance(shape[-1], (int,)) and shape[-1] > 0 Prevention
- Always give Input a concrete feature dimension
- Add a Dense projection before CRF
- Pin Keras version to keep shape inference stable
When it happens
Trigger: Feeding inputs with dynamic/undefined last dimension, e.g. an Input(shape=(None, None)), a layer upstream that produces unknown channel size, or input_shape passed without a defined final axis when calling the layer directly.
Common situations: Using tf.keras Input with variable feature dimension; building a model where the embedding/feature dimension is inferred as None; upgrading Keras versions where shape inference behavior changed.
Related errors
- The last dimension of the input shape must be equal to outpu
- `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/32da211cd22bd16d.
Report an issue: GitHub.