Preprocessing and data collators

Hugging Face Transformers · Practical · 12 min

Efficient, correct batching is half the work of fine-tuning and a common source of shape errors.

Before training, turn text columns into model inputs. The idiom is a batched map with the tokenizer:

def tokenize(batch):
    return tok(batch["text"], truncation=True, max_length=256)
ds = ds.map(tokenize, batched=True, remove_columns=["text"])

Notice there is no padding here. Padding every example to a global maximum wastes compute. Instead, a data collator pads each batch to its own longest sequence at load time (dynamic padding):

  • DataCollatorWithPadding(tok) for classification and similar tasks.
  • DataCollatorForTokenClassification(tok) also pads labels with -100.
  • DataCollatorForLanguageModeling(tok, mlm=False) builds causal LM labels from input_ids (set mlm=True for masked LM with random masking).
  • DataCollatorForSeq2Seq(tok, model=model) for encoder-decoder models.

The label value -100 is special: PyTorch's cross-entropy (and Transformers' loss functions) ignore it, so padding positions and prompt tokens do not contribute to the loss.

Name the target column labels (or label, which collators rename) because models compute the loss when they receive labels. Remove raw string columns; the Trainer drops unused columns automatically, but explicit removal avoids surprises.

Group similar lengths together (train_sampling_strategy="group_by_length" in TrainingArguments) to reduce padding further.

Example

from datasets import Dataset
from transformers import AutoTokenizer, DataCollatorWithPadding

tok = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased")
ds = Dataset.from_dict({"text": ["short", "a much longer example sentence"],
                        "label": [0, 1]})

def tokenize(batch):
    return tok(batch["text"], truncation=True, max_length=128)

ds = ds.map(tokenize, batched=True, remove_columns=["text"])
print([len(x) for x in ds["input_ids"]])   # [3, 7]  (no padding yet)

collator = DataCollatorWithPadding(tok)
batch = collator([ds[0], ds[1]])
print(batch["input_ids"].shape)            # torch.Size([2, 7])  padded per batch
print(batch["labels"])                     # tensor([0, 1])  'label' renamed

Remember

  • Tokenize with a batched map and truncation, but do not pad there
  • Data collators pad each batch dynamically to its longest sequence
  • Label -100 is ignored by the loss (padding, prompt tokens)

Watch out for

  • Padding everything to max_length in map, which makes training far slower than dynamic padding.

Check yourself

  1. Why do token-classification collators pad labels with -100?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: huggingface.co/docs/transformers/data_collators