Data Augmentation with Python

augmentation_python

Data Augmentation with Python: A Complete Guide with Coded Algorithms

Learn how to multiply the value of your dataset using Python — with hands-on, ready-to-run code for images, text, and audio.


📌 What Is Data Augmentation?

Data augmentation is the process of artificially expanding a training dataset by creating modified versions of existing data. Instead of collecting thousands of new samples, we transform the ones we already have — rotating an image, swapping a synonym in a sentence, or shifting the pitch of an audio clip — to teach a machine learning model to generalize better.

It's one of the cheapest and most effective ways to fight overfitting, especially when labeled data is scarce or expensive to obtain.

Why it matters: A model trained only on upright, well-lit photos will fail the moment it sees a tilted or dim one. Augmentation exposes the model to that variation during training — before it ever meets the real world.

🧰 Python Libraries Used in This Guide

Library Best For
OpenCV / Pillow Manual pixel-level image transforms
imgaug / Albumentations Fast, pipeline-based image augmentation
torchvision.transforms PyTorch training pipelines
tf.keras.preprocessing TensorFlow/Keras training pipelines
nlpaug Text augmentation (NLP)
librosa Audio augmentation

Install what you need:

pip install opencv-python pillow imgaug albumentations torchvision tensorflow nlpaug librosa

1️⃣ Image Augmentation — From Scratch (NumPy + OpenCV)

Understanding the algorithm behind augmentation matters as much as using a library. Here's how core transforms actually work under the hood:

import cv2
import numpy as np
import random

def random_rotate(image, angle_range=(-25, 25)):
    """Rotate image by a random angle within the given range."""
    h, w = image.shape[:2]
    angle = random.uniform(*angle_range)
    center = (w // 2, h // 2)
    matrix = cv2.getRotationMatrix2D(center, angle, 1.0)
    return cv2.warpAffine(image, matrix, (w, h), borderMode=cv2.BORDER_REFLECT)

def random_flip(image, p=0.5):
    """Horizontally flip the image with probability p."""
    if random.random() < p:
        return cv2.flip(image, 1)
    return image

def add_gaussian_noise(image, mean=0, sigma=15):
    """Inject Gaussian noise into the image."""
    noise = np.random.normal(mean, sigma, image.shape).astype(np.float32)
    noisy = image.astype(np.float32) + noise
    return np.clip(noisy, 0, 255).astype(np.uint8)

def random_brightness_contrast(image, brightness=30, contrast=0.3):
    """Randomly adjust brightness and contrast."""
    b = random.uniform(-brightness, brightness)
    c = 1 + random.uniform(-contrast, contrast)
    adjusted = image.astype(np.float32) * c + b
    return np.clip(adjusted, 0, 255).astype(np.uint8)

def random_crop(image, crop_ratio=0.8):
    """Crop a random region and resize back to original size."""
    h, w = image.shape[:2]
    ch, cw = int(h * crop_ratio), int(w * crop_ratio)
    y = random.randint(0, h - ch)
    x = random.randint(0, w - cw)
    cropped = image[y:y+ch, x:x+cw]
    return cv2.resize(cropped, (w, h))

def augment_pipeline(image):
    """Chain multiple augmentations into a single pipeline."""
    image = random_flip(image)
    image = random_rotate(image)
    image = random_crop(image)
    image = random_brightness_contrast(image)
    image = add_gaussian_noise(image)
    return image

# Example usage
img = cv2.imread("sample.jpg")
augmented = augment_pipeline(img)
cv2.imwrite("augmented_sample.jpg", augmented)

What each function does:

  • random_rotate — rotates the image around its center using an affine transformation matrix.
  • random_flip — mirrors the image horizontally, useful for objects without a fixed left/right orientation.
  • add_gaussian_noise — simulates sensor noise so the model doesn't rely on pixel-perfect inputs.
  • random_brightness_contrast — mimics different lighting conditions.
  • random_crop — forces the model to recognize objects even when partially framed.

2️⃣ Image Augmentation — Using Albumentations (Production-Grade)

For real projects, use a battle-tested library instead of reinventing transforms. Albumentations is fast (built on OpenCV) and integrates directly with PyTorch/TensorFlow pipelines.

import albumentations as A
import cv2

transform = A.Compose([
    A.HorizontalFlip(p=0.5),
    A.Rotate(limit=30, p=0.7),
    A.RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2, p=0.6),
    A.GaussNoise(var_limit=(10.0, 50.0), p=0.4),
    A.CoarseDropout(max_holes=8, max_height=20, max_width=20, p=0.3),  # simulates occlusion
    A.RandomResizedCrop(height=224, width=224, scale=(0.7, 1.0), p=0.8),
])

