{"record":{"id":"c34ba8dc8419748c","repo":"keras-team/keras","slug":"training-and-validation-subsets-have-different-num","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"keras/src/legacy/preprocessing/image.py","lineNumber":594,"sourceCode":"                f\"Found: x.shape = {np.asarray(x).shape}, \"\n                f\"sample_weight.shape = {np.asarray(sample_weight).shape}\"\n            )\n        if subset is not None:\n            if subset not in {\"training\", \"validation\"}:\n                raise ValueError(\n                    f\"Invalid subset name: {subset}\"\n                    '; expected \"training\" or \"validation\".'\n                )\n            split_idx = int(len(x) * image_data_generator._validation_split)\n\n            if (\n                y is not None\n                and not ignore_class_split\n                and not np.array_equal(\n                    np.unique(y[:split_idx]), np.unique(y[split_idx:])\n                )\n            ):\n                raise ValueError(\n                    \"Training and validation subsets \"\n                    \"have different number of classes after \"\n                    \"the split. If your numpy arrays are \"\n                    \"sorted by the label, you might want \"\n                    \"to shuffle them.\"\n                )\n\n            if subset == \"validation\":\n                x = x[:split_idx]\n                x_misc = [np.asarray(xx[:split_idx]) for xx in x_misc]\n                if y is not None:\n                    y = y[:split_idx]\n            else:\n                x = x[split_idx:]\n                x_misc = [np.asarray(xx[split_idx:]) for xx in x_misc]\n                if y is not None:\n                    y = y[split_idx:]\n","sourceCodeStart":576,"sourceCodeEnd":612,"githubUrl":"https://github.com/keras-team/keras/blob/7a34a03db60bf60042242d6a556fc3be119046a5/keras/src/legacy/preprocessing/image.py#L576-L612","documentation":"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.","triggerScenarios":"Using validation_split with NumpyArrayIterator on arrays sorted by class label, so np.unique(y[:split]) != np.unique(y[split:]).","commonSituations":"Dataset assembled class-by-class then split without shuffling; rare classes landing entirely in the validation slice.","solutions":["Shuffle x and y jointly with the same permutation before flow()","Or pass ignore_class_split=True if missing classes in the split are acceptable","Use train_test_split(..., stratify=y) to keep class balance"],"exampleFix":"// before\nit_train = gen.flow(x, y, subset='training')  # x sorted by label\n// after\nidx = np.random.permutation(len(x))\nx, y = x[idx], y[idx]\nit_train = gen.flow(x, y, subset='training')\n","handlingStrategy":"validation","validationCode":"import numpy as np\nperm = np.random.RandomState(42).permutation(len(x))\nx, y = np.asarray(x)[perm], np.asarray(y)[perm]\nassert set(np.unique(y[:int(len(y)*split)])) == set(np.unique(y))","typeGuard":null,"tryCatchPattern":"try: gen.flow(x, y, subset='training')\nexcept ValueError as e: if 'shuffle' in str(e): shuffle jointly and retry once","preventionTips":["Always shuffle before validation_split","Prefer stratified splits for rare classes"],"tags":["keras","train-validation-split","class-imbalance"],"backgroundTag":"train-test-data-leak-or-mismatch","analyzedSha":"7a34a03db60bf60042242d6a556fc3be119046a5","analyzedAt":"2026-08-25T21:25:25.994Z","schemaVersion":2},"datasetVersion":"2026-08-26T02:17:13.382Z"}