Почему ваша нейросеть запоминает, а не учится?
Вы собрали 500 фотографий кошек и 500 фотографий не-кошек. Обучили модель. На обучающей выборке точность 99%. Радостно запускаете на новых данных — и получаете 60%. Что пошло не так? Модель просто запомнила ваши 500 кошек, а не поняла концепцию «кошачести». Это переобучение в чистом виде, и главная причина — недостаток разнообразия в данных.
И вот здесь появляется аугментация. Не просто «увеличение датасета», а создание новых, правдоподобных вариаций из существующих данных. Цель — заставить модель обращать внимание на инвариантные признаки (форма ушей, усы, нос), а не на шум (фон, освещение, угол съемки).
Базовые методы: что можно делать с кошкой (без вреда для животного)
Начнем с простых пространственных преобразований. Они дешевы в вычислении и часто дают самый большой прирост.
1Поворот, отражение и сдвиг
Кошки не всегда стоят прямо. Поворот на случайный угол (например, ±30 градусов) учит модель, что ориентация — не главный признак. Горизонтальное отражение (flip) — мощнейший прием, особенно для симметричных объектов. Сдвиг (translation) имитирует неточное кадрирование.
Осторожно с поворотом на 90 или 180 градусов! Для задачи «кошка/не кошка» это, возможно, окей. Но если вы различаете, скажем, буквы «И» и «N», поворот уничтожит различия. Всегда думайте о семантике.
2Масштабирование и кроппинг
Кошка может быть близко или далеко. Случайный кроп (вырезка части изображения) заставляет модель искать признаки в разных частях кадра. Часто комбинируют с изменением масштаба. Важно: после кропа обычно приводят изображение к исходному размеру (например, 224x224), иначе не получится батч.
3Цветовые искажения
Яркость, контрастность, насыщенность, оттенок (Hue). Освещение в жизни меняется. Солнечный свет, лампочка, тень — у всех разная цветовая температура. Слегка меняя эти параметры, вы готовите модель к любым условиям. Ключевое слово — слегка. Не делайте из рыжей кошки зеленую.
# Пример слабых цветовых искажений в Albumentations (версия 1.4.x, актуальна на 20.01.2026)
import albumentations as A
transform = A.Compose([
A.RandomBrightnessContrast(brightness_limit=0.1, contrast_limit=0.1, p=0.5),
A.HueSaturationValue(hue_shift_limit=10, sat_shift_limit=20, val_shift_limit=10, p=0.5),
])Продвинутые методы: когда базовых уже мало
Если ваш датасет очень маленький или объекты имеют сложную геометрию, подключайте тяжелую артиллерию.
CutMix и MixUp: Эти методы не просто смешивают изображения, они создают принципиально новые точки данных. CutMix вырезает прямоугольную область с одного изображения и вставляет на другое, соответствующим образом смешивая лейблы (например, 70% «кошка», 30% «собака»). Модель учится обращать внимание на части объектов, а не на целое. MixUp линейно интерполирует между двумя изображениями и их лейблами. Оба метода — отличный способ регуляризации, но требуют аккуратной настройки.
Стирание (Random Erasing, Cutout): Случайно закрашиваем прямоугольную область на изображении черным цветом или шумом. Зачем? Чтобы модель не зацикливалась на одном, самом ярком признаке (например, если все ваши кошки с красным ошейником). Вынуждает искать другие, дополнительные признаки.
Геометрические искажения (Grid Distortion, Elastic Transform): Имитируют нелинейные деформации, как будто объект сфотографирован через стекло или на гибкой поверхности. Для кошек — не самый частый сценарий, но для медицинских изображений (рентген) или снимков текстиля — бесценно.
Практика: собираем пайплайн аугментации на PyTorch
Теория — это хорошо, но код — лучше. Давайте соберем реалистичный пайплайн для классификации кошек с помощью torchvision.transforms и albumentations. Почему albumentations? Он быстрее, особенно для больших разрешений, и имеет более богатый набор преобразований.
import torch
from torch.utils.data import Dataset, DataLoader
import albumentations as A
from albumentations.pytorch import ToTensorV2
import cv2
import os
# Определяем аугментации для обучающей выборки
train_transform = A.Compose([
A.RandomResizedCrop(height=224, width=224, scale=(0.8, 1.0)),
A.HorizontalFlip(p=0.5),
A.ShiftScaleRotate(shift_limit=0.05, scale_limit=0.05, rotate_limit=15, p=0.5),
A.OneOf([
A.RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2),
A.HueSaturationValue(hue_shift_limit=10, sat_shift_limit=20, val_shift_limit=10),
], p=0.5),
A.CoarseDropout(max_holes=8, max_height=16, max_width=16, fill_value=0, p=0.3), # аналог Cutout
A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
ToTensorV2(),
])
# Для валидации — только ресайз и нормализация. НИКАКИХ случайных преобразований!
val_transform = A.Compose([
A.Resize(224, 224),
A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
ToTensorV2(),
])
class CatDataset(Dataset):
def __init__(self, file_paths, labels, transform=None):
self.file_paths = file_paths
self.labels = labels
self.transform = transform
def __len__(self):
return len(self.file_paths)
def __getitem__(self, idx):
img_path = self.file_paths[idx]
label = self.labels[idx]
# Читаем изображение в BGR (формат OpenCV)
image = cv2.imread(img_path)
# Конвертируем в RGB
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
if self.transform:
augmented = self.transform(image=image)
image = augmented['image']
return image, label
# Создаем даталоадеры
train_dataset = CatDataset(train_files, train_labels, transform=train_transform)
val_dataset = CatDataset(val_files, val_labels, transform=val_transform)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False)Обратите внимание на ключевое различие: для обучения — богатый набор случайных аугментаций, для валидации — детерминированный пайплайн (только ресайз и нормализация). Если вы будете применять случайные аугментации к валидации, ваши метрики будут «прыгать» от эпохи к эпохе, и вы не сможете адекватно оценить прогресс модели.
Распространенные ошибки и как их избежать
| Ошибка | Последствие | Решение |
|---|---|---|
| Применение аугментаций к валидационной/тестовой выборке | Несопоставимые метрики, невозможно понять, улучшилась ли модель | Используйте разные пайплайны для train и val/test |
| Слишком агрессивные преобразования | Изображение становится нереалистичным, модель учится на артефактах | Начинайте с мягких параметров. Увеличивайте силу постепенно, если видите недообучение |
| Игнорирование доменной специфики | Аугментации, противоречащие физике объекта (вертикальный flip для текста) | Продумывайте, какие преобразования имеют смысл для ваших данных. Не используйте всё подряд |
| Аугментация «на лету» без кеширования на медленном хранилище | ГПУ простаивает, обучение упирается в скорость чтения/аугментации данных | Используйте быстрые библиотеки (albumentations). Рассмотрите предварительную аугментацию и сохранение на SSD для маленьких датасетов |
Самая коварная ошибка — утечка данных через аугментацию. Представьте, у вас есть 10 уникальных фото кошки Барсика. Вы делаете 100 аугментированных версий каждого. Потом случайно разбиваете данные на train/val так, что аугментированные версии одного исходного фото попадают и в train, и в val. Модель увидит почти идентичные изображения в обеих выборках и покажет завышенную валидационную точность. Разбивайте данные по исходным, уникальным идентификаторам до аугментации.
А если данных все равно мало?
Аугментация — не панацея. Если у вас 50 фотографий, даже создав из них 5000 вариантов, вы не охватите всё разнообразие мира. Здесь нужно думать стратегически:
- Сбор большего количества данных — банально, но эффективно. Используйте открытые датасеты или скрапинг.
- Использование предобученных моделей (Transfer Learning). Возьмите модель, обученную на ImageNet (где есть кошки!), и дообучите (fine-tune) на своих данных. Она уже знает базовые признаки вроде граней и текстур.
- Генеративные модели (GANs, Diffusion Models). На 20.01.2026 модели типа Stable Diffusion 3 или DALL-E 3 способны генерировать фотореалистичные изображения кошек по текстовому описанию. Вы можете использовать их для расширения датасета. Но будьте осторожны: модель может научиться на артефактах генерации. Всегда смешивайте сгенерированные данные с реальными.
Помните про data poisoning? Если вы скачиваете данные из непроверенных источников или используете сгенерированные изображения без фильтрации, вы рискуете отравить свой датасет. Несколько вредоносных образцов с неверной разметкой могут существенно снизить качество модели.
Финальный совет: аугментация — это эксперимент
Не существует идеального набора аугментаций «для кошек». Для уличных кошек важны изменения освещения и погодных условий (добавьте имитацию дождя или снега?). Для породистых — возможно, более важны геометрические искажения, чтобы модель не зациклилась на «идеальном» профиле.
Создайте несколько конфигураций (легкая, средняя, агрессивная). Обучите модель с каждой. Смотрите не только на валидационную точность, но и на разницу между train и val loss. Если train loss намного ниже val loss — у вас все еще переобучение, можно усиливать аугментацию или добавлять другие методы регуляризации (Dropout, Weight Decay).
Аугментация превращает вашу модель из заучки, которая зубрит конкретные картинки, в сообразительного ученика, который понимает суть. И теперь, когда вы видите очередной мем про «кота в коробке», ваша нейросеть — если вы всё сделали правильно — уверенно скажет: «Да, это кошка». Даже если видна только половина.