image = cv2.imread("sample.jpg")
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

result = transform(image=image)
augmented_image = result["image"]

cv2.imwrite("albumentations_output.jpg", cv2.cvtColor(augmented_image, cv2.COLOR_RGB2BGR))

3️⃣ Real-Time Augmentation During Training (Keras)

Instead of pre-generating augmented images and storing them on disk, augment on the fly during training — this saves storage and gives infinite variation:

from tensorflow.keras.preprocessing.image import ImageDataGenerator

datagen = ImageDataGenerator(
    rotation_range=25,
    width_shift_range=0.15,
    height_shift_range=0.15,
    shear_range=0.15,
    zoom_range=0.2,
    horizontal_flip=True,
    brightness_range=[0.8, 1.2],
    fill_mode="nearest"
)

train_generator = datagen.flow_from_directory(
    "dataset/train",
    target_size=(224, 224),
    batch_size=32,
    class_mode="categorical"
)

# model.fit(train_generator, epochs=20, validation_data=val_generator)

4️⃣ Text Augmentation with nlpaug

NLP models benefit from augmented text just like vision models benefit from augmented images — synonym replacement, back-translation, and random insertion/deletion all help.

import nlpaug.augmenter.word as naw

text = "The quick brown fox jumps over the lazy dog."

# Synonym replacement using WordNet
syn_aug = naw.SynonymAug(aug_src="wordnet")
print(syn_aug.augment(text))

# Random word swap
swap_aug = naw.RandomWordAug(action="swap")
print(swap_aug.augment(text))

# Contextual word embedding substitution (BERT-based)
bert_aug = naw.ContextualWordEmbsAug(model_path="bert-base-uncased", action="substitute")
print(bert_aug.augment(text))

5️⃣ Audio Augmentation with librosa

import librosa
import numpy as np

y, sr = librosa.load("sample.wav")

def pitch_shift(y, sr, n_steps=3):
    return librosa.effects.pitch_shift(y, sr=sr, n_steps=n_steps)

def time_stretch(y, rate=1.2):
    return librosa.effects.time_stretch(y, rate=rate)

def add_noise(y, noise_factor=0.005):
    noise = np.random.randn(len(y))
    return y + noise_factor * noise

augmented_audio = pitch_shift(y, sr)
augmented_audio = time_stretch(augmented_audio)
augmented_audio = add_noise(augmented_audio)

✅ Best Practices Checklist

  • Match augmentation to domain: don't flip digits/text horizontally (6 becomes 9!) or over-rotate satellite imagery in ways that break label meaning.
  • Augment only the training set — never the validation/test sets, or you'll get misleading metrics.
  • Start mild, increase gradually — extreme distortions can teach the model wrong patterns.
  • Combine with normalization — augmentation changes pixel/statistical distribution, so re-check your preprocessing.
  • Use on-the-fly augmentation for large datasets to avoid exploding disk usage.
  • Visualize before training — always eyeball a batch of augmented samples to catch bugs early.

🎯 Conclusion

Data augmentation turns a small dataset into a much richer training signal — without collecting a single new sample. Whether you hand-code transforms with NumPy/OpenCV for full control, or lean on libraries like Albumentations, Keras, nlpaug, and librosa for speed, the underlying idea is the same: expose your model to realistic variation so it learns the true pattern, not the noise.

💡 Next step: Try applying the pipeline above to your own dataset, then compare validation accuracy with and without augmentation — the difference is often dramatic.

Tip for Blogger: paste this into the HTML view of a new post (not the visual/compose editor) so the formatting and code blocks render correctly.

Post a Comment

0 Comments