TensorFlow
BatchEncoding
dataset creation
machine learning
data preprocessing

Merge multiple BatchEncoding or create tensorflow dataset from list of BatchEncoding objects

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When you tokenize text with Hugging Face, the output is often a BatchEncoding, which behaves like a dictionary containing fields such as input_ids and attention_mask. Trouble starts when you collect many single examples and then try to train a TensorFlow model, because TensorFlow expects consistent shapes and aligned labels. The clean solution is to normalize the encodings first, then convert them into a tf.data.Dataset.

Understand What a BatchEncoding Contains

A BatchEncoding is essentially a mapping of feature names to tokenized values. For transformer text models, the most common keys are input_ids, attention_mask, and sometimes token_type_ids.

python
1from transformers import AutoTokenizer
2
3tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")
4
5encoding = tokenizer(
6    "Transformers are easier to train with clean inputs.",
7    padding="max_length",
8    truncation=True,
9    max_length=8,
10)
11
12print(encoding.keys())
13print(encoding["input_ids"])

Before you merge anything, verify that every example has the same set of keys and the same sequence length. If those assumptions are false, dataset creation will fail later in a less obvious place.

The Best Option Is Usually Batch Tokenization

If you still have raw text, do not build a dataset by merging many single-example encodings. Tokenize the full list at once instead.

python
1import tensorflow as tf
2from transformers import AutoTokenizer
3
4texts = [
5    "Short sentence.",
6    "Another training example.",
7    "A third sample for the dataset.",
8]
9labels = [0, 1, 0]
10
11tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")
12batched = tokenizer(
13    texts,
14    padding=True,
15    truncation=True,
16    return_tensors="np",
17)
18
19dataset = tf.data.Dataset.from_tensor_slices((dict(batched), labels))
20dataset = dataset.batch(2).prefetch(tf.data.AUTOTUNE)

This is simpler, faster, and less error-prone than tokenizing each sample separately and trying to reconstruct the batch later.

Merging a List of BatchEncoding Objects

Sometimes you really do start with a list of separate BatchEncoding objects, for example after custom preprocessing. In that case, build one merged dictionary where each key maps to a stacked array.

python
1import numpy as np
2from transformers import AutoTokenizer
3
4tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")
5
6samples = [
7    tokenizer("first text", padding="max_length", truncation=True, max_length=6),
8    tokenizer("second text", padding="max_length", truncation=True, max_length=6),
9]
10
11keys = samples[0].keys()
12
13merged = {
14    key: np.stack([np.array(sample[key]) for sample in samples], axis=0)
15    for key in keys
16}
17
18print(merged["input_ids"].shape)

The important rule is consistency. Every sample must expose the same keys, and every value under a given key must have the same length if you want to use from_tensor_slices.

Build the TensorFlow Dataset

After merging, dataset creation is straightforward.

python
1import tensorflow as tf
2import numpy as np
3
4labels = np.array([0, 1], dtype=np.int32)
5
6dataset = tf.data.Dataset.from_tensor_slices((merged, labels))
7dataset = dataset.shuffle(len(labels)).batch(2).prefetch(tf.data.AUTOTUNE)
8
9for features, y in dataset.take(1):
10    print(features["input_ids"].shape)
11    print(y.numpy())

This pattern works well with model.fit, since Keras accepts a dictionary of named input tensors plus a label tensor.

Handle Missing Keys and Variable Lengths

Not every tokenizer returns every field. Some models need token_type_ids; others do not. If your samples are mixed, normalize them before stacking.

python
for sample in samples:
    if "token_type_ids" not in sample:
        sample["token_type_ids"] = [0] * len(sample["input_ids"])

Variable-length sequences are another common issue. If you did not pad during tokenization, your arrays may be ragged and np.stack will fail. The usual fix is to pad during tokenization:

python
1encoding = tokenizer(
2    "example text",
3    padding="max_length",
4    truncation=True,
5    max_length=32,
6)

If you intentionally want variable-length sequences, then you need a ragged or padded batching strategy rather than plain stacking.

Add Lightweight Validation

A short validation step saves time before training starts.

python
1def validate(encodings, labels):
2    if not encodings:
3        raise ValueError("No encodings provided.")
4
5    first_keys = set(encodings[0].keys())
6    for index, item in enumerate(encodings):
7        if set(item.keys()) != first_keys:
8            raise ValueError(f"Encoding {index} has inconsistent keys.")
9
10    if len(encodings) != len(labels):
11        raise ValueError("Feature and label counts do not match.")

This kind of preflight check is worth adding when data comes from multiple preprocessing steps.

Common Pitfalls

The biggest mistake is merging samples with inconsistent sequence lengths. np.stack requires matching shapes, so one unpadded example can break the whole batch.

Another issue is assuming every model uses the same keys. Some tokenizers produce token_type_ids, others do not. If your model expects a field that is missing from some samples, training will fail later.

It is also easy to forget label alignment. A perfectly valid feature dictionary is still unusable if the labels do not match the number of encoded examples.

Finally, avoid overcomplicating the pipeline when raw texts are still available. Batch tokenization is almost always the cleaner design.

Summary

  • A BatchEncoding behaves like a dictionary of model input fields.
  • If possible, tokenize the full list of texts in one call and build the dataset directly.
  • If you already have a list of BatchEncoding objects, merge them by stacking arrays per key.
  • 'tf.data.Dataset.from_tensor_slices requires consistent shapes and aligned labels.'
  • Validate keys, lengths, and label counts before handing data to TensorFlow.

Course illustration
Course illustration

All Rights Reserved.