keras
flow_from_directory
class imbalance
oversampling
undersampling

keras flow_from_directory over or undersample a class

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

flow_from_directory is convenient for loading image batches, but it does not have a built-in switch to oversample one class or undersample another. If your dataset is imbalanced, the usual fixes are class weights, a custom generator, or a more modern tf.data pipeline where you control sampling explicitly. The best choice depends on whether you want to rebalance at training time or physically rebalance files on disk.

What flow_from_directory Does and Does Not Do

ImageDataGenerator.flow_from_directory(...) scans subdirectories, assigns class indices, and yields batches. It can shuffle and augment, but it does not provide a class-balancing policy such as “sample minority twice as often.”

That means you cannot ask it directly to oversample class cat or undersample class dog with one argument.

Easiest First Step: Use class_weight

If the goal is better training behavior rather than equal batch composition, try class weights first. This keeps the dataset unchanged but tells Keras to penalize mistakes on minority classes more heavily.

python
1import tensorflow as tf
2from tensorflow.keras.preprocessing.image import ImageDataGenerator
3
4train_gen = ImageDataGenerator(rescale=1.0 / 255).flow_from_directory(
5    "data/train",
6    target_size=(224, 224),
7    batch_size=32,
8    class_mode="binary"
9)
10
11model = tf.keras.Sequential([
12    tf.keras.layers.Input(shape=(224, 224, 3)),
13    tf.keras.layers.Flatten(),
14    tf.keras.layers.Dense(1, activation="sigmoid")
15])
16
17model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])
18
19model.fit(
20    train_gen,
21    epochs=3,
22    class_weight={0: 1.0, 1: 4.0}
23)

This is often good enough and much simpler than custom sampling.

Oversampling Requires a Custom Input Strategy

If you truly need more minority examples per epoch, you usually move beyond plain flow_from_directory. One practical approach is to build a list of file paths yourself, duplicate minority-class entries, and feed them through a custom Sequence or tf.data.Dataset.

python
1import tensorflow as tf
2
3cat_files = tf.io.gfile.glob("data/train/cat/*.jpg")
4dog_files = tf.io.gfile.glob("data/train/dog/*.jpg")
5
6balanced_files = cat_files * 3 + dog_files
7labels = [0] * (len(cat_files) * 3) + [1] * len(dog_files)
8
9path_ds = tf.data.Dataset.from_tensor_slices((balanced_files, labels))
10path_ds = path_ds.shuffle(len(balanced_files))
11
12def load_image(path, label):
13    image = tf.io.read_file(path)
14    image = tf.image.decode_jpeg(image, channels=3)
15    image = tf.image.resize(image, [224, 224]) / 255.0
16    return image, label
17
18dataset = path_ds.map(load_image).batch(32)

This is a real oversampling strategy because minority file paths appear multiple times.

Undersampling Is Simpler but Loses Data

Undersampling means keeping fewer majority-class samples per epoch. That is easy to implement by trimming the larger class before creating the dataset. The tradeoff is obvious: you discard information.

Undersampling can still be useful when:

  • the majority class is extremely large
  • training speed matters more than maximum recall
  • duplicate-like majority images add little information

Keep Validation and Test Data Unchanged

Whatever balancing strategy you choose for training, do not oversample or undersample the validation and test sets just to make the metrics look cleaner. Those splits should reflect the real-world distribution you care about. Otherwise you can end up with a model that looks balanced in training reports but performs poorly in production.

Prefer tf.data for Fine-Grained Control

Modern Keras works better with tf.data than with ImageDataGenerator for advanced sampling behavior. If the question is specifically about flow_from_directory, the honest answer is that it is not the right abstraction for class-aware over- or under-sampling.

You can still use directory-based loading logic, but you gain much more control once you build the dataset yourself.

Common Pitfalls

  • Expecting flow_from_directory to perform class balancing automatically.
  • Oversampling by copying files on disk when dynamic sampling would be cleaner.
  • Ignoring class_weight, which may solve the problem with far less complexity.
  • Undersampling so aggressively that the model loses important majority-class variety.
  • Evaluating on a rebalanced validation set instead of a realistic validation distribution.

Summary

  • 'flow_from_directory does not directly support over- or under-sampling by class.'
  • 'class_weight is the simplest fix for many imbalance problems.'
  • Real oversampling usually requires a custom generator or tf.data pipeline.
  • Undersampling is easy but throws away training data.
  • For advanced balancing logic, tf.data is usually the better long-term approach.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.