Машинное обучение

Генеративно-состязательные сети (GAN)

В 2014 году аспирант Монреальского университета Иэн Гудфеллоу спорил с друзьями в баре о том, как научить нейросеть генерировать реалистичные изображения. Все предложения казались слишком сложными. Тогда ему пришла в голову идея: что если натравить две нейросети друг на друга - одна создаёт фейки, другая их разоблачает? Он пришёл домой, написал код за одну ночь, запустил - и это сработало с первого раза. Так появились GAN - генеративно-состязательные сети, которые сегодня создают фотореалистичные лица людей, которых никогда не существовало.

  • **Генерация лиц (ThisPersonDoesNotExist.com)** - StyleGAN создаёт фотореалистичные портреты несуществующих людей с разрешением 1024x1024, которые невозможно отличить от реальных фотографий: от текстуры кожи до отражений в глазах
  • **Super-resolution и реставрация** - ESRGAN увеличивает разрешение изображений в 4-8 раз, восстанавливая детали, которых не было в оригинале: из размытого 64x64 фото получается чёткое 512x512, что применяется в медицинской визуализации и реставрации старых фильмов
  • **Data augmentation в медицине** - GAN генерирует синтетические рентгеновские снимки и МРТ для обучения диагностических моделей, решая проблему нехватки размеченных медицинских данных и требований конфиденциальности пациентов

Предварительные знания

  • Autoencoders and VAE

Спор в баре, ставший генеративной революцией

Рассказывают, что идею генеративно-состязательных сетей Ян Гудфеллоу набросал во время спора в баре в Монреале в 2014 году: столкнуть две сети друг с другом - одна генерирует подделки, другая пытается их поймать - и пусть это соревнование толкает генератор к реалистичности. В ту же ночь он написал рабочий прототип, а статья 2014 года породила целую область. В 2015 году Рэдфорд с коллегами предложили DCGAN, который позволил GAN стабильно обучаться на свёрточных архитектурах с понятными правилами проектирования. К 2018 году StyleGAN от NVIDIA под руководством Теро Карраса генерировал настолько убедительные фотореалистичные лица людей, что отличить их от настоящих фотографий стало по-настоящему трудно.

Генератор: создание данных из шума

Генератор - это нейросеть, которая принимает на вход **случайный вектор z** (latent vector) из нормального распределения и превращает его в синтетические данные, например изображение. Представьте фальшивомонетчика, который получает случайные чернильные пятна и учится превращать их в убедительные банкноты. В начале обучения генератор выдаёт бессмысленный шум, но постепенно учится создавать всё более реалистичные данные.

**Latent space** (скрытое пространство) - это пространство всех возможных входных векторов z. Каждая точка в этом пространстве соответствует какому-то выходному изображению. Удивительное свойство хорошо обученного GAN: *похожие точки в latent space дают похожие изображения*. Если z1 генерирует лицо с улыбкой, то z1 + небольшой сдвиг даст лицо с чуть другой улыбкой. Это позволяет плавно интерполировать между изображениями.

**Почему Tanh на выходе генератора?** Tanh выдаёт значения от -1 до +1. Изображения нормализуются в тот же диапазон. Это даёт: - **Симметричный диапазон** - центрирован вокруг нуля, что помогает стабильности обучения - **Ограниченный выход** - значения пикселей не уходят в бесконечность - **Совместимость** - дискриминатор получает реальные и фейковые изображения в одном масштабе Альтернатива - Sigmoid (0 до 1), но Tanh обычно даёт лучшую стабильность при обучении GAN.

Генератор никогда не видит реальных данных напрямую. Он учится только через **градиенты от дискриминатора**. Когда дискриминатор говорит "это фейк", генератор получает сигнал, в каком направлении менять веса, чтобы обмануть дискриминатор в следующий раз. Это как фальшивомонетчик, который никогда не видел настоящих денег, но получает обратную связь от детектора подделок: "вот здесь водяной знак не так", "краска не того оттенка".

Что является входом генератора в GAN?

Дискриминатор: детектор подделок

