Пишем модель генерации изображений с нуля
Привет пикабушники!
Сегодня мы создадим и обучим модель инверсионной диффузии для генерации изображений.
Требования - python, conda/rocm, pytoch, torchvision matplotlib(для визуализации)
1 Скачайте и установите python, на GNU/Linux установите uv , а затем uv python install python3.12
2 Создайте и активируйте виртуальное окружение.
Что такое виртуальное окружение(venv)? venv это изолированная среда python для установки зависимостей
1 Вариант (для uv, очень простой)
uv venv .venv --python python3.12, выполните команду, которую выдаст uv,
установка зависимостей в окружении uv pip install datasets torch torchvision matplotlib (для cpu, для gpu ниже).
Внимание!! Вам нужна особая команда для установки torch с поддержкой gpu.
Полный список здесь -
uv pip install torch torchvision --index-url https://download.pytorch.org/whl/cu128, это для nvidia
uv pip install torch torchvision --index-url https://download.pytorch.org/whl/rocm6.4 amd rocm(только на GNU/Linux).
2 Вариант для python venv.
На винде - py -3.12 -m venv .venv, дальнейшие этапы аналогичные, только команды для установки зависимостей без uv, просто pip.
3 Этап создайте файл, назовите его как хотите, но с расширением py , например model.py.
Скопируйте туда данный код, запустите через python вашфайл.py и начнется скачивание mnist датасет с рукописными цифрами и затем обучение в 20 эпох.
Если у вас слабый gpu или его нет, то, к сожалению, ждать нужно будет очень долго.
С gpu +- час - 2 часа. В результате у вас отобразится результат генерации, а также поле для ввода цифры, чтобы сгенерировать. Чем больше эпох при обучении, тем лучше результат. Но не стоит ставить огромные значения, модель может переобучиться.
Для тех у кого нет gpu можете загрузить пред обученную модель с моего гитхаба.
Как это работает и что это такое
Это условная диффузионная модель (Conditional Diffusion Model), которая генерирует изображения цифр MNIST (0–9) с контролем над классом (например, можно запросить генерацию именно цифры "5"). Модель сочетает:
Диффузионный процесс — постепенное добавление/удаление шума.
Условную генерацию — зависимость от целевого класса (цифры).
Архитектуру U-Net — для обработки изображений на разных уровнях детализации.
Как это работает?
1. Прямой диффузионный процесс (заражение шумом)
Цель: Постепенно превратить изображение в случайный шум за T=1000 шагов.
Математика:
xt=αˉt
⋅x0+1−αˉt
⋅ϵ
где:
x0 — исходное изображение,
ϵ — случайный шум (Gaussian noise),
αˉt=∏s=1t(1−βs) — кумулятивное произведение коэффициентов "чистоты" сигнала.
В коде:
python
1
2
3
4
⌄
def forward_diffusion(self, x0, t):
noise = torch.randn_like(x0)
xt = sqrt_alphas_cumprod[t] * x0 + sqrt_one_minus_alphas_cumprod[t] * noise
return xt, noise
2. Обратный процесс (генерация из шума)
Цель: Восстановить изображение из шума, шаг за шагом уменьшая шум.
Как учится модель?
На каждом шаге t модель предсказывает шум ϵθ(xt,t,y) , где y — целевой класс (цифра).Функция потерь: MSE между предсказанным и реальным шумом:
L=Ex0,ϵ,t[∥ϵ−ϵθ(xt,t,y)∥2]
В коде:
def forward_diffusion(self, x0, t):
noise = torch.randn_like(x0)
xt = sqrt_alphas_cumprod[t] * x0 + sqrt_one_minus_alphas_cumprod[t] * noise
return xt, noise
1
2
noise_pred = self.model(xt, t, y) # Предсказание шума
loss = F.mse_loss(noise_pred, noise) # Расчет потерь
3. Условная генерация (ключевая особенность)
Модель генерирует изображение конкретного класса (например, цифру "7") благодаря:
Встраиванию класса:
Класс y преобразуется в эмбеддинг через nn.Embedding(num_classes, class_emb_dim).
Эмбеддинг проходит через MLP для нелинейного преобразования.
Интеграция в U-Net:
В каждом блоке U-Net информация о классе добавляется к промежуточным активациям:
noise_pred = self.model(xt, t, y) # Предсказание шума
loss = F.mse_loss(noise_pred, noise) # Расчет потерь
1
h = h + t_emb[..., None, None] + c_emb[..., None, None]
Это позволяет модели адаптировать обработку изображения под целевую цифру.
4. Архитектура модели: Условный U-Net
Структура:
Downsampling: 2 уровня уменьшения размерности (с сохранением skip-соединений).
Bottleneck: Обработка на низком разрешении.
Upsampling: 2 уровня увеличения размерности (с использованием skip-соединений).
Особенности:
Позиционное кодирование времени: timestep_embedding преобразует шаг t в вектор, чтобы модель "понимала", на каком этапе диффузии она работает.
Групповая нормализация (GroupNorm): Улучшает стабильность обучения.
SiLU активации: Нелинейность, улучшающая градиентный поток.
Этапы работы модели
1. Обучение
Загружаем данные MNIST (нормализованные в диапазон [-1, 1]).
Для каждого батча:
Случайно выбираем шаг диффузии t∈[0,T−1] .
Добавляем шум к изображению: xt=f(x0,t) .
Модель предсказывает шум ϵθ(xt,t,y) .
Обновляем веса через MSE-потерю.
Каждую эпоху генерируем образцы для всех классов (0–9) и сохраняем их.
2. Генерация (сэмплирование)
Начинаем с случайного шума xT∼N(0,I) .
Итеративно уменьшаем шум от t=T−1 до t=0 :
Предсказываем шум ϵθ(xt,t,y) .
Обновляем изображение:
xt−1=αt
1(xt−1−αˉt
βtϵθ)+σtz
где z — новый шум (если t>0 ).
На выходе получаем чистое изображение x0 нужного класса y .
Скачать пред обученную модель
https://github.com/Karag0/simple-diffusiuion-model/releases/...А на этом всё!