Содержание курса 08 / 33

08 / 33 · Вариационные автоэнкодеры

Варианты VAE: β-VAE и VQ-VAE

Три способа изменить VAE: вес при слагаемом KL, который задаёт, сколько информации может нести код (β-VAE), дискретный код, априорное распределение которого учится потом (VQ-VAE и VQ-VAE-2), и, как дополнительный материал, декодер-поток с точным правдоподобием (VAPNEV).

На этой странице 11

VAE закончился двумя претензиями. Его сэмплы размыты, а фиксированное гауссово априорное распределение лишь приблизительно заполняется кодами, которые на самом деле выдаёт энкодер, так что сэмплы из априорного распределения могут попасть туда, где декодер никогда не обучался. Эта заметка разбирает три ответа. Первый сохраняет модель и меняет целевую функцию: вес β\beta при слагаемом KL решает, сколько информации может нести код. Второй сохраняет автоэнкодер и меняет код: сетка дискретных символов из обучаемого словаря, а априорное распределение подгоняется потом моделью, достаточно сильной, чтобы им соответствовать. Третий сохраняет гауссов код и меняет правдоподобие декодера: точное правдоподобие, вычисленное нормализующим потоком (normalizing flow), вместо квадратичной ошибки, просуммированной по пикселям.

Обозначения. Как в заметке о VAE: изображение xx, код zz, энкодер qφ(z∣x)q_\varphi(z \mid x), декодер pθ(x∣z)p_\theta(x \mid z), априорное распределение p(z)p(z). sg[⋅]\mathrm{sg}[\cdot] — оператор остановки градиента (stop-gradient): при прямом проходе возвращает аргумент, а при обратном имеет нулевую производную. Словарь кодов (codebook) — набор из KK векторов e1,…,eK∈Rde_1, \dots, e_K \in \mathbb R^d.

Три способа изменить VAE#

ELBO одного изображения состоит из двух слагаемых:

L(x)=Eqφ(z∣x)[log⁡pθ(x∣z)]⏟реконструкция−DKL(qφ(z∣x) ∥ p(z))⏟KL к априорному.\mathcal L(x) = \underbrace{\mathbb E_{q_\varphi(z \mid x)}\big[\log p_\theta(x \mid z)\big]}_{\text{реконструкция}} - \underbrace{D_{\mathrm{KL}}\big(q_\varphi(z \mid x)\,\|\,p(z)\big)}_{\text{KL к априорному}} .

Первое хочет, чтобы код сообщал об xx как можно больше; второе берёт плату за каждый сообщённый бит. Изменить их баланс — это β-VAE. Изменить то, чем является код, — непрерывным гауссовым или одним символом из KK, — это VQ-VAE. Одно не зависит от другого: первое двигает точку вдоль компромисса, второе меняет то, где находится трудность генерации. Третье изменение, дополнительное, в конце заметки, сохраняет оба слагаемых и заменяет вид самого слагаемого реконструкции, pθ(x∣z)p_\theta(x \mid z).

β-VAE: вес при слагаемом KL#

β-VAE (Higgins et al., 2017) максимизирует

Lβ(x)=Eqφ(z∣x)[log⁡pθ(x∣z)]−β DKL(qφ(z∣x) ∥ p(z)).\mathcal L_\beta(x) = \mathbb E_{q_\varphi(z \mid x)}\big[\log p_\theta(x \mid z)\big] - \beta\, D_{\mathrm{KL}}\big(q_\varphi(z \mid x)\,\|\,p(z)\big) .

β=1\beta = 1 — обычный VAE. При β>1\beta > 1 целевая функция по-прежнему нижняя оценка log⁡pθ(x)\log p_\theta(x), потому что вычитает неотрицательной величины больше, чем ELBO; при β<1\beta < 1 она может превысить log⁡pθ(x)\log p_\theta(x) и оценкой уже не является. В обоих случаях β\beta меняет то, какую модель предпочитает обучение, а не только масштаб функции потерь.

Скорость и искажение#

После усреднения по данным у двух слагаемых появляются имена из теории информации (Alemi et al., 2018). Скорость (rate) — средняя KL,

R=Ex DKL(qφ(z∣x) ∥ p(z)),R = \mathbb E_{x}\, D_{\mathrm{KL}}\big(q_\varphi(z \mid x)\,\|\,p(z)\big),

измеряемая в натах (nats). Она ограничивает сверху взаимную информацию между изображениями и их кодами при данном энкодере: тождество, на котором это держится, — скорость равна взаимной информации плюс KL от агрегированного апостериорного распределения к априорному, — выведено в заметке о VAE. Искажение (distortion) D=−ExEqφ(z∣x)log⁡pθ(x∣z)D = -\mathbb E_x \mathbb E_{q_\varphi(z \mid x)} \log p_\theta(x \mid z) — средняя функция потерь реконструкции. Отрицательный ELBO равен D+RD + R, а β-VAE минимизирует D+βRD + \beta R — лагранжиан задачи «реконструировать как можно лучше при скорости не выше заданной». Каждое β\beta выбирает одну точку компромисса; β=1\beta = 1 — та, что лучше всего оценивает правдоподобие.

Разобранный пример: одна латентная координата#

Чтобы увидеть компромисс в числах, возьмём одну латентную координату, стандартное нормальное априорное распределение p(z)=N(0,1)p(z) = \mathcal N(0, 1) и фиксированный линейный декодер p(x∣z)=N(wz,σ2)p(x \mid z) = \mathcal N(w z, \sigma^2) с w=1w = 1 и σ2=0.1\sigma^2 = 0.1. Данные порождены этой же моделью, так что x∼N(0,w2+σ2)=N(0,1.1)x \sim \mathcal N(0, w^2 + \sigma^2) = \mathcal N(0, 1.1). Фиксированный декодер позволяет увидеть, что β\beta делает именно с энкодером. Пусть энкодер — q(z∣x)=N(m,v)q(z \mid x) = \mathcal N(m, v). Для одного xx β-целевая функция с точностью до констант равна

J(m,v)=−(x−wm)2+w2v2σ2−β2(v+m2−1−ln⁡v),J(m, v) = -\frac{(x - w m)^2 + w^2 v}{2\sigma^2} - \frac{\beta}{2}\big(v + m^2 - 1 - \ln v\big),

где использованы Eq(x−wz)2=(x−wm)2+w2v\mathbb E_q (x - w z)^2 = (x - wm)^2 + w^2 v и KL к стандартному нормальному распределению в замкнутой форме из заметки о VAE. Приравнивая производные к нулю,

∂J∂v=−w22σ2−β2+β2v=0,∂J∂m=w(x−wm)σ2−βm=0,\frac{\partial J}{\partial v} = -\frac{w^2}{2\sigma^2} - \frac{\beta}{2} + \frac{\beta}{2v} = 0, \qquad \frac{\partial J}{\partial m} = \frac{w(x - wm)}{\sigma^2} - \beta m = 0,

получаем оптимальный энкодер

m=ww2+βσ2 x,v=βσ2w2+βσ2.m = \frac{w}{w^2 + \beta\sigma^2}\, x, \qquad v = \frac{\beta\sigma^2}{w^2 + \beta\sigma^2} .

При β=1\beta = 1 это среднее и дисперсия точного апостериорного распределения p(z∣x)p(z \mid x), так что ELBO точен. Усреднение по x∼N(0,1.1)x \sim \mathcal N(0, 1.1) даёт скорость и искажение в виде квадратичной ошибки E(x−wz)2\mathbb E(x - wz)^2:

β\betam/xm / xvvскорость RR, натыискажение E(x−wz)2\mathbb E(x - wz)^2
0.250.9760.0241.890.025
10.9090.0911.200.100
40.7140.2860.550.376
160.3850.6150.131.032

Рост β\beta стягивает код к априорному распределению: среднее тянется к 0, а дисперсия растёт к 1, так что код сообщает об xx меньше, и реконструкция ухудшается. При β=16\beta = 16 искажение 1.03 близко к дисперсии данных 1.1: код почти ничего не несёт. Уменьшение β\beta делает обратное и покупает более чёткие реконструкции ценой большей скорости.

Высокая скорость сама по себе не означает, что код далёк от априорного распределения. Скорость раскладывается на взаимную информацию I(X;Z)I(X; Z) между изображениями и кодами и KL от агрегированного апостериорного распределения q(z)=Ex q(z∣x)q(z) = \mathbb E_x\, q(z \mid x) к априорному. Здесь q(z)=N(0,(m/x)2⋅1.1+v)q(z) = \mathcal N\big(0, (m/x)^2 \cdot 1.1 + v\big): при β=0.25\beta = 0.25 его дисперсия равна 1.071, а рассогласование DKL(q(z) ∥ p(z))D_{\mathrm{KL}}\big(q(z)\,\|\,p(z)\big) составляет 0.001 из 1.89 ната, так что почти вся скорость — информация об xx. Сэмплы из априорного распределения плохи, когда агрегированное апостериорное распределение уходит от априорного или когда декодер ошибается там, куда априорное распределение кладёт массу. В этом игрушечном примере декодер зафиксирован и совпадает с истинной моделью, поэтому β\beta меняет только энкодер, а сэмплы, декодированные из априорного распределения, остаются точными. В VAE, где всё обучается совместно, малое β\beta ослабляет и штраф за рассогласование — так оно и может ухудшить сэмплы из априорного распределения.

Рисунок

β-VAE передвигает точку по кривой «скорость–искажение»

Кривая «скорость–искажение» для β-VAEУбывающая кривая: при росте β скорость падает, искажение растёт. β = 0.25: R = 1.89, D = 0.03; β = 1: R = 1.20, D = 0.10; β = 4: R = 0.55, D = 0.38; β = 16: R = 0.13, D = 1.03.00.40.81.200.511.522.5скорость R, натыискажение E(x − wz)²β = 0.25R 1.89, D 0.03β = 1, обычный VAER 1.20, D 0.10β = 4R 0.55, D 0.38β = 16R 0.13, D 1.03Кривая «скорость–искажение» для β-VAEУбывающая кривая: при росте β скорость падает, искажение растёт. β = 0.25: R = 1.89, D = 0.03; β = 1: R = 1.20, D = 0.10; β = 4: R = 0.55, D = 0.38; β = 16: R = 0.13, D = 1.03.00.40.81.200.511.522.5скорость R, натыискажение E(x − wz)²β = 0.25β = 1β = 4β = 16
Одна латентная координата, фиксированный декодер x | z ~ N(z, 0.1) и данные x ~ N(0, 1.1). Для каждого β энкодер выбран оптимально по формулам в тексте; кривая — все такие точки при β от 0.025 до 100. Скорость R — средняя KL от апостериорного распределения к априорному в натах, искажение — средняя квадратичная ошибка реконструкции. β = 1 (обычный VAE) даёт точное апостериорное распределение и искажение ровно 0.1, шум декодера. При β = 4 скорость падает меньше чем до половины, а ошибка растёт почти вчетверо.

Что даёт β, а что нет#

Higgins et al. (2017) сообщают, что при β>1\beta > 1 отдельные латентные координаты начинают следить за отдельными факторами изменчивости (положение, масштаб, поворот спрайта), и называют это распутыванием (disentanglement). Распутанное представление — такое, в котором отдельная латентная координата чувствительна к изменениям одного порождающего фактора и относительно инвариантна к изменениям остальных (раздел 1). Важны обе половины определения: координата должна следовать за своим фактором и мало меняться, когда меняется другой фактор. На лицах CelebA при β=250\beta = 250 отдельные координаты поворачивают голову, меняют выражение лица в сторону улыбки или меняют причёску, а остальное лицо остаётся прежним; в обычном VAE (β=1\beta = 1) координата, которая поворачивает голову, меняет заодно выражение лица, очки и пол (рисунок 1). Такой код позволил бы редактировать по одному признаку за раз, переиспользовать факторы в новых задачах, рассуждать о не встречавшихся сочетаниях известных факторов и замечать входы, которые не подходят ни под одно известное сочетание (раздел 1).

Механизм — давление тратить мало скорости: факторизованное априорное распределение дешевле всего подогнать апостериорным с независимыми координатами. β<1\beta < 1 ослабляет это давление: такое значение покупает более чёткие реконструкции, и целевая функция поощряет распутанный код ещё меньше. Эффект β>1\beta > 1 тоже не гарантирован. Locatello et al. (2019) доказывают, что без учителя или индуктивных смещений (inductive biases) распутывание нельзя идентифицировать по данным, и в исследовании более чем 12 000 обученных моделей находят, что начальные значения генератора случайных чисел (seeds) и гиперпараметры значат больше, чем выбор между распутывающими целевыми функциями. Burgess et al. (2018) заменяют фиксированный вес на целевую скорость CC, которая растёт по ходу обучения, Eqlog⁡pθ(x∣z)−γ ∣DKL−C∣\mathbb E_q \log p_\theta(x \mid z) - \gamma\,\lvert D_{\mathrm{KL}} - C \rvert, так что коду разрешается по одному нату больше за раз. Полезное прочтение β-VAE — то, что выше: ручка регулировки скорости, а не выключатель интерпретируемости.