Дискриминатор - это **бинарный классификатор**, который принимает изображение (реальное или сгенерированное) и выдаёт вероятность того, что оно настоящее. Если генератор - это фальшивомонетчик, то дискриминатор - детектив, специализирующийся на выявлении подделок. Его задача: научиться отличать реальные данные из обучающей выборки от фейков, созданных генератором.

Обратите внимание на **LeakyReLU** вместо обычного ReLU в дискриминаторе. Обычный ReLU обнуляет все отрицательные значения, что может привести к "мёртвым нейронам" - нейронам, через которые градиент перестаёт течь. LeakyReLU пропускает маленький отрицательный сигнал (обычно 0.2 * x), что стабилизирует обучение GAN. Также в дискриминаторе **не используется BatchNorm** - это эмпирическое правило, которое улучшает стабильность.

**Состязательная игра: генератор vs дискриминатор** Две сети обучаются одновременно с противоположными целями: - **Дискриминатор** хочет: D(real) = 1 (реальное - настоящее), D(G(z)) = 0 (фейк - поддельное) - **Генератор** хочет: D(G(z)) = 1 (обмануть дискриминатор, чтобы он считал фейк настоящим) Это и есть **adversarial** (состязательный) подход: успех одной сети - провал другой. Генератор не может напрямую улучшить свои изображения - он может только пытаться обмануть дискриминатор. А дискриминатор не может расслабиться - генератор постоянно становится лучше.

Ключевое отличие от автоэнкодеров: автоэнкодер учится *реконструировать* входные данные через bottleneck, а GAN учится *генерировать* новые данные, которые неотличимы от реальных. Автоэнкодер сравнивает выход со входом напрямую (pixel-to-pixel loss), а GAN использует дискриминатор как "обученного критика". Поэтому GAN генерирует более чёткие и реалистичные изображения - дискриминатор замечает размытость и наказывает за неё.

Какую функцию активации обычно используют в скрытых слоях дискриминатора GAN и почему?

Динамика обучения GAN

Обучение GAN - это **minimax-игра**: генератор минимизирует, а дискриминатор максимизирует функцию потерь V(D, G) = E[log D(x)] + E[log(1 - D(G(z)))]. Первый член - насколько хорошо D распознаёт реальные данные. Второй - насколько хорошо D отвергает фейки. D хочет оба члена максимальными (правильно классифицировать), G хочет второй член минимальным (обмануть D).

В идеале обучение достигает **равновесия Нэша**: дискриминатор выдаёт 0.5 на любой вход, потому что не может отличить реальные данные от сгенерированных. На практике это равновесие нестабильно. Два главных врага обучения GAN: **mode collapse** и **дисбаланс** между генератором и дискриминатором.

**Mode collapse - главная проблема GAN:** Mode collapse происходит, когда генератор находит "лазейку" - один тип изображения, который стабильно обманывает дискриминатор, и начинает генерировать только его. Пример: GAN обучается на лицах, но генерирует только женские лица с улыбкой. Все 1000 разных z дают почти одинаковое изображение. Генератор "схлопнулся" в одну моду (mode) распределения данных, игнорируя всё разнообразие. Почему это происходит: генератору выгоднее идеально освоить одну моду, чем рисковать с разнообразием. Это рациональная стратегия в minimax-игре, но катастрофа для генерации.

**Wasserstein GAN (WGAN) - решение проблемы нестабильности:** Обычный GAN использует BCE loss, который может давать vanishing gradients когда дискриминатор слишком силён. WGAN заменяет loss на **Wasserstein distance** (Earth Mover's Distance): - Дискриминатор ("critic") выдаёт не вероятность, а score без Sigmoid - loss_D = D(fake) - D(real) (critic хочет разницу побольше) - loss_G = -D(fake) (генератор хочет высокий score) - **Gradient clipping** или **gradient penalty** для Lipschitz-ограничения WGAN даёт значимую метрику качества: чем ниже Wasserstein distance, тем лучше генератор. В обычном GAN loss генератора не коррелирует с качеством.

Что такое mode collapse в контексте обучения GAN?

DCGAN: глубокие свёрточные GAN

**DCGAN** (Deep Convolutional GAN) - первая архитектура, которая систематизировала правила построения стабильных свёрточных GAN. До DCGAN (2015) попытки использовать CNN в GAN часто заканчивались нестабильным обучением. Alec Radford и коллеги определили набор архитектурных рекомендаций, которые стали стандартом для всех последующих GAN.

**Архитектурные правила DCGAN:** 1. **Никакого pooling** - заменить Max Pooling на strided convolutions (дискриминатор) и transposed convolutions (генератор). Пусть сеть сама учится понижать/повышать разрешение. 2. **Batch Normalization везде** - кроме выходного слоя генератора и входного слоя дискриминатора. BatchNorm стабилизирует обучение, предотвращая mode collapse. 3. **Никаких полносвязных скрытых слоёв** - только свёрточные слои. Полносвязные слои используются только для проекции z в начальный тензор генератора. 4. **ReLU в генераторе, LeakyReLU в дискриминаторе** - кроме выхода генератора (Tanh) и выхода дискриминатора (Sigmoid).

**Transposed convolution** (иногда называют "deconvolution", хотя это математически некорректно) - ключевая операция в генераторе DCGAN. Обычная свёртка уменьшает пространственное разрешение (32x32 -> 16x16), а transposed convolution увеличивает (16x16 -> 32x32). Интуитивно: она вставляет нули между пикселями и применяет обычную свёртку, "растягивая" изображение. Stride=2 удваивает размер.

Одно из самых впечатляющих открытий DCGAN - **арифметика в latent space**. Оказалось, что latent vectors можно складывать и вычитать, и результат имеет семантический смысл: vector("мужчина в очках") - vector("мужчина") + vector("женщина") = vector("женщина в очках"). Это доказало, что GAN не просто запоминает изображения из датасета, а учит *осмысленное* представление - latent space организовано по семантическим признакам.

Какое из следующих архитектурных решений является правилом DCGAN?

StyleGAN и современные GAN

**StyleGAN** (2018, NVIDIA) - революционная архитектура, которая переосмыслила генератор GAN. Вместо того чтобы подавать z напрямую в свёрточные слои, StyleGAN сначала пропускает z через **mapping network** (8 полносвязных слоёв), преобразуя его в промежуточный вектор w. Этот w-вектор затем "внедряется" в каждый слой генератора через механизм **Adaptive Instance Normalization (AdaIN)**, контролируя стиль на каждом уровне детализации.

**Adaptive Instance Normalization (AdaIN)** - ключевой механизм StyleGAN. Для каждого слоя он нормализует feature maps (вычитает среднее, делит на std), а затем масштабирует и сдвигает их параметрами, вычисленными из style vector w. Формула: AdaIN(x, w) = scale(w) * normalize(x) + bias(w). Это позволяет w-вектору управлять "стилем" на каждом уровне детализации независимо.

**Progressive growing: от 4x4 до 1024x1024** Оригинальный StyleGAN использовал **progressive growing** - технику постепенного увеличения разрешения: 1. Начать обучение на 4x4 изображениях (простая задача, быстрая сходимость) 2. Добавить слои для 8x8, продолжить обучение 3. Постепенно дорасти до 16x16, 32x32, 64x64... 1024x1024 Это решает проблему: обучать GAN сразу на 1024x1024 практически невозможно - слишком много деталей, слишком нестабильно. Progressive growing позволяет сети сначала выучить грубую структуру, а потом постепенно добавлять детали. **StyleGAN2** отказался от progressive growing, заменив его на path length regularization и другие техники стабилизации.

**StyleGAN2** (2020) исправил артефакты оригинального StyleGAN (характерные "капли" на изображениях), убрал progressive growing и улучшил качество генерации. **StyleGAN3** (2021) решил проблему "texture sticking" - когда текстуры привязываются к пиксельным координатам вместо того, чтобы следовать за геометрией объекта.

Сегодня ландшафт генеративных моделей изменился. **Diffusion models** (DALL-E 2, Stable Diffusion, Midjourney) превзошли GAN по качеству генерации и разнообразию. Они обучаются стабильнее (нет adversarial dynamics), не страдают от mode collapse и лучше покрывают всё распределение данных. Однако GAN остаются актуальными: они генерируют изображения за один forward pass (миллисекунды), тогда как diffusion models требуют десятки шагов (секунды). Для real-time приложений - видео, интерактивные системы - GAN по-прежнему предпочтительнее.

GAN - лучший способ генерации изображений, ничто не может их превзойти

Diffusion-модели (DALL-E 2, Stable Diffusion) превзошли GAN по качеству и стабильности обучения, но GAN остаются быстрее при inference и незаменимы для real-time приложений

GAN страдают от mode collapse и нестабильного обучения. Diffusion models обучаются стабильно, лучше покрывают всё распределение данных и генерируют более разнообразные результаты. Однако diffusion models требуют десятки шагов denoising (секунды), тогда как GAN генерирует за один forward pass (миллисекунды). Выбор зависит от задачи: для максимального качества - diffusion, для скорости - GAN.

Итоги

  • **Генератор** принимает случайный вектор z из нормального распределения и трансформирует его в синтетическое изображение через серию слоёв - он никогда не видит реальные данные, а учится только через градиенты от дискриминатора
  • **Дискриминатор** - бинарный классификатор, который отличает реальные данные от сгенерированных, используя LeakyReLU вместо ReLU для предотвращения мёртвых нейронов
  • **Minimax-игра** чередует обучение D (отличать реальное от фейка) и G (обмануть D), но страдает от mode collapse и нестабильности - WGAN с Wasserstein distance решает часть этих проблем
  • **DCGAN** задал архитектурные правила: strided convolutions вместо pooling, Batch Normalization, никаких полносвязных скрытых слоёв - и открыл арифметику latent space (мужчина в очках - мужчина + женщина = женщина в очках)
  • **StyleGAN** разделил генерацию на mapping network (z -> w) и synthesis network с AdaIN, позволяя управлять стилем на каждом уровне детализации - от позы до текстуры кожи
  • Как и та ночь Гудфеллоу в 2014 году, когда идея о двух конкурирующих сетях сработала с первого запуска, GAN показали что состязательный подход - рабочий принцип обучения, хотя сегодня diffusion models превзошли GAN по качеству, оставив им преимущество в скорости inference

Связанные темы

GAN стоят на пересечении генеративных моделей и adversarial подходов, связывая классические автоэнкодеры с современной генерацией изображений:

  • Автоэнкодеры — Предшественник GAN в генеративных моделях: автоэнкодер сжимает данные в latent space и восстанавливает обратно, а GAN заменяет pixel-to-pixel reconstruction loss на дискриминатор-критик, что даёт более чёткие и реалистичные изображения
  • Классификация изображений — Дискриминатор GAN - по сути CNN-классификатор, обученный на бинарной задаче real/fake. Архитектурные решения из классификации (свёртки, BatchNorm, strided convolutions) прямо перенесены в GAN и составляют основу DCGAN

Вопросы для размышления

  • Почему генератор GAN, который никогда не видит реальные данные напрямую, способен создавать реалистичные изображения? Какую роль играет дискриминатор как посредник между реальными данными и генератором?
  • Mode collapse - одна из главных проблем GAN. Если бы вы разрабатывали новую GAN-архитектуру, какие механизмы вы бы добавили для поощрения разнообразия генерации?
  • Diffusion models превзошли GAN по качеству генерации, но GAN генерируют за миллисекунды, а diffusion - за секунды. В каких реальных приложениях скорость GAN критична, а в каких можно позволить себе ждать ради качества?

Связанные уроки

  • ml-32-autoencoders — Общая основа генеративного латентного пространства
  • ml-38-image-classification — Дискриминатор - бинарный классификатор изображений
  • ml-27-activation-functions — Стабильность генератора зависит от активаций
  • prob-04-bayes — GAN неявно моделируют распределение данных
  • aie-26-image-generation — GAN лежат в основе генерации изображений
  • dl-14
Генеративно-состязательные сети (GAN)

0

1

Войти

Какую роль выполняет mapping network в StyleGAN?