Вектор средних, ковариационная матрица, двумерная плотность и сэмплирование любой гауссианы из стандартного шума с помощью квадратного корня из матрицы, а также параметризация в PyTorch, которая используется в первых экспериментах по подгонке распределений.
Генеративная модель — это распределение, из которого можно сэмплировать и, в идеале, вычислять его плотность (Что такое генеративное моделирование). Пока нейронные сети не появились, курс работает с простейшим распределением, которое остаётся интересным в нескольких измерениях: многомерным гауссовским (multivariate Gaussian). Оно служит сквозным примером первых заметок и выступает там в двух ролях: это и цель, из которой мы берём данные, и модель, которую мы под эти данные подгоняем. Оно же возвращается почти в каждой следующей модели: априорное распределение VAE, шум диффузионной модели, базовое распределение нормализующего потока (normalizing flow) и статистики признаков, на которых построен FID.
Вводный блок курса состоит из трёх шагов:
сгенерировать данные из известного распределения (эта заметка);
подогнать параметризованное двумерное распределение к данным градиентным спуском по такому расстоянию (Подгонка распределений с помощью KL).
Обозначения. Заглавные буквы, например X и Z, обозначают случайные векторы; полужирные строчные, например x и z, — точки плоскости, то есть значения, которые эти векторы принимают. Полужирные заглавные, например Σ, A и L, — матрицы, I — единичная матрица, A⊤ — транспонированная матрица, ∣Σ∣ — определитель. Запись X∼N(μ,σ2) означает одномерное нормальное распределение со средним μ и дисперсией σ2, а X∼N(μ,Σ) — многомерное нормальное распределение с вектором средних μ и ковариационной матрицей Σ: второй аргумент — всегда дисперсия или ковариация, а не стандартное отклонение. Плотности обозначаются p и q; начиная с раздела про PyTorch, P — фиксированное целевое распределение с плотностью p, а Q — обучаемая модель с плотностью q.
где ρ — коэффициент корреляции между X1 и X2. Матрица симметрична, потому что Cov(X1,X2)=Cov(X2,X1). Кроме того, она положительно полуопределённая (positive semidefinite): для любого фиксированного вектора a дисперсия Var(a⊤X)=a⊤Σa не может быть отрицательной. Все дисперсии и ковариации вектора умещаются в три свободных числа.
Пример, который проходит через всю заметку, — гауссиана с центром в начале координат и
μ=(00),Σ=(10.50.51):
единичные дисперсии и корреляция ρ=0.5, поэтому облако точек вытянуто вдоль диагонали x1=x2.
Две дисперсии говорят, насколько облако разбросано вдоль каждой координатной оси. Этого достаточно, только когда координаты некоррелированы, и тогда облако вытянуто вдоль осей. Внедиагональный элемент хранит то, чего дисперсии передать не могут: как координаты меняются совместно. Именно он наклоняет облако.
На рисунке 1 правое облако — это левое, повёрнутое на 45°. У двух облаков одинаковые собственные значения (1.5 и 0.5), но обе дисперсии правого облака вдоль осей равны 1. Ровно такие же дисперсии вдоль осей у круглого облака N(0,I), так что по одним двум дисперсиям наклонённое облако нельзя отличить от круга. Наклон фиксирует только Cov(X1,X2)=0.5.
Рисунок
Диагональная матрица растягивает облако только вдоль осей; ковариация его наклоняет
Оба облака построены по одним и тем же парам из стандартного нормального распределения (260 пар, без немногих, выходящих за пределы любого из окон). Слева: Σ = diag(1.5, 0.5), координаты независимы, поэтому разброс описывается одними Var(X₁) и Var(X₂). Справа: Σ = [[1, 0.5], [0.5, 1]], сквозной пример заметки. Её собственные значения 1.5 и 0.5, поэтому это левое облако, повёрнутое на 45°. Дисперсии вдоль обеих осей равны 1, и наклон фиксирует только внедиагональный элемент. Фигурные скобки охватывают ±1 стандартное отклонение, ±√Var; пунктирные направляющие опущены к ним из точек, где эллипс 1σ достигает крайних значений. Сплошная и пунктирная кривые — эллипсы 1σ и 2σ.
Когда Σ обратима (положительно определена, а не только полуопределена), совместная плотность на всей плоскости R2 равна
p(x)=2π∣Σ∣1×exp(−21(x−μ)⊤Σ−1(x−μ)),
где x=(x1,x2)⊤, Σ−1 — обратная матрица, а ∣Σ∣ — определитель ковариационной матрицы. Размеры сомножителей в квадратичной форме таковы:
1×2(x−μ)⊤2×2Σ−12×1(x−μ),
поэтому показатель экспоненты — скаляр. В d измерениях нормирующая константа становится равной (2π)−d/2∣Σ∣−1/2, и при d=2 получается выражение выше (Bishop, 2006, §2.3).
Линии уровня плотности, на которых квадрат расстояния Махаланобиса (Mahalanobis distance) (x−μ)⊤Σ−1(x−μ) равен k2, — эллипсы (Murphy, 2022, §3.2). Рисунки 1 и 3 показывают их как линии уровня 1σ (k=1) и 2σ (k=2). Вероятность попасть внутрь такого эллипса следует из преобразования, описанного ниже в разделе о сэмплировании. Запишем X=μ+Σ1/2Z, где Z∼N(0,I). Поскольку Σ1/2 симметрична и Σ1/2Σ−1Σ1/2=I, квадрат расстояния превращается в Z⊤Z=Z12+Z22 — квадрат длины стандартного шума. Стандартная плотность 2π1e−r2/2 зависит только от радиуса r, поэтому в полярных координатах
Pr(Z12+Z22≤k2)=∫0kre−r2/2dr=1−e−k2/2.
Это функция распределения χ2 с двумя степенями свободы в точке k2. Значит, эллипс 1σ содержит 1−e−1/2≈39% вероятности, а эллипс 2σ — 1−e−2≈86%, а не 68% и 95%, как одномерные интервалы.
а максимальное значение плотности равно p(μ)=1/(2π0.75)≈0.184.
Сэмплирование: от стандартного шума к любой гауссиане#
Коротко. Чтобы сэмплировать N(μ,Σ), возьмём Z∼N(0,I) и вернём μ+AZ для любой матрицы A с AA⊤=Σ; в коде A — множитель Холецкого. Остальная часть раздела строит квадратный корень и доказывает рецепт дважды: заменой переменных и через моменты. Кто знает аффинные преобразования гауссиан из курса теории вероятностей, может считать эти два доказательства дополнительными и сразу перейти к разобранному примеру.
В одномерном случае стандартизация и обратное к ней преобразование имеют вид
Поэтому, чтобы сэмплировать любое нормальное распределение, достаточно сэмплировать стандартное, растянуть результат в σ раз и сдвинуть на μ.
Рисунок
Стандартизация и обратное преобразование в одномерном случае
Точка z = 1 стандартного нормального распределения переходит в x = μ + σz = 3.5 при μ = 2, σ = 1.5; деление (x − μ) на σ возвращает её обратно. Обе точки лежат на одно стандартное отклонение выше своего среднего.
В двумерном случае нужна матрица, которая играет роль σ.
Спектральное разложение. По спектральной теореме любую вещественную симметричную матрицу, в частности любую ковариационную матрицу, можно записать как
Σ=UΛU⊤,
где Λ — диагональная матрица из собственных значений Σ, а столбцы ортогональной матрицы U — соответствующие нормированные собственные векторы. Собственные значения неотрицательны, потому что Σ положительно полуопределена, и можно определить квадратный корень из матрицы
Σ1/2=UΛ1/2U⊤,
где Λ1/2 содержит квадратные корни из собственных значений. Корень сам симметричен, потому что (UΛ1/2U⊤)⊤=UΛ1/2U⊤. Так как U⊤U=I, получаем Σ1/2Σ1/2=UΛU⊤=Σ.
Преобразование. Если Z∼N(0,I), то
X=μ+Σ1/2Z∼N(μ,Σ).
В общем случае подходит любая квадратная матрица A с AA⊤=Σ; Σ1/2 — одна из них, потому что она симметрична и в квадрате даёт Σ. Для положительно определённой Σ такая A обратима, поскольку (detA)2=∣Σ∣>0, и формула замены переменных (change of variables) даёт плотность X=μ+AZ (Murphy, 2022, §2.8). Подставим z=A−1(x−μ) в стандартную плотность 2π1e−z⊤z/2 и разделим на ∣detA∣=∣Σ∣1/2:
потому что z⊤z=(x−μ)⊤(A−1)⊤A−1(x−μ) и (A−1)⊤A−1=(AA⊤)−1=Σ−1. Это плотность N(μ,Σ) из предыдущего раздела. (Для вырожденной Σ то же преобразование задаёт вырожденную гауссиану, сосредоточенную на прямой; плотности на плоскости у неё нет.) Первые два момента дают быструю проверку. Среднее равно μ+AE[Z]=μ, а ковариация —
Cov(μ+AZ)=ACov(Z)A⊤=AIA⊤=Σ.
Симметричный корень Σ1/2 — лишь один из вариантов. Для положительно определённой Σ существует ровно одна нижнетреугольная матрица L с положительной диагональю и LL⊤=Σ — множитель Холецкого (Cholesky factor) (Golub and Van Loan, 2013, §4.2). В коде обычно выбирают именно его: конечный алгоритм вычисляет его примерно за d3/3 операций с плавающей точкой для матрицы d×d, тогда как спектральному разложению нужен итерационный метод. В отличие от симметричного корня, он требует положительной определённости: torch.linalg.cholesky завершается ошибкой на вырожденной ковариации, а MultivariateNormal принимает только положительно определённую covariance_matrix. MultivariateNormal в PyTorch сэмплирует ровно так: хранит множитель Холецкого переданной ковариации и возвращает μ+LZ, где Z∼N(0,I) (документация и исходный код PyTorch). Та же схема — на входе шум, на выходе детерминированное преобразование — лежит в основе трюка репараметризации (reparameterization trick) в VAE и формулы зашумления за один шаг в DDPM.
Рисунок
Сэмплирование любой гауссианы из стандартного шума
Независимые пары Z из стандартного нормального распределения умножаются на матрицу A с AAᵀ = Σ (здесь это множитель Холецкого L для Σ = [[1, 0.5], [0.5, 1]] из сквозного примера), а затем сдвигаются на μ = (1.5, 1). Янтарная точка z = (2, 1) прослежена через оба шага: она переходит в Az = (2, 1.87), а затем в μ + Az = (3.5, 2.87). Кривые — линии уровня 1σ и 2σ; у всех панелей одно и то же окно.
Для Σ=(10.50.51) характеристическое уравнение имеет вид (1−λ)2=0.25, поэтому собственные значения равны λ1=1.5 и λ2=0.5. Собственные векторы — 21(1,1)⊤ и 21(1,−1)⊤. Дисперсия максимальна вдоль диагонали x1=x2: полуоси эллипса 1σ равны 1.5≈1.225 вдоль неё и 0.5≈0.707 поперёк. Два допустимых квадратных корня:
Проверка: 0.9662+0.2592≈1 и 2⋅0.966⋅0.259≈0.5. Для множителя Холецкого LL⊤=(10.50.50.25+0.75)=Σ. Обе матрицы превращают независимый стандартный шум в сэмплы одного и того же коррелированного облака.
Проверьте себя. Возьмём Σ=(1−0.8−0.81). Вдоль какой диагонали вытянуто облако и каков его множитель Холецкого? Ответ: собственные значения равны 1.8 и 0.2, длинная ось идёт вдоль x1=−x2, полуоси равны 1.8≈1.342 и 0.2≈0.447, а L=(1−0.800.6), поскольку LL⊤=(1−0.8−0.80.64+0.36)=Σ.
torch.distributions содержит параметризуемые распределения с методами для вычисления (логарифма) плотности и для сэмплирования. Двумерная гауссиана — это MultivariateNormal. Экспериментам по подгонке в заметке Подгонка распределений с помощью KL нужна гауссиана, параметры которой оптимизатор может менять свободно. Мешает ковариация: произвольная матрица 2×2, вообще говоря, не является допустимой ковариационной матрицей.
Выход — обучать не Σ, а множитель Холецкого. При
L=(eab0ec),LL⊤=(e2abeabeab2+e2c),
три исходных числа a,b,c могут принимать любые вещественные значения. Диагональ L хранится через логарифм, поэтому остаётся положительной, и треугольная матрица L обратима. Тогда LL⊤ симметрична и положительно определена: для v=0 имеем v⊤LL⊤v=∥L⊤v∥2>0, поскольку L⊤ обратима. Сквозной пример получается при a=0, b=0.5 и c=ln0.75≈−0.144; инициализация a=b=c=0 даёт Σ=I.
Обучаемые параметры создаются с requires_grad=True: это говорит механизму автоматического дифференцирования PyTorch (autograd) записывать операции над ними и вычислять их градиенты. У модельного распределения Q обучаются среднее и исходные элементы L. Целевое распределение P создаётся с requires_grad=False, потому что оно фиксировано. Рисунок 4 показывает начальную точку первого эксперимента по подгонке; каждое облако окрашено по своей собственной плотности.
Рисунок
Целевое распределение P и модель Q до обучения
По 400 сэмплов из фиксированного целевого распределения P = N((−5, −5), I) и из обучаемой модели Q, инициализированной как N(0, I), в пределах графика (−10, 10). Каждая точка окрашена по плотности своего облака: p(x) для сэмплов цели и q(x) для сэмплов модели, так что более насыщенный цвет означает более высокую плотность.
Минимальный пример обоих способов сэмплировать из распределения сквозного примера:
import torchfrom torch import distributions as distrsmu = torch.zeros(2)cov = torch.tensor([[1.0, 0.5], [0.5, 1.0]])target = distrs.MultivariateNormal( mu, covariance_matrix=cov)# 1000 сэмплов, форма (1000, 2)x = target.sample(torch.Size([1000]))# L = [[1, 0], [0.5, 0.866]]L = torch.linalg.cholesky(cov)# то же распределение вручнуюx_manual = mu + torch.randn(1000, 2) @ L.T
Каждая строка torch.randn(1000, 2) — один сэмпл z⊤, поэтому @ L.T построчно вычисляет (Lz)⊤.
Практическая часть заметки следует ноутбуку Distances between distributions из репозитория курса HSE-LAMBDA Deep Generative Models. Ссылка закреплена на конкретном коммите; ячейки нумеруются с 1, считая все ячейки подряд.
Ячейка 2 готовит окружение: импортирует Matplotlib со стилем fivethirtyeight, NumPy, PyTorch с torch.distributions под именем distrs и clear_output из IPython, с помощью которой циклы обучения потом перерисовывают графики.
Ячейка 4 определяет plot_2d_dots — диаграмму рассеяния массива N×2 в пределах (−10,10) по умолчанию для обеих осей (аргументы xlim и ylim), по одной маленькой точке на сэмпл; точки можно окрасить по необязательному массиву значений через цветовую карту cmap (по умолчанию viridis).
Ячейка 5 определяет три вспомогательные функции для описанной выше параметризации. get_parameters(mu, sigma, requires_grad) создаёт среднее (μ,μ) и исходные элементы a=c=lnσ, b=0. create_distr собирает L и возвращает MultivariateNormal(mu, L @ L.T), передавая LL⊤ как covariance_matrix. sample(distr, n) возвращает тензор n×2. Поскольку L уже является корректным множителем Холецкого, MultivariateNormal(mu, scale_tril=L) задаёт то же распределение и обходится без повторного разложения, которое PyTorch выполняет для L @ L.T; по этой причине документация PyTorch рекомендует scale_tril.
Ячейки 8–11 создают фиксированное целевое распределение N((−5,−5),I) и обучаемую модель Q, инициализированную как N(0,I), и рисуют оба облака, окрашенные по p(x) и q(x) (рисунок 4). Ячейки 8 и 11 берут по 1000 сэмплов из каждого распределения, а графики используют цветовые карты viridis и plasma; на рисунке 4 по 400 сэмплов на облако, а плотность передана насыщенностью цвета. Сама подгонка — тема заметки Подгонка распределений с помощью KL.
Когда есть целевое распределение и обучаемая модель, остаётся понять, что значит «подогнать»: нужно число, которое говорит, насколько Q далеко от P. Первый кандидат — KL-дивергенция, и чтобы понять её, мы начнём с энтропии в заметке Энтропия, кросс-энтропия и KL-дивергенция.
K. P. Murphy. Probabilistic Machine Learning: An Introduction. MIT Press, 2022. §2.8: преобразования случайных величин, включая формулу замены переменных; §3.2: многомерное гауссовское распределение и расстояние Махаланобиса.
G. H. Golub, C. F. Van Loan. Matrix Computations, 4th ed. Johns Hopkins University Press, 2013. §4.2: положительно определённые системы и разложение Холецкого.