keras-team/keras · error · ValueError

Training and validation subsets have different number of cla

Error message

Training and validation subsets have different number of classes after the split. If your numpy arrays are sorted by the label, you might want to shuffle them.

What it means

After the validation split, the training and validation slices must contain the same set of classes (unless ignore_class_split=True). Sorted-by-label data puts all of one class in one slice, making one-hot/label encoding impossible for the missing class.

Source

Thrown at keras/src/legacy/preprocessing/image.py:594

                f"Found: x.shape = {np.asarray(x).shape}, "
                f"sample_weight.shape = {np.asarray(sample_weight).shape}"
            )
        if subset is not None:
            if subset not in {"training", "validation"}:
                raise ValueError(
                    f"Invalid subset name: {subset}"
                    '; expected "training" or "validation".'
                )
            split_idx = int(len(x) * image_data_generator._validation_split)

            if (
                y is not None
                and not ignore_class_split
                and not np.array_equal(
                    np.unique(y[:split_idx]), np.unique(y[split_idx:])
                )
            ):
                raise ValueError(
                    "Training and validation subsets "
                    "have different number of classes after "
                    "the split. If your numpy arrays are "
                    "sorted by the label, you might want "
                    "to shuffle them."
                )

            if subset == "validation":
                x = x[:split_idx]
                x_misc = [np.asarray(xx[:split_idx]) for xx in x_misc]
                if y is not None:
                    y = y[:split_idx]
            else:
                x = x[split_idx:]
                x_misc = [np.asarray(xx[split_idx:]) for xx in x_misc]
                if y is not None:
                    y = y[split_idx:]

View on GitHub (pinned to 7a34a03db6)

Solutions

  1. Shuffle x and y jointly with the same permutation before flow()
  2. Or pass ignore_class_split=True if missing classes in the split are acceptable
  3. Use train_test_split(..., stratify=y) to keep class balance

Example fix

// before
it_train = gen.flow(x, y, subset='training')  # x sorted by label
// after
idx = np.random.permutation(len(x))
x, y = x[idx], y[idx]
it_train = gen.flow(x, y, subset='training')
Defensive patterns

Strategy: validation

Validate before calling

import numpy as np
perm = np.random.RandomState(42).permutation(len(x))
x, y = np.asarray(x)[perm], np.asarray(y)[perm]
assert set(np.unique(y[:int(len(y)*split)])) == set(np.unique(y))

Try / catch

try: gen.flow(x, y, subset='training')
except ValueError as e: if 'shuffle' in str(e): shuffle jointly and retry once

Prevention

When it happens

Trigger: Using validation_split with NumpyArrayIterator on arrays sorted by class label, so np.unique(y[:split]) != np.unique(y[split:]).

Common situations: Dataset assembled class-by-class then split without shuffling; rare classes landing entirely in the validation slice.

Related errors


AI-assisted analysis of keras-team/keras@7a34a03db6 (2026-08-25). Data as JSON: /api/errors/c34ba8dc8419748c. Report an issue: GitHub.