hankcs/HanLP · error · ValueError

invalid reduction: {reduction}

Error message

invalid reduction: {reduction}

What it means

CRF.forward (used for compute_loss) reduces the total log-likelihood according to `reduction`, which must be one of 'none' (per-sequence), 'sum', 'mean' (batch mean), or 'token_mean' (mean per real token using the mask). Any other string raises ValueError.

Source

Thrown at hanlp/layers/crf/crf.py:111

                ``(seq_length, batch_size, num_tags)`` if ``batch_first`` is ``False``,
                ``(batch_size, seq_length, num_tags)`` otherwise.
            tags (`~torch.LongTensor`): Sequence of tags tensor of size
                ``(seq_length, batch_size)`` if ``batch_first`` is ``False``,
                ``(batch_size, seq_length)`` otherwise.
            mask (`~torch.ByteTensor`): Mask tensor of size ``(seq_length, batch_size)``
                if ``batch_first`` is ``False``, ``(batch_size, seq_length)`` otherwise.
            reduction: Specifies  the reduction to apply to the output:
                ``none|sum|mean|token_mean``. ``none``: no reduction will be applied.
                ``sum``: the output will be summed over batches. ``mean``: the output will be
                averaged over batches. ``token_mean``: the output will be averaged over tokens.

        Returns:
            `~torch.Tensor`: The log likelihood. This will have size ``(batch_size,)`` if
            reduction is ``none``, ``()`` otherwise.
        """
        self._validate(emissions, tags=tags, mask=mask)
        if reduction not in ('none', 'sum', 'mean', 'token_mean'):
            raise ValueError(f'invalid reduction: {reduction}')
        if mask is None:
            mask = torch.ones_like(tags, dtype=torch.uint8)

        if self.batch_first:
            emissions = emissions.transpose(0, 1)
            tags = tags.transpose(0, 1)
            mask = mask.transpose(0, 1)

        # shape: (batch_size,)
        numerator = self._compute_score(emissions, tags, mask)
        # shape: (batch_size,)
        denominator = self._compute_normalizer(emissions, mask)
        # shape: (batch_size,)
        llh = numerator - denominator

        if reduction == 'none':
            return llh
        if reduction == 'sum':

View on GitHub (pinned to ddb1299bdd)

Solutions

  1. Use 'none', 'sum', 'mean', or 'token_mean'
  2. For per-token normalization with padding, 'token_mean' is what you want (not a custom 'token' string)

Example fix

# before
loss = crf(emissions, tags, mask, reduction='batch')
# after
loss = crf(emissions, tags, mask, reduction='token_mean')
Defensive patterns

Strategy: validation

Validate before calling

assert reduction in ('none', 'sum', 'mean', 'token_mean'), f'bad reduction {reduction!r}'

Prevention

When it happens

Trigger: Calling crf(emissions, tags, mask, reduction=...) with an unsupported value like 'batch_mean', 'avg', or None; often from custom training loops choosing their own normalization.

Common situations: Writing a custom criterion around the CRF; copying reduction names from other loss APIs (e.g. 'mean'/'sum' from CrossEntropyLoss are fine but extras like 'batch' are not).

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of hankcs/HanLP@ddb1299bdd (2026-08-27). Data as JSON: /api/errors/83004253627a8499. Report an issue: GitHub.