VQ-VAE: дискретный латентный код#

VQ-VAE (van den Oord, Vinyals and Kavukcuoglu, 2017) отказывается от непрерывного кода. Энкодер по-прежнему выдаёт карту векторов ze(x)∈Rh×w×dz_e(x) \in \mathbb R^{h \times w \times d}, но перед подачей в декодер каждый вектор заменяется ближайшим элементом обучаемого словаря:

k∗(i)=arg⁡min⁡k∥ze(x)i−ek∥2,zq(x)i=ek∗(i).k^*(i) = \arg\min_k \big\lVert z_e(x)_i - e_k \big\rVert^2, \qquad z_q(x)_i = e_{k^*(i)} .

Код изображения — сетка индексов k∗(i)k^*(i): для изображений 32×3232 \times 32 ниже это 64 целых числа от 1 до 512 на нижнем уровне. В терминах ELBO апостериорное распределение q(z=k∣x)q(z = k \mid x) — единица в k∗k^*, и при равномерном априорном распределении на KK кодах его KL равна log⁡K\log K на позицию, то есть константе. Слагаемое KL выпадает из обучения, и VQ-VAE обучается как обычный автоэнкодер с квантованным узким местом.

Рисунок

Векторное квантование: ближайший вектор словаря

Ячейки словаря на плоскостиКвадрат, разделённый на три ячейки линиями x = 1, y = 1 и y = x. В каждой ячейке свой вектор словаря и несколько выходов энкодера. Выход (1.4, 0.3) соединён пунктиром с ближайшим вектором e₂ = (2, 0).e₁e₃выход энкодера zezq = e₂каждый выход энкодера заменяетсяближайшим вектором словаря:плоскость делится на ячейки Вороного‖ze − e₂‖² = 0.45 — наименьшее‖ze − e₁‖² = 2.05‖ze − e₃‖² = 4.85Ячейки словаря на плоскостиКвадрат, разделённый на три ячейки линиями x = 1, y = 1 и y = x. В каждой ячейке свой вектор словаря и несколько выходов энкодера. Выход (1.4, 0.3) соединён пунктиром с ближайшим вектором e₂ = (2, 0).e₁e₃выход энкодера zezq = e₂каждый выход энкодера заменяетсяближайшим вектором словаря:плоскость делится на ячейки Вороного‖ze − e₂‖² = 0.45 — наименьшее‖ze − e₁‖² = 2.05‖ze − e₃‖² = 4.85
Словарь из трёх векторов e₁ = (0, 0), e₂ = (2, 0), e₃ = (0, 2) делит плоскость на три ячейки, границы которых — серединные перпендикуляры между векторами. Точки — выходы энкодера, окрашенные по своей ячейке. Выход (1.4, 0.3) из разобранного примера ближе всего к e₂, поэтому декодер получает e₂. Слагаемое привязки тянет этот выход к e₂, а обновление словаря сдвигает e₂ к среднему выходов, попавших в его ячейку.

Обучение через argmin#

У argmin нет полезного градиента: малое изменение zez_e либо оставляет тот же eke_k, либо перескакивает на другой. VQ-VAE использует прямой проброс градиента (straight-through estimator, Bengio, Léonard and Courville, 2013): при прямом проходе декодер получает zqz_q, при обратном градиент по zqz_q без изменений копируется в zez_e. В коде это одна строка, z_q = z_e + (z_q - z_e).detach(): значение — zqz_q, производная — как у zez_e. Копия — заменитель, а не производная квантования. Внутри ячейки квантователь постоянен, поэтому его настоящий якобиан равен нулю; на границе ячейки он скачет. Прямой проброс подставляет вместо этого якобиана единичную матрицу, и это остаётся подстановкой даже тогда, когда zez_e лежит точно на ek∗e_{k^*}: настоящая производная там всё равно нулевая. Близость лишь делает эвристику правдоподобной: градиент декодера, вычисленный в ek∗e_{k^*}, тогда разумно подсказывает, куда сдвигать zez_e. В функции потерь три слагаемых:

L=−log⁡pθ(x∣zq(x))+∥sg[ze(x)]−e∥2+βc∥ze(x)−sg[e]∥2,\mathcal L = -\log p_\theta\big(x \mid z_q(x)\big) + \big\lVert \mathrm{sg}[z_e(x)] - e \big\rVert^2 + \beta_c \big\lVert z_e(x) - \mathrm{sg}[e] \big\rVert^2 ,

просуммированных по позициям, где e=ek∗e = e_{k^*}. Слагаемое реконструкции обучает декодер и, через прямой проброс, энкодер. Слагаемое словаря двигает ee к выходу энкодера; энкодер оно не трогает. Слагаемое привязки (commitment loss) двигает выход энкодера к ee; словарь оно не трогает. Без него ничто не мешает выходам энкодера уходить от словаря быстрее, чем словарь успевает за ними. В статье βc=0.25\beta_c = 0.25, и результаты к нему нечувствительны.

Разобранный пример: один шаг квантования#

Возьмём d=2d = 2, K=3K = 3, словарь e1=(0,0)e_1 = (0, 0), e2=(2,0)e_2 = (2, 0), e3=(0,2)e_3 = (0, 2) и один выход энкодера ze=(1.4,0.3)z_e = (1.4, 0.3) — красную точку на рисунке. Квадраты расстояний:

∥ze−e1∥2=1.96+0.09=2.05,∥ze−e2∥2=0.36+0.09=0.45,∥ze−e3∥2=1.96+2.89=4.85.\lVert z_e - e_1\rVert^2 = 1.96 + 0.09 = 2.05, \quad \lVert z_e - e_2\rVert^2 = 0.36 + 0.09 = 0.45, \quad \lVert z_e - e_3\rVert^2 = 1.96 + 2.89 = 4.85 .

Ближайший вектор — e2e_2, поэтому декодер получает zq=(2,0)z_q = (2, 0), а код — индекс 2. Слагаемое словаря равно 0.450.45, слагаемое привязки — 0.25⋅0.45=0.11250.25 \cdot 0.45 = 0.1125: то же расстояние, но градиенты направлены в противоположные стороны. Если градиент функции потерь декодера по zqz_q равен gg, то энкодер получает в zez_e ровно gg плюс градиент привязки 2βc(ze−e2)=0.5⋅(−0.6,0.3)=(−0.3,0.15)2\beta_c(z_e - e_2) = 0.5 \cdot (-0.6, 0.3) = (-0.3, 0.15), направленный от e2e_2 к zez_e, так что шаг спуска сдвигает zez_e к e2e_2.

Словарь как онлайн-k-means#

Слагаемое словаря двигает каждый eke_k к выходам энкодера, отнесённым к нему, — это шаг k-means. Приложение статьи о VQ-VAE заменяет его экспоненциальными скользящими средними. Для каждого кода хранятся счётчик NkN_k и сумма mkm_k, которые обновляются по nkn_k выходам, отнесённым к коду kk в батче,

Nk←γNk+(1−γ) nk,mk←γ mk+(1−γ)∑i: k∗(i)=kze(x)i,ek=mkNk,N_k \leftarrow \gamma N_k + (1 - \gamma)\, n_k, \qquad m_k \leftarrow \gamma\, m_k + (1 - \gamma) \sum_{i:\, k^*(i) = k} z_e(x)_i, \qquad e_k = \frac{m_k}{N_k},

с γ=0.99\gamma = 0.99, а слагаемое словаря убирается из функции потерь. Каждый eke_k тогда — скользящее среднее своей ячейки, то есть центроид k-means, вычисляемый онлайн. При N2=10N_2 = 10, m2=(20,0)m_2 = (20, 0) (так что e2=(2,0)e_2 = (2, 0)) и батче из двух выходов (1.4,0.3)(1.4, 0.3) и (1.8,−0.1)(1.8, -0.1), отнесённых к нему, обновление даёт N2=9.92N_2 = 9.92, m2=(19.832,0.002)m_2 = (19.832, 0.002) и e2=(1.9992,0.0002)e_2 = (1.9992, 0.0002): маленький шаг к среднему батча (1.6,0.1)(1.6, 0.1), как и положено скользящему среднему с γ=0.99\gamma = 0.99.

Слабое место этой схемы — то же, что у k-means: код, который не выбирает ни один выход, не получает обновлений и остаётся там, где был инициализирован, — мёртвый код (dead code). При многих мёртвых кодах фактический словарь мал. Практические исправления перезапускают неиспользуемые коды в недавних выходах энкодера, как в Jukebox (Dhariwal et al., 2020), или ищут коды в низкоразмерном нормированном пространстве, как в ViT-VQGAN (Yu et al., 2022). Реализации часто добавляют к счётчикам малую константу (сглаживание Лапласа), чтобы не делить на ноль для неиспользуемых кодов; оживить их это не помогает.

Куда делось априорное распределение#

Поскольку слагаемое KL постоянно, обучение оставляет априорное распределение равномерным, и независимое равномерное сэмплирование кодов дало бы изображение из случайных кусков. Поэтому VQ-VAE подгоняет априорное распределение после автоэнкодера: обучающая выборка кодируется в сетки индексов, и на них обучается авторегрессионная модель — в статье PixelCNN, — предсказывающая каждый индекс по предыдущим. Генерация сэмплирует сетку из этого распределения и декодирует её. Двухэтапная структура — суть метода. Автоэнкодер отвечает за пиксели, а априорной модели нужно описать сетку в десятки раз меньше, состоящую из символов, — там авторегрессионные модели сильны; как они устроены, разбирает заметка об авторегрессионных моделях.

VQ-VAE-2: два уровня кодов#

Одна сетка должна нести и общую компоновку, и мелкую текстуру. VQ-VAE-2 (Razavi, van den Oord and Vinyals, 2019) использует две: грубую верхнюю для компоновки и более мелкую нижнюю для деталей, которая квантуется, уже видя верхнюю. Для ImageNet 256×256256 \times 256 сетки имеют размер 32×3232 \times 32 и 64×6464 \times 64 по 512 кодов; для FFHQ 1024×10241024 \times 1024 уровней три. Априорное распределение тоже иерархическое: авторегрессионная модель по верхним кодам, в которой каузальное самовнимание чередуется с гейтированными свёртками, и условная модель по нижним кодам при данных верхних — без внимания, чтобы большая сетка оставалась посильной. Статья к тому же отбирает сэмплы предобученным классификатором ImageNet — шаг отбраковки, который меняет разнообразие на качество.

Рисунок

Небольшой VQ-VAE-2: две карты кодов

Обучение и генерация в двухуровневом VQ-VAEОбучение: изображение 32×32 проходит нижний энкодер до карты 8×8, верхний энкодер сжимает её до 4×4, верхняя карта квантуется, раскодируется до 8×8, объединяется с признаками нижнего энкодера и квантуется как нижняя карта; декодер восстанавливает изображение из увеличенных верхних кодов и нижних кодов. Генерация: PixelCNN сэмплирует 16 верхних кодов, условный PixelCNN — 64 нижних, декодер превращает их в изображение.изображение32×32×3нижний энкодер÷4 → 8×8верхний энкодер÷2 → 4×4квантование верхакоды 4×4 из 512верхний декодер4×4 → 8×8квантование низакоды 8×8 из 512декодерверх ↑ + низреконструкция32×32×3PixelCNN (верх)16 кодов по одномуусловный PixelCNN64 нижних кодадекодерновое изображениеобучениегенерацияОбучение и генерация в двухуровневом VQ-VAEОбучение: изображение 32×32 проходит нижний энкодер до карты 8×8, верхний энкодер сжимает её до 4×4, верхняя карта квантуется, раскодируется до 8×8, объединяется с признаками нижнего энкодера и квантуется как нижняя карта; декодер восстанавливает изображение из увеличенных верхних кодов и нижних кодов. Генерация: PixelCNN сэмплирует 16 верхних кодов, условный PixelCNN — 64 нижних, декодер превращает их в изображение.изображение32×32×3нижний энкодер÷4 → 8×8верхний энкодер÷2 → 4×4квантование верхакоды 4×4 из 512верхний декодер4×4 → 8×8квантование низакоды 8×8 из 512декодерверх ↑ + низреконструкция32×32×3PixelCNN (верх)16 кодов по одномуусловный PixelCNN64 нижних кодадекодерновое изображениеобучениегенерация
Сверху — путь обучения для изображений CIFAR-10 32×32. Нижний энкодер уменьшает изображение в 4 раза, верхний — ещё в 2. Верхняя карта 4×4 квантуется первой; её раскодированная версия вместе с признаками нижнего энкодера определяет нижнюю карту 8×8. Декодер получает увеличенные верхние коды и нижние коды. Снизу — генерация: верхние коды сэмплируются PixelCNN по одному, нижние — условным PixelCNN, который видит верхние, и декодер превращает пару карт в изображение. Обе карты — индексы в словаре из 512 векторов размерности 64.

Сколько битов#

Рисунок показывает небольшую версию для изображений CIFAR-10 32×3232 \times 32: верхняя сетка 4×44 \times 4 и нижняя 8×88 \times 8, по 512 кодов в каждой. Изображение занимает 32⋅32⋅3=307232 \cdot 32 \cdot 3 = 3072 байта, или 24 576 бит. Его код — 16+64=8016 + 64 = 80 индексов по log⁡2512=9\log_2 512 = 9 бит, то есть 720 бит, примерно в 34 раза меньше. Стоимость сэмплирования масштабируется так же: авторегрессионной модели по сырым субпикселям нужны 3072 последовательных шага на изображение, двум априорным моделям — 16+64=8016 + 64 = 80. В масштабе статьи, 256×256256 \times 256, разрыв — 196 608196\,608 субпикселей против 322+642=512032^2 + 64^2 = 5120 кодов.

VAPNEV: правдоподобие потока вместо попиксельной реконструкции#

Дополнительный материал: декодер-поток с точным правдоподобием и его условная версия. Остальная часть заметки на него не опирается.

Изменения выше не трогают правдоподобие декодера. С факторизованным гауссовским декодером −log⁡pθ(x∣z)-\log p_\theta(x \mid z) — это квадратичная ошибка, просуммированная по пикселям, и лучший выход декодера для кода — среднее всех изображений, которые ему подходят: отсюда размытость VAE. VAPNEV (Agrawal and Dukkipati, 2016), анаграмма VAE-NVP, сохраняет гауссов код и ELBO и заменяет это слагаемое точным правдоподобием, которое вычисляется зависящим от кода потоком real NVP (Dinh, Sohl-Dickstein and Bengio, 2017). Подробно потоки разбираются позже в курсе, в заметке о нормализующих потоках; этому разделу нужны только формула замены переменных и слой связи (coupling layer), и обе вещи мы здесь повторяем.

Обозначения. y∈RDy \in \mathbb R^D — промежуточная переменная того же размера, что и изображение. Для каждого кода zz отображение fz:y↦xf_z: y \mapsto x обратимо; это поток, записанный в принятом в курсе направлении из латентного пространства в данные, с обратным отображением fz−1:x↦yf_z^{-1}: x \mapsto y. Agrawal и Dukkipati записывают отображение в направлении из данных в латентное пространство.

Правдоподобие декодера как замена переменных#

Сеть-декодер не выдаёт изображение. Она выдаёт среднее и дисперсии гауссианы над yy, а поток превращает yy в изображение:

y∣z∼N(μθ(z),σθ2(z)),x=fz(y).y \mid z \sim \mathcal N\big(\mu_\theta(z), \sigma_\theta^2(z)\big), \qquad x = f_z(y).

По формуле замены переменных правдоподобие изображения вычисляется точно (раздел 3.1, формулы 10–11):

log⁡pθ(x∣z)=log⁡N(fz−1(x); μθ(z),σθ2(z))+log⁡∣det⁡∂fz−1(x)∂x∣.\begin{aligned} \log p_\theta(x \mid z) ={}& \log\mathcal N\big(f_z^{-1}(x);\, \mu_\theta(z), \sigma_\theta^2(z)\big) \\ &+ \log\left|\det\frac{\partial f_z^{-1}(x)}{\partial x}\right| . \end{aligned}

ELBO сохраняет свой вид, только вместо квадратичной ошибки в нём стоит это слагаемое:

L(x)=Eqφ(z∣x)[log⁡N(fz−1(x); μθ(z),σθ2(z))+log⁡∣det⁡∂fz−1(x)∂x∣]−DKL(qφ(z∣x) ∥ p(z)).\begin{aligned} \mathcal L(x) ={}& \mathbb E_{q_\varphi(z \mid x)}\Big[\log\mathcal N\big(f_z^{-1}(x);\, \mu_\theta(z), \sigma_\theta^2(z)\big) \\ &\qquad + \log\left|\det\frac{\partial f_z^{-1}(x)}{\partial x}\right|\Big] \\ &- D_{\mathrm{KL}}\big(q_\varphi(z \mid x)\,\|\,p(z)\big). \end{aligned}

Гауссиана теперь живёт в пространстве yy, а не пикселей. Поток перемешивает пиксели, поэтому модель может представить зависимости между пикселями при данном коде, чего не может факторизованный гауссовский декодер: он считает их независимым шумом вокруг одного среднего изображения. Если fzf_z — тождественное отображение, модель становится обычным VAE с гауссовским декодером с обучаемыми дисперсиями. Формула верна и тогда, когда поток не зависит от zz; код тогда действует только через μθ\mu_\theta и σθ\sigma_\theta (раздел 3.1).

Условные слои связи#

Обратное отображение fz−1f_z^{-1} — стопка условных слоёв связи (conditional coupling layers; раздел 3.2). Как в аффинном слое связи, вход слоя разбивается на две части xax_a и xbx_b: первая проходит без изменений, а вторая масштабируется и сдвигается функциями от первой. Здесь эти функции видят ещё и код (формулы 12–13):

ya=xa,yb=xb⊙exp⁡(sz(xa))+tz(xa).y_a = x_a, \qquad y_b = x_b \odot \exp\big(s_z(x_a)\big) + t_z(x_a).

При фиксированном zz матрица Якоби по-прежнему треугольная, log⁡∣det⁡∣=∑isz(xa)i\log\lvert\det\rvert = \sum_i s_z(x_a)_i, а обратное преобразование — xb=(yb−tz(ya))⊙exp⁡(−sz(ya))x_b = \big(y_b - t_z(y_a)\big) \odot \exp\big(-s_z(y_a)\big) (формулы 14–15). Для обращения нужен код, и он всегда известен: при обучении — от энкодера, при генерации — из априорного распределения.

Масштаб объединяет сеть s1s_1 от неизменной части (в статье — два остаточных блока) с небольшой сетью s2s_2 из транспонированных свёрток (transposed convolutions), которая превращает низкоразмерный код в карту той же формы (формула 16):

sz(xa)=κ⊙s1(xa)⊙s2(z)+β1⊙s1(xa)+β2⊙s2(z)+b.\begin{aligned} s_z(x_a) ={}& \kappa \odot s_1(x_a) \odot s_2(z) + \beta_1 \odot s_1(x_a) \\ &+ \beta_2 \odot s_2(z) + b . \end{aligned}

Векторы κ\kappa, β1\beta_1, β2\beta_2 и bb обучаются отдельно для каждого канала и распространяются (broadcasting) по позициям, а сдвиг tzt_z строится так же из собственной пары сетей. Слагаемое с произведением позволяет коду включать и выключать признаки xax_a, а прямое слагаемое даёт каждому слою короткий путь к коду. С этими короткими путями авторы связывают сильное влияние кода и хорошие результаты потока с меньшим числом слоёв.

