Оригинальное название: Stable Diffusion from Scratch II

Read this article in:
html { font-size: 20px; } code { font-size: 0.8rem; } .center { text-align: center; } .a20251225-container { margin: 2em auto 5em; width: 800px; } .a20251225-container img { max-width: calc( 100% - 1em ); padding: 0.5em; display: flex; margin: auto; } .a20251225-container img.bordered { border: 1px solid #999; } .a20251225-container table { margin: auto; } .a20251225-container table thead td { text-align: center; } .a20251225-container table.bordered td { border-bottom: 1px solid #999; padding: 0.5em; }

Это регургитация предыдущего Оригинальное название: Stable Diffusion from ScratchМне требуется более 1 дня, чтобы понять и реализовать код в этой статье. Случайно оригинальные статьи были удалены из Интернета - настолько, насколько сомнительно, что я копировал чужую работу - ну, оригинал больше не доступен, поэтому мой может стать авторитетной копией. И чтобы было ясно: я глубоко восхищаюсь авторами, которых я копирую. Я завидую их умственной ловкости и силе (а также времени и ресурсам, которые у них есть, чтобы продолжить эти исследования). Я восхищаюсь людьми, которые изобрели стабильную диффузию и другие алгоритмы в ее окрестностях. Ниже приведена моя скромная попытка реализовать код из этой статьи и получить стабильный экземпляр диффузии, написанный с нуля.

Кроме того, я буду в основном сосредотачиваться на вещах, с которыми я борюсь, так что это может быть не полный и полный учебник. Кроме того, для читателя я настоятельно рекомендую эту книгу: Погружение в глубокое обучениеОчень четко написано, это мне очень помогло. Их объяснение более яростного кодирования времени сделало концепцию кристально ясной для меня. Итак, краткая таблица содержания для этой статьи:

Таблица содержимого

  • 1D передняя/обратная диффузия
  • U-Net архитектура для работы с изображениями
  • потеря, связанная с изучением функции оценки
  • Модель внимания для условной генерации
  • автокодер

lightning

Базовая передняя и обратная диффузия

Для архитектуры стабильной диффузии. Допустим, у нас есть данные (изображения или одна точка данных), и мы добавляем к ним шум. Затем мы тренируем нейронную сеть, чтобы обезвредить наши данные. Так что мы будем иметь переднюю диффузию (добавляющий шум) и обратную диффузию (удаляющий шум). Для первого шага мы используем очень простую одномерную точку (y), которая дифференцируется как функция времени (x).

$$ x(t + \Delta t) = x(t) + \sigma(t) \sqrt{ \Delta t} \; r $$

Где \( \sigma(t) > 0 \) - сила шума, \( \Delta t \) - размер шага, а \( r \sim \mathcal{N} (0, 1) \) - стандартная нормальная случайная величина. Мы неоднократно добавляем нормально распределенный шум в наш образец. Часто сила шума \(\sigma(t) > 0 \) выбирается в зависимости от времени и становится выше по мере увеличения t. Это передний проход, поэтому \(\sigma(t)\) увеличивается со временем при добавлении шума и уменьшается со временем при его удалении.

Давайте реализуем передний проход в питоне.


## Simulate forward diffusion for N steps.
def forward_diffusion_1d(x0, noise_strength_fn, t0, nsteps, dt):
  """x0: initial sample value, scalar
  noise_strength_fn: function of time, outputs scalar noise strength
  t0: initial time
  nsteps: number of diffusion steps
  dt: time step size
  """

  # Initialize trajectory
  x = np.zeros(nsteps + 1); x[0] = x0
  t = t0 + np.arange(nsteps + 1)*dt

  # Perform many Euler-Maruyama time steps
  for i in range(nsteps):
    noise_strength = noise_strength_fn(t[i])
    random_normal = np.random.randn()
    x[i+1] = x[i] + random_normal
  return x, t

## Example noise strength function: always equal to 1
def noise_strength_constant(t):
  return 1

Давайте запустим его и визуализируем:


nsteps = 100
t0 = 0
dt = 0.1
noise_strength_fn = noise_strength_constant
x0 = 0

num_tries = 5
for i in range(num_tries):
  x, t = forward_diffusion_1d(x0, noise_strength_fn, t0, nsteps, dt)

  plt.plot(t, x)
  plt.xlabel('time', fontsize=20)
  plt.ylabel('$x$', fontsize=20)
plt.title('Forward diffusion visualized', fontsize=20)
plt.show()
1d stable diffusion

Мы можем изменить этот процесс диффузии с помощью аналогичного правила обновления:

$$ x(t + \Delta t) = x(t) + \sigma(T - t)^2 \frac{d}{dx}\left[ \log p(x, T-t) \right] \Delta t + \sigma(T-t) \sqrt{\Delta t} \ r $$

Где?

$$ s(x, t) := \frac{d}{dx} \log p(x, t) $$

  • x = шумное изображение в момент t
  • \(p(x, t)\) = плотность вероятности x в момент времени t
  • \(\frac{d}{dx} \) = градиент относительно x
  • \(s(x, t)\) = функция оценки

Это ключевой концептуальный момент в диффузионных моделях и стабильной диффузии. Цель модели состоит в том, чтобы научиться обезвреживать x, перемещая его в области с более высокой вероятностью распределения данных. Почему log(p) вместо p? Это имеет численные преимущества. Вероятности p(x) часто очень малы, особенно в больших размерах.

log d dx

Производная от бревна небольшого значения довольно велика. Кроме того, бревно превращает продукты в суммы, делая градиенты более стабильными. Градиент журнала дает направление, а не величину, которая зависит от абсолютного значения p(x). log p(x) и p(x) равнозначны по оптимизации, но первые гораздо более стабильны в численном отношении. Многие алгоритмы обучения (MLE, score matching) естественно используют log.

Что значит иметь вероятностное распределение изображения? Для этого я отношу вас к вариационным автокодерам (VAE), которые кодируют вход (изображение) как распределение вероятностей (1) центр и (2) стандартное отклонение в скрытом пространстве. Скрытое пространственное представление изображения в VAE - это именно то, что является изученным распределением вероятностей изображения.

На практике мы еще не знаем функцию оценки; вместо этого мы должны ее изучить. Один из способов научиться этому — обучить нейронную сеть «денозировать» образцы с помощью очерняющей цели.

$$ J := \mathbb{E} {t\in (0, T), x 0 \sim p 0(x 0)}\left[ \ \Vert s(x {noised}, t) \sigma^2(t) + (x {noised} - x 0) \Vert^2 2 \ \right] $$

где \(p 0(x 0)\) является нашим целевым распределением (например, фотографии кошек и собак), и где \(x {noised}\) является выборкой целевого распределения (x 0\) после одного шага диффузии, т.е.\(x {noised} - x 0\) Это просто нормально распределенная случайная переменная.

Вот еще один способ написания того же самого, который ближе к фактической реализации. путем замены \[\begin{equation} x {noised} = x 0 + \sigma(t) \epsilon, \; \epsilon\sim \mathcal N(0,I) \end{equation}\] Мы получили эту объективную функцию. \[\begin{equation} J := \mathbb{E} {t\in (0, T), x 0 \sim p 0(x 0), \epsilon \sim \mathcal N(0,I)}\left[ \\Vert s(x 0 + \sigma(t) \epsilon, t) \sigma(t) + \epsilon \Vert^2 2 \ \right] \end{equation}\

символзначение\(J\)Функция потерь для обучения сети оценок \(s \theta \)\(\mathbb{E} {t \in (0,T), x 0 \sim p 0(x 0)}[\cdot] \)Ожидание с течением времени \(t\) и образцы данных \(x 0\)\( x 0 \sim p 0(x 0)\)\(x 0\) извлекается из распределения данных (например, изображений)\( x {\text{noised}} \)Шумная версия \(x 0\) в момент времени (t)\(s(x {\text{noised}}, t)\)Вывод сети с оценкой, приближение \(\nabla x \log p t(x {\text{noized}})\)\(\sigma(t)\)Функция шумового расписания (стандартное отклонение гауссовского шума в момент времени t)\(\Vert \cdot \Vert 2^2 \)Квадратная норма L2 (евклидово расстояние в квадрате)

Мы учимся предсказывать сколько шума было добавлено к каждой части образцаМы должны быть в состоянии сделать это хорошо в любое время. \(t\) в процессе диффузии и для каждого (x 0\) в нашем оригинальном (собаки/кошки/и т.д.) распределении.

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

Зачем умножать на \(\sigma^2(t)\)? В выводах, соответствующих баллам, оптимальный балл связан с шумом, добавленным по \(\sigma^2(t)\):

\[ s \theta(x {\rm noised}, t) \approx - \frac{x {\rm noised} - x 0}{\sigma^2(t)} \.

Умножение на \(\sigma^2(t)\) удаляет масштабирование, поэтому сеть учится предсказывать фактический шум. Интуитивное объяснение:

  • Возьмите чистую точку данных \( x {0} \)
  • Добавьте гауссов шум, чтобы получить \( x {\text{noised}} \)
  • Перейдите \( x {\text{noised}} \) в сеть \(s \theta \)
  • Вычислите, насколько близко \(s \theta(x {\rm noised}, t) \, \sigma^2(t)\) к фактическому шуму \((x {\rm noized} - x 0)\)
  • Среднее значение для всех точек данных и всех времен t

По сути, вы учите сеть, как «обезвредить» шумный образец в любое время.

U-сети

Please login to post comments: