hankcs/HanLP · error · ValueError
mask of the first timestep must all be on
Error message
mask of the first timestep must all be on
What it means
HanLP's TorchCRF requires that the first timestep of every sequence is valid (mask all-on at timestep 0), because CRF scoring assumes each sequence starts at the first emission. _validate checks mask[0].all() (or mask[:,0].all() for batch_first) and rejects masks whose first step has any zeros. This is inherited from torchcrf's semantics where empty prefixes are not representable.
Source
Thrown at hanlp/layers/crf/crf.py:186
raise ValueError(
f'expected last dimension of emissions is {self.num_tags}, '
f'got {emissions.size(2)}')
if tags is not None:
if emissions.shape[:2] != tags.shape:
raise ValueError(
'the first two dimensions of emissions and tags must match, '
f'got {tuple(emissions.shape[:2])} and {tuple(tags.shape)}')
if mask is not None:
if emissions.shape[:2] != mask.shape:
raise ValueError(
'the first two dimensions of emissions and mask must match, '
f'got {tuple(emissions.shape[:2])} and {tuple(mask.shape)}')
no_empty_seq = not self.batch_first and mask[0].all()
no_empty_seq_bf = self.batch_first and mask[:, 0].all()
if not no_empty_seq and not no_empty_seq_bf:
raise ValueError('mask of the first timestep must all be on')
def _compute_score(
self, emissions: torch.Tensor, tags: torch.LongTensor,
mask: torch.ByteTensor) -> torch.Tensor:
# emissions: (seq_length, batch_size, num_tags)
# tags: (seq_length, batch_size)
# mask: (seq_length, batch_size)
assert emissions.dim() == 3 and tags.dim() == 2
assert emissions.shape[:2] == tags.shape
assert emissions.size(2) == self.num_tags
assert mask.shape == tags.shape
assert mask[0].all()
seq_length, batch_size = tags.shape
mask = mask.type_as(emissions)
# Start transition score and first emission
# shape: (batch_size,)View on GitHub (pinned to ddb1299bdd)
Solutions
- Use right-padding so each sequence's first timestep is real and mask[:,0]==1 for all batches
- Double-check mask orientation matches batch_first (mask[:,0] vs mask[0])
- Rebuild mask as arange(T) < length per sequence
Example fix
# before mask = (torch.arange(T)[None, :] >= lengths[:, None]) # inverted -> first step off # after mask = (torch.arange(T)[None, :] < lengths[:, None]).to(torch.uint8) assert mask[:, 0].all()
Defensive patterns
Strategy: validation
Validate before calling
assert (mask[:, 0] if batch_first else mask[0]).all(), 'first timestep must be unmasked'
Type guard
def first_step_on(mask: torch.Tensor, batch_first: bool) -> bool:
return bool((mask[:, 0] if batch_first else mask[0]).all()) Prevention
- Always right-pad variable-length sequences
- Never feed all-zero masks
- Sanity-check mask[:,0].sum() == batch_size in tests
When it happens
Trigger: Passing a mask where any sequence has mask[..., 0] == 0, e.g. mask built with an off-by-one roll, sorted-by-length batches misaligned, or a mask that marks pad positions starting at index 0 for shorter sequences placed after longer ones without batch_first alignment.
Common situations: Left-padding sequences instead of right-padding; constructing mask from lengths with reversed or transposed axes; feeding a mask of all zeros for some sample.
Related errors
- the first two dimensions of emissions and mask must match, g
- the first two dimensions of emissions and tags must match, g
- The `{mask_name}` should be specified for {len(self.layers)}
- DataParallel not supported when CRF is used
- invalid number of tags: {num_tags}
AI-assisted analysis of hankcs/HanLP@ddb1299bdd (2026-08-27).
Data as JSON: /api/errors/8c50bac30956313c.
Report an issue: GitHub.