hankcs/HanLP · error · ValueError

DataParallel not supported when CRF is used

Error message

DataParallel not supported when CRF is used

What it means

When a tagger is configured with crf=True, build_criterion returns the model's CRF module as the loss (CRF computes its own log-likelihood). A raw CRF has shared parameters, so wrapping the model in nn.DataParallel (which replicates the module and scatters/gathers batch dimensions) breaks CRF's sequence-level computation; HanLP therefore refuses the combination.

Source

Thrown at hanlp/components/taggers/tagger.py:37

from hanlp.utils.time_util import CountdownTimer
from hanlp_common.util import reorder
from hanlp_trie import DictInterface, TrieDict
from hanlp_trie.dictionary import TupleTrieDict


class Tagger(DistillableComponent, ABC):
    def build_optimizer(self, optimizer, lr, **kwargs):
        if optimizer == 'adam':
            return optim.Adam(params=self.model.parameters(), lr=lr)
        elif optimizer == 'sgd':
            return torch.optim.SGD(self.model.parameters(), lr=lr)

    def build_criterion(self, model=None, reduction='mean', decoder=None, **kwargs):
        if self.config.get('crf', False):
            if not model:
                model = decoder or self.model
            if isinstance(model, nn.DataParallel):
                raise ValueError('DataParallel not supported when CRF is used')
                return self.model_from_config.module.crf
            return model.crf
        else:
            return nn.CrossEntropyLoss(reduction=reduction)

    def build_metric(self, **kwargs):
        return CategoricalAccuracy()

    @abstractmethod
    def feed_batch(self, batch):
        pass

    def compute_loss(self, criterion, out, y, mask):
        if self.config.get('crf', False):
            criterion: CRF = criterion
            loss = -criterion.forward(out, y, mask)
        else:
            loss = criterion(out[mask], y[mask])

View on GitHub (pinned to ddb1299bdd)

Solutions

  1. Train on a single GPU: set devices to one GPU id (e.g. devices=0 or devices=-1 depending on config) so DataParallel is not used
  2. Disable CRF (crf=False) if multi-GPU training is required — you lose sequence-level loss but can parallelize
  3. Use DistributedDataParallel-style training outside HanLP's loop only if you understand CRF gather implications

Example fix

# before (hanlp.json / training config)
{"crf": true, "devices": [0, 1]}
# after
{"crf": true, "devices": [0]}
Defensive patterns

Strategy: validation

Validate before calling

import torch.nn as nn
assert not (config.get('crf', False) and isinstance(model, nn.DataParallel)), 'CRF + DataParallel unsupported; use a single device'

Prevention

When it happens

Trigger: Training a tagger (e.g. RNN/CRF tagger) with config crf=True while running on multiple GPUs so HanLP wraps the model in nn.DataParallel, then execute_training_loop calls build_criterion and hits the check. Note: the code after the raise (return self.model_from_config.module.crf) is unreachable dead code.

Common situations: Scaling single-GPU CRF training to a multi-GPU machine with devices in config; enabling CRF for better sequence tagging accuracy then hitting multi-GPU training.

Related errors


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