Разобранный пример: одно точное вычисление правдоподобия#

Игрушечный случай: D=2D = 2 и скалярный код z=0.5z = 0.5. Один условный слой связи использует sz(xa)=xazs_z(x_a) = x_a z и tz(xa)=xa−zt_z(x_a) = x_a - z, а декодер выдаёт μθ(z)=(z,2z)=(0.5,1.0)\mu_\theta(z) = (z, 2z) = (0.5, 1.0) и σθ=(1,0.5)\sigma_\theta = (1, 0.5). Возьмём изображение x=(0.4,1.0)x = (0.4, 1.0).

  1. Переход к yy. ya=0.4y_a = 0.4. Слой вычисляет s=0.4⋅0.5=0.2s = 0.4 \cdot 0.5 = 0.2 и t=0.4−0.5=−0.1t = 0.4 - 0.5 = -0.1, так что yb=1.0⋅e0.2−0.1=1.1214y_b = 1.0 \cdot e^{0.2} - 0.1 = 1.1214.
  2. Гауссовское слагаемое. log⁡N(0.4; 0.5,12)+log⁡N(1.1214; 1.0,0.52)=−0.9239−0.2553=−1.1792\log\mathcal N(0.4;\, 0.5, 1^2) + \log\mathcal N(1.1214;\, 1.0, 0.5^2) = -0.9239 - 0.2553 = -1.1792.
  3. Логарифм определителя. s=0.2s = 0.2: слой растягивает направление xbx_b в e0.2e^{0.2} раз, поэтому плотность xx в e0.2e^{0.2} раз больше плотности yy.
  4. Итого. log⁡pθ(x∣z)=−1.1792+0.2=−0.9792\log p_\theta(x \mid z) = -1.1792 + 0.2 = -0.9792 ната.

В обратную сторону xb=(1.1214+0.1) e−0.2=1.0x_b = (1.1214 + 0.1)\, e^{-0.2} = 1.0: при известном zz слой обращается точно.

Обучение, сэмплирование и результаты#

  • Обучение. Модель максимизирует ELBO с помощью Adam. Авторы наблюдали, как слагаемое KL в начале обучения уходит в ноль, — это коллапс апостериорного распределения (posterior collapse) при декодере, достаточно сильном, чтобы моделировать изображения без кода, — и боролись с этим отжигом KL (KL annealing) из Bowman et al. (2016), раздел 3.1: вес при слагаемом KL начинается с нуля и растёт до единицы по ходу обучения (раздел 3.3).
  • Непрерывные данные. Потоку нужны непрерывные входы. 8-битные изображения проходят деквантование (dequantization) равномерным шумом (см. врезку о дискретных данных), масштабируются в [0,1][0, 1] и отображаются по формуле x′=logit⁡(α+(1−α) x)x' = \operatorname{logit}\big(\alpha + (1 - \alpha)\,x\big) с α=0.05\alpha = 0.05, а оценка поправляется на логарифм якобиана этой предобработки, чтобы она относилась к самим изображениям (раздел 4.1). Как потоки применяются к изображениям, разбирается в заметке Архитектуры потоков.
  • Сэмплирование. Берём z∼N(0,I)z \sim \mathcal N(0, I), затем y∼N(μθ(z),σθ2(z))y \sim \mathcal N(\mu_\theta(z), \sigma_\theta^2(z)) и возвращаем x=fz(y)x = f_z(y) (раздел 3.4). Декодер VAE тоже задаёт распределение, но его сэмплы для одного кода различаются лишь независимым шумом в пикселях, поэтому обычно показывают только его среднее. Здесь шум в yy проходит через поток, который смешивает пиксели, поэтому один код даёт разные изображения; y=μθ(z)y = \mu_\theta(z) даёт одно изображение на код. Реконструкция устроена так же, только zz берётся от энкодера (раздел 3.5).
  • Архитектура (раздел 4.2). Восьмислойный свёрточный энкодер и восьмислойный декодер из транспонированных свёрток, код размерности 256 и многомасштабный real NVP с двумя масштабами. На каждом масштабе 3 условных слоя связи с шахматными масками и 3 с поканальными масками; в остаточных блоках первого масштаба 64 фильтра, второго — 128.

Результаты на тестовой выборке в битах на размерность (bits per dimension), таблицы 1–2; чем меньше, тем лучше, а << отмечает верхнюю оценку, полученную из ELBO:

МодельCIFAR-10CelebA
PixelRNN3.00—
VAE с обратным авторегрессионным потоком (IAF)<3.28< 3.28—
Real NVP3.493.02
Convolutional DRAW<3.59< 3.59—
VAPNEV<3.55< 3.55<2.8< 2.8

На CIFAR-10 VAE с одним стохастическим слоем и таким правдоподобием примерно наравне с real NVP, у которого 8 остаточных блоков на слой связи против 2, и его оценка немного ниже, чем у convolutional DRAW — VAE с несколькими стохастическими слоями и рекуррентностью. Он остаётся позади авторегрессионных моделей и VAE с апостериорным распределением на основе потока. На CelebA он обходит real NVP, используя 2 масштаба вместо 4 (раздел 4.4). Реконструкции сохраняют высокоуровневое содержание: позу, цвет фона, цвет волос и выражение лица (рисунки 3–4). Биты на размерность — та же мера, что в заметке об авторегрессионных моделях.

Условный VAPNEV#

Agrawal и Dukkipati предлагают условное моделирование плотности как расширение, но не реализуют его (раздел 5). Конструкция та же, что у условного VAE. Для изображения xx с условием cc — у CelebA это 40 бинарных атрибутов — сделаем условными энкодер, qφ(z∣x,c)q_\varphi(z \mid x, c), гауссиану декодера, N(μθ(z,c),σθ2(z,c))\mathcal N\big(\mu_\theta(z, c), \sigma_\theta^2(z, c)\big), и слои связи, у которых ветвь кода s2s_2 (и её аналог для сдвига) получает zz и cc вместе. Обозначим получившийся поток fz,cf_{z,c} и оставим априорное распределение p(z)=N(0,I)p(z) = \mathcal N(0, I). Оценка принимает вид

log⁡pθ(x∣c)≥Eqφ(z∣x,c)[log⁡N(fz,c−1(x); μθ(z,c),σθ2(z,c))+log⁡∣det⁡∂fz,c−1(x)∂x∣]−DKL(qφ(z∣x,c) ∥ p(z)).\begin{aligned} \log p_\theta(x \mid c) \ge{}& \mathbb E_{q_\varphi(z \mid x, c)}\Big[\log\mathcal N\big(f_{z,c}^{-1}(x);\, \mu_\theta(z, c), \sigma_\theta^2(z, c)\big) \\ &\qquad + \log\left|\det\frac{\partial f_{z,c}^{-1}(x)}{\partial x}\right|\Big] \\ &- D_{\mathrm{KL}}\big(q_\varphi(z \mid x, c)\,\|\,p(z)\big). \end{aligned}

Сэмплирование фиксирует атрибуты, берёт zz из априорного распределения, берёт yy из гауссианы декодера N(μθ(z,c),σθ2(z,c))\mathcal N\big(\mu_\theta(z, c), \sigma_\theta^2(z, c)\big) и возвращает x=fz,c(y)x = f_{z,c}(y). Если изменить один атрибут, сохранив zz, мы запрашиваем то же лицо с изменённым атрибутом — в той мере, в какой код не вобрал в себя сам атрибут.

Что изменилось#

VAEβ-VAEVQ-VAE / VQ-VAE-2VAPNEV
Коднепрерывный, гауссовнепрерывный, гауссовсетка индексов в словаренепрерывный, гауссов
Целевая функцияELBOреконструкция − β · KLреконструкция + словарь + привязкаELBO с точным правдоподобием потока
Роль априорного распределенияфиксированное N(0,I)\mathcal N(0, I), задаётся KLто же, с весом β\betaравномерное при обучении; потом обучается авторегрессионной модельюфиксированное N(0,I)\mathcal N(0, I), задаётся KL
Градиент через кодрепараметризациярепараметризацияпрямой пробросрепараметризация
Сэмплированиедекодировать z∼N(0,I)z \sim \mathcal N(0, I)то жеавторегрессионно сэмплировать коды, затем декодироватьдекодировать zz в гауссиану над yy, сэмплировать yy, применить поток
Типичная бедаразмытость, дыры в априорномсам компромисс «скорость–искажение»мёртвые коды, медленная последовательная априорная модельколлапс KL без отжига, дорогой декодер в полном разрешении

Ограничения#

  • β двигает вдоль компромисса, но не избавляет от него. Меньшее искажение стоит скорости. Скорость — это в основном информация об изображении и не обязательно рассогласование с априорным распределением; плохие сэмплы из априорного распределения возникают, когда от него уходит агрегированное апостериорное распределение, а малое β\beta штрафует за это слабее. Распутывание — возможный побочный эффект, а не свойство целевой функции.
  • Прямой проброс градиента — заменитель. Он использует единичный якобиан там, где настоящая производная квантователя равна нулю, поэтому точным градиентом он не бывает никогда; слагаемое привязки держит zez_e рядом с его вектором словаря, и это делает подстановку разумной, но не точной.
  • Схлопывание словаря. Без перезапусков или нормированного поиска заметная доля кодов может остаться неиспользуемой.
  • Двухэтапное обучение. Априорная модель подгоняется к кодам замороженного автоэнкодера; ошибки первого этапа, например сетку кодов, которую трудно предсказывать, второй исправить не может.
  • Декодер-поток силён и дорог. Декодер VAPNEV может моделировать изображения без кода, поэтому слагаемое KL схлопывается, если не применять отжиг, а его поток работает в полном разрешении изображения, что обходится гораздо дороже декодера из транспонированных свёрток.
  • Последовательное сэмплирование. Авторегрессионная априорная модель сэмплирует по одному индексу. Сетка меньше пикселей, но всё равно последовательна; дальнейшие работы заменяют априорную модель трансформерами по тем же кодам или диффузией в непрерывном латентном пространстве (латентная диффузия).

Итоги#

  • β-VAE умножает слагаемое KL на β\beta и двигает модель вдоль кривой «скорость–искажение»: β>1\beta > 1 даёт меньшую скорость и худшую реконструкцию, β<1\beta < 1 — наоборот. β=1\beta = 1 возвращает стандартную ELBO, β>1\beta > 1 максимизирует более слабую нижнюю оценку, а при β<1\beta < 1 целевая функция может и не оценивать правдоподобие снизу.
  • VQ-VAE заменяет гауссов код ближайшим вектором словаря. KL становится константой, argmin преодолевается прямым пробросом градиента, а функция потерь добавляет слагаемые словаря и привязки — или EMA-обновление, превращающее словарь в онлайн-k-means.
  • Априорное распределение обучается после автоэнкодера авторегрессионной моделью по сетке кодов. VQ-VAE-2 использует две сетки — грубую для компоновки и мелкую для деталей — и по априорной модели на каждую.
  • VAPNEV сохраняет гауссов код и ELBO и заменяет попиксельную реконструкцию точным правдоподобием потока real NVP, у которого базовая гауссиана и слои связи зависят от кода. Чтобы код продолжал использоваться, нужен отжиг KL. Условная версия добавляет метку в энкодер, декодер и слои связи.

Ноутбук#

Часть про VQ-VAE следует ноутбуку VQ-VAE-2 из репозитория HSE-LAMBDA Deep Generative Models (номера ячеек считают все ячейки, начиная с 1). Сохранённых выходов в ноутбуке нет, поэтому он описывает процедуру, а не результаты.

  • Ячейка 6: Quantize вычисляет квадраты расстояний сразу до всех 512 векторов словаря через разложение ∥a−e∥2=∥a∥2−2a⊤e+∥e∥2\lVert a - e\rVert^2 = \lVert a\rVert^2 - 2a^\top e + \lVert e\rVert^2, одним матричным произведением, выбирает ближайший, обновляет словарь описанным выше EMA (затухание 0.99), возвращает расстояние привязки diff = mean((quantize.detach() - input)²) и применяет прямой проброс input + (quantize - input).detach(). Словарь — буфер, взятый из стандартного нормального распределения, а не параметр, поэтому Adam его не трогает; словарь меняется только через EMA и только в режиме обучения. Счётчики сглаживаются как Nk←Nk+ϵn+Kϵ nN_k \leftarrow \frac{N_k + \epsilon}{n + K\epsilon}\, n с n=∑kNkn = \sum_k N_k и ϵ=10−5\epsilon = 10^{-5}; это сохраняет их сумму и делает каждый счётчик положительным. Одна проблема: счётчики начинаются с 00, а суммы mkm_k — со случайного словаря. Поэтому после первого обновления код, который первый батч не выбрал, делится на сглаженный счётчик порядка ϵ\epsilon, и его норма вырастает примерно в 10510^5 раз. Обратно она уменьшается лишь как 0.99t0.99^t, что занимает около ln⁡105/−ln⁡0.99≈1150\ln 10^5 / {-\ln 0.99} \approx 1150 шагов. В нашем собственном игрушечном прогоне этого обновления со стандартными нормальными выходами энкодера (это не выход ноутбука) между шагами 2 и 1000 выбирались только 2–3 кода из 512. Если начать счётчики с 11, так что первое частное mk/Nkm_k / N_k — сам случайный словарь, скачка не будет.
  • Ячейки 7–10: архитектура. ResBlock — это ReLU, свёртка 3×33 \times 3 из 128 в 32 канала, ReLU и свёртка 1×11 \times 1 обратно в 128 каналов; результат прибавляется к входу блока. Нижний энкодер применяет две свёртки 4×44 \times 4 с шагом 2 и свёртку 3×33 \times 3, верхний — одну свёртку 4×44 \times 4 с шагом 2 и свёртку 3×33 \times 3; за каждым из них следуют остаточные блоки. Декодеры устроены зеркально: свёртка 3×33 \times 3, остаточные блоки и транспонированные свёртки 4×44 \times 4 с шагом 2. Настройки: channel=128, n_res_block=2, n_res_channel=32, словари из 512 векторов размерности 64. Нижний энкодер уменьшает разрешение в 4 раза (до 8×88 \times 8 для CIFAR-10), верхний — ещё в 2 (до 4×44 \times 4), а свёртки 1×11 \times 1 перед квантованием проецируют признаки в 64-мерные векторы кода. Верхний код попадает на нижний уровень двумя отдельными путями: dec_t, небольшой декодер, возвращает его к 8×88 \times 8, чтобы объединить с нижними признаками и квантовать как нижний код, а upsample_t, одна транспонированная свёртка, увеличивает его для итогового декодера, который получает его вместе с нижним кодом.
  • Ячейка 12: обучение минимизирует среднюю квадратичную ошибку реконструкции плюс 0.25⋅0.25 \cdot diff, слагаемое привязки; слагаемого словаря нет, потому что его заменяет EMA. Каждые sample_interval шагов (200 в ячейке 20) сохраняется сетка: батч, а под ним его реконструкции, вычисленные в режиме оценки.
  • Ячейки 13 и 22: infer_vqvae реконструирует два батча по 64 тестовых изображения CIFAR-10 в режиме оценки и сохраняет 128 реконструкций в файл.
  • Ячейки 14–20: CIFAR-10 в разрешении 32×3232 \times 32, нормированный к [−1,1][-1, 1] (комментарий в ячейке 15 всё ещё говорит о 64×6464 \times 64), батч 32, Adam с шагом 3⋅10−43 \cdot 10^{-4}, пять эпох.
  • Ячейки 25–27: априорные модели. Маскированные свёртки типов A и B и две априорные модели PixelCNN из семи маскированных слоёв 7×77 \times 7 по 64 канала с обычными ReLU между ними, без гейтов. На входе эмбеддинг индексов кода, Embedding(512, 64), а свёртка 1×11 \times 1 даёт 512 логитов на позицию. Безусловная априорная модель описывает верхние коды. Условная описывает нижние: она строит эмбеддинги верхних кодов, увеличенных методом ближайшего соседа, через Embedding(512, 16), конкатенирует их с эмбеддингом нижних кодов и смешивает их свёрткой 1×11 \times 1. Здесь две проблемы. Такая простая стопка слоёв имеет слепое пятно, и в ней нет гейтированных слоёв и внимания, как в априорных моделях статьи. А поскольку условие подмешивается в те же каналы до первого маскированного слоя типа A, маска скрывает и условие в предсказываемой позиции. Каждый нижний индекс видит верхние коды только через предыдущие позиции, поэтому левый верхний индекс каждого блока 2×22 \times 2, чей верхний код не встречается ни в одной предыдущей позиции, предсказывается без него. Мы проверили это, продифференцировав собственную повторную реализацию сети: у логитов в позиции нулевой градиент по условию в той же позиции. Условие должно входить без маски и добавляться в каждом слое, как в условном Gated PixelCNN.
  • Ячейки 29–32: датасеты, на лету кодирующие каждое изображение в сетки кодов, и обучение двух априорных моделей кросс-энтропией с Adam при шаге обучения 10−310^{-3}, батче 32 и 10 эпохах для каждой. Кодировать нужно с VQ-VAE в режиме оценки, в котором его оставляет ячейка 22; в режиме обучения квантизатор продолжал бы обновлять словарь, пока извлекаются коды.
  • Ячейки 34–35: сэмплирование — 16 последовательных шагов для верхней сетки, 64 для нижней при данной увеличенной верхней — и декодирование. Каждый шаг заново прогоняет PixelCNN по всей сетке.
  • Замечание о реализации. utils.save_image(..., range=(-1, 1)) в ячейках 12, 22 и 35 использует имя аргумента, которое в torchvision переименовано в value_range; в текущих версиях эти вызовы требуют нового имени.

У β-VAE нет обученного примера в ноутбуках курса: ноутбук VAE определяет функцию потерь с весом β в ячейке 24, но обучает только с β=1\beta = 1.

У VAPNEV нет реализации в репозитории курса. Ноутбук с упражнениями 03_hw_vapnev.ipynb из того же репозитория формулирует задания на CelebA и оставляет ячейки кода пустыми. Его единственные сохранённые выходы — устройство (mps), форма одного изображения, 3×64×643 \times 64 \times 64, и сетка из 25 случайных лиц.

  • Ячейки 3–9: данные. CelebA через класс датасета курса, с Resize(64) и CenterCrop(64), которые сохраняют соотношение сторон, и пикселями, переведёнными из [0,1][0, 1] в [−1,1][-1, 1] преобразованием 2x−12x - 1.
  • Ячейки 10–11: нормализующий поток на этих лицах, оцениваемый по FID и отрицательному логарифму правдоподобия. Допускаются любые слои — слои связи, авторегрессионные или линейные, свёрточные или на вытянутом в вектор изображении; слои описаны в заметке Архитектуры потоков. Правдоподобие, которое приводится для изображений, должно учитывать деквантование и якобиан предобработки, как это делают Agrawal и Dukkipati для своего логит-преобразования.
  • Ячейки 12–13: VAE на тех же лицах, оцениваемый по FID, как в ноутбуке о VAE.
  • Ячейки 14–15: VAPNEV по статье и условный VAPNEV. Подробности условия ноутбук оставляет формулировке задания; естественный выбор — 40 атрибутов CelebA, которые класс датасета курса возвращает вместе с каждым изображением, а обёртка из ячейки 6 отбрасывает.
  • Ячейки 16–17: анализ латентных пространств: какая модель лучше интерполирует, кодирование лица не из CelebA и поиск ближайших к нему кодов обучающих изображений, а также самый интересный сэмпл.

Дальше#

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

Литература#