<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=46.0.164.18&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=46.0.164.18&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/46.0.164.18"/>
		<updated>2026-06-11T14:11:04Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%92%D0%B0%D1%80%D0%B8%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%B0%D0%B2%D1%82%D0%BE%D0%BA%D0%BE%D0%B4%D0%B8%D1%80%D0%BE%D0%B2%D1%89%D0%B8%D0%BA&amp;diff=71899</id>
		<title>Вариационный автокодировщик</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%92%D0%B0%D1%80%D0%B8%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%B0%D0%B2%D1%82%D0%BE%D0%BA%D0%BE%D0%B4%D0%B8%D1%80%D0%BE%D0%B2%D1%89%D0%B8%D0%BA&amp;diff=71899"/>
				<updated>2019-10-23T14:27:00Z</updated>
		
		<summary type="html">&lt;p&gt;46.0.164.18: Откуда появилось условное распределение? Разве мы не хотим приблизить априорное безусловное распределение z к наблюдаемому условному?&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Вариационный автокодировщик''' (англ. ''Variational Autoencoder'', ''VAE'') {{---}} [[автокодировщик]]&amp;lt;sup&amp;gt;[на 28.01.19 не создан]&amp;lt;/sup&amp;gt; (генеративная модель, которая учится отображать объекты в заданное скрытое пространство (и обратно)) основанный на вариационном выводе.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Предпосылки ==&lt;br /&gt;
При попытке использования обыкновенного автокодировщика для генерации новых объектов (желательно из того же априорного распределения, что и датасет) возникает следующая проблема. Случайной величиной с каким распределением проинициализировать скрытые векторы, для того, чтобы картинка, после применения декодера, стала похожа на картинки из датасета, но при этом не совпадала ни с одной из них? Ответ на этот вопрос не ясен, в связи с тем, что обыкновенный автокодировщик не может ничего утверждать про распределение скрытого вектора и даже про его область определения. В частности, область определения может быть даже дискретной.&lt;br /&gt;
&lt;br /&gt;
Вариационный автокодировщик в свою очередь предлагает пользователю самому определить распределение скрытого вектора. &lt;br /&gt;
&lt;br /&gt;
== Описание ==&lt;br /&gt;
'''Порождающее моделирование''' (англ. ''Generative modelling'') {{---}} область машинного обучения, имеющая дело с распределением &amp;lt;math&amp;gt;P(X)&amp;lt;/math&amp;gt;, определенном на датасете &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt; из пространства (возможно многомерного) &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. Так, например, популярные задачи генерации картинок имеют дело с огромным количеством измерений (пикселей). &lt;br /&gt;
&lt;br /&gt;
Также как и в обыкновенных кодировщиках у нас имеется скрытое вероятностное пространство &amp;lt;math&amp;gt;Z&amp;lt;/math&amp;gt; соответствующее случайной величине &amp;lt;math&amp;gt;(z, P(z))&amp;lt;/math&amp;gt; (распределенной как-нибудь фиксированно, здесь &amp;lt;math&amp;gt;\sim N(0, 1)&amp;lt;/math&amp;gt;). И мы хотим иметь декодер &amp;lt;math&amp;gt;f(z, \theta) \colon Z \times \Theta \to X &amp;lt;/math&amp;gt;. При этом мы хотим найти такие &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;, чтобы после разыгрывания &amp;lt;math&amp;gt;z&amp;lt;/math&amp;gt; по &amp;lt;math&amp;gt;P(z)&amp;lt;/math&amp;gt; мы получили &amp;quot;что-то похожее&amp;quot; на элементы &amp;lt;math&amp;gt;X&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Вообще, для любого &amp;lt;math&amp;gt;x \in X&amp;lt;/math&amp;gt; мы хотим считать &amp;lt;math&amp;gt;P(x) = \int P(x|z; \theta)P(z)dz&amp;lt;/math&amp;gt;, здесь мы заменили &amp;lt;math&amp;gt;f(z, \theta)&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;P(x|z; \theta)&amp;lt;/math&amp;gt;, чтобы явно показать зависимость между &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;z&amp;lt;/math&amp;gt; и после этого применить формулу полной вероятности. Обычно &amp;lt;math&amp;gt;P(x|z; \theta)&amp;lt;/math&amp;gt; около нуля почти для всех пар &amp;lt;math&amp;gt;(x, z)&amp;lt;/math&amp;gt;. Основная идея в том, что мы хотим теперь генерировать &amp;lt;math&amp;gt;z&amp;lt;/math&amp;gt;, который бы давали что-то около &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; и только их суммировать в &amp;lt;math&amp;gt;P(x)&amp;lt;/math&amp;gt;. Для этого нам требуется ввести еще одно распределение &amp;lt;math&amp;gt;Q(z|X)&amp;lt;/math&amp;gt;, которое будет получать &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; и говорить распределение на &amp;lt;math&amp;gt;z&amp;lt;/math&amp;gt; которое наиболее вероятно будет генерировать нам такой &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;. Теперь нам нужно как-то сделать похожими распределения &amp;lt;math&amp;gt;E_{z\sim Q}P(X|z)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;P(X)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Рассмотрим следующую дивергенцию Кульбака-Лейблера (''Kullback–Leibler divergence'', ''KL-div'').&lt;br /&gt;
:&amp;lt;math&amp;gt;D[Q(z)||P(z|X)] = E_{z∼Q} [log Q(z) − log P(z|X)]&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
Распишем &amp;lt;math&amp;gt;P(z|X)&amp;lt;/math&amp;gt; как &amp;lt;math&amp;gt;P(X|z) * P(z) / P(X)&amp;lt;/math&amp;gt;.&lt;br /&gt;
:&amp;lt;math&amp;gt;D[Q(z)||P(z|X)] = E_{z∼Q} [log Q(z) − log P(X|z) - log P(z)] + log P(X)&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
Что эквивалентно:&lt;br /&gt;
:&amp;lt;math&amp;gt;logP(x) - D[Q(z)||P(z|X)] = E_{z∼Q}[log P(X|z)] - D[Q(z)||P(z)]&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
Рассмотрим эту штуку для &amp;lt;math&amp;gt;Q(z|X)&amp;lt;/math&amp;gt;, тогда:&lt;br /&gt;
:&amp;lt;math&amp;gt;logP(x) - D[Q(z|X)||P(z|X)] = E_{z∼Q}[log P(X|z)] - D[Q(z|X)||P(z)]&amp;lt;/math&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
Посмотрим, на это равенство. Правую часть мы можем оптимизировать градиентным спуском (пусть пока и не совсем понятно как).&lt;br /&gt;
В левой же части первое слагаемое {{---}} то, что мы хотим максимизировать. В то же время &amp;lt;math&amp;gt;D[Q(z|X)||P(z|X)]&amp;lt;/math&amp;gt; мы хотим минимизировать. Если у нас &amp;lt;math&amp;gt;Q(z|X)&amp;lt;/math&amp;gt; {{---}} достаточно сильная модель, то в какой-то момент она будет хорошо матчить &amp;lt;math&amp;gt;P(z|X)&amp;lt;/math&amp;gt;, а значит их дивергенция Кульбака-Лейблера будет почти 0. Значит, при оптимизации можно исключить эту часть и стараться максимизировать только правую. В качестве бонуса мы еще получили более &amp;quot;податливую&amp;quot; &amp;lt;math&amp;gt;P(z|X)&amp;lt;/math&amp;gt;, вместо нее можно смотреть на &amp;lt;math&amp;gt;Q(z|X)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Теперь разберемся как оптимизировать правую часть. Сначала нужно определиться с моделью для &amp;lt;math&amp;gt;Q(z|X)&amp;lt;/math&amp;gt;. Обычно ее берут равной &amp;lt;math&amp;gt;N(z|\mu(X, \theta), \sigma(X, \theta))&amp;lt;/math&amp;gt;. Где &amp;lt;math&amp;gt;\mu&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\sigma&amp;lt;/math&amp;gt; какие-то детерминированные функции на X с обучаемыми параметрами &amp;lt;math&amp;gt;\theta&amp;lt;/math&amp;gt;, которые мы впредь будем опускать (обычно используются нейронные сети). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Нетрудно проверить, что для дивергенция Кульбака-Лейблера двух нормальных распределений имеет следующий вид:&lt;br /&gt;
:&amp;lt;math&amp;gt;D_{K}[N(\mu_1, \Sigma_0)||N(\mu_1, \Sigma_0)]&amp;lt;/math&amp;gt;, KLD есть &amp;lt;math&amp;gt;\frac{1}{2} (tr(\Sigma_1^{-1}\Sigma_0) + (\mu_1 - \mu_0)^T\Sigma_1^{-1}(\mu_1 - \mu_0) - k + log(\frac{det\Sigma_1}{det\Sigma_0})) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Это значит, что&lt;br /&gt;
:&amp;lt;math&amp;gt;D[Q(z|X)||P(z)] = D[N(\mu(X), \Sigma(X))||N(0, I)] = \frac12 (tr(\Sigma(X)) + \mu(X)^T\mu(X) - k - log(det\Sigma(X)))&amp;lt;/math&amp;gt;. &lt;br /&gt;
Теперь здесь &lt;br /&gt;
можно считать градиенты, для BackPropagation. С первым слагаемым в правой части все немного сложнее. &amp;lt;math&amp;gt;E_{z∼Q}[log P(X|z)]&amp;lt;/math&amp;gt; мы можем считать методом Монте-Карло(МК), но тогда такая штука (из-за того, что переменные спрятаны в распределении, из которого мы генерируем себе выборку, для МК) не является гладкой относительно них, а значит непонятно, как проталкивать через это градиент. Для того, чтобы все-таки можно было протолкнуть градиент, применяется так называемый ''трюк репараметризации'', который базируется на простой формуле &amp;lt;math&amp;gt;N(\Sigma(X), \mu(X)) = \mu(X) + \Sigma^{\frac12}(X) * N(0, I) &amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
:&amp;lt;math&amp;gt;E_{z∼Q}[log P(X|z)] = E_{\epsilon \sim N(0, I)}[log P(X = f(\mu(X) + \Sigma^{\frac12}(X) * \epsilon), \theta)]&amp;lt;/math&amp;gt;. &lt;br /&gt;
В такой форме мы уже можем использовать BackPropagation для переменных из функций &amp;lt;math&amp;gt;\Sigma&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;\mu&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следующая картинка лучше поможет осознать структуру VAE и, в частности, зачем нужен (и как работает) трюк репараметризации.&lt;br /&gt;
&lt;br /&gt;
На левой части диаграмма без использования reparameterization trick. &lt;br /&gt;
На правой части диаграмма с использованием reparameterization trick. &lt;br /&gt;
&lt;br /&gt;
[[Файл:VAE.PNG]]&lt;br /&gt;
&lt;br /&gt;
взято из https://arxiv.org/pdf/1606.05908.pdf&lt;br /&gt;
&lt;br /&gt;
== Пример реализации ==&lt;br /&gt;
Ниже приведена реализация частного случая VAE на языке Python с использованием библиотеки Pytorch.&lt;br /&gt;
Эта реализация работает с датасетом MNIST.&lt;br /&gt;
Размерность скрытого слоя {{---}} 2. &lt;br /&gt;
Координаты в нем считаются независимыми (из-за этого, например, матрица &amp;lt;math&amp;gt;\Sigma&amp;lt;/math&amp;gt; диагональная, и формула для расчета KLD немного другая).&lt;br /&gt;
&lt;br /&gt;
 class VariationalAutoencoder(nn.Module):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        super().__init__()&lt;br /&gt;
        self.mu = nn.Linear(32, 2)&lt;br /&gt;
        self.gamma = nn.Linear(32, 2)&lt;br /&gt;
        self.encoder = nn.Sequential(nn.Linear(784, 32), nn.ReLU(True))&lt;br /&gt;
        self.decoder = nn.Sequential(nn.Linear(2, 32), nn.ReLU(True), nn.Linear(32, 784), nn.Sigmoid())&lt;br /&gt;
 &lt;br /&gt;
    def forward(self, x):&lt;br /&gt;
        mu, gamma = self.encode(x)&lt;br /&gt;
        encoding = self.reparameterize(mu, gamma)&lt;br /&gt;
        x = self.decoder(encoding)&lt;br /&gt;
        return x, mu, gamma&lt;br /&gt;
 &lt;br /&gt;
    def reparameterize(self, mu, gamma):&lt;br /&gt;
        if self.training:&lt;br /&gt;
            sigma = torch.exp(0.5*gamma)&lt;br /&gt;
            std_z = Variable(torch.from_numpy(np.random.normal(0, 1, size=sigma.size())).float())&lt;br /&gt;
            encoding = std_z.mul(sigma).add(mu)&lt;br /&gt;
            return encoding&lt;br /&gt;
        else:&lt;br /&gt;
            return mu&lt;br /&gt;
 &lt;br /&gt;
    def encode(self, x):&lt;br /&gt;
        x = self.encoder(x)&lt;br /&gt;
        mu = self.mu(x)&lt;br /&gt;
        gamma = self.gamma(x)&lt;br /&gt;
        return mu, gamma&lt;br /&gt;
  &lt;br /&gt;
    def decode(self, x):&lt;br /&gt;
        return self.decoder(x)&lt;br /&gt;
 &lt;br /&gt;
    def latent(self, x):&lt;br /&gt;
        mu, gamma = self.encode(x)&lt;br /&gt;
        encoding = self.reparameterize(mu, gamma)&lt;br /&gt;
        return encoding&lt;br /&gt;
 &lt;br /&gt;
 def loss_function(input, output, mu, gamma, batch_size=batch_size):&lt;br /&gt;
    BCE = F.binary_cross_entropy(output, input)&lt;br /&gt;
    KLD = -0.5*torch.sum(1 + gamma - mu.pow(2) - gamma.exp())&lt;br /&gt;
    KLD /= batch_size*784&lt;br /&gt;
    return BCE + KLD&lt;br /&gt;
&lt;br /&gt;
== Применение ==&lt;br /&gt;
Область применения вариационных автокодировщиков совпадает с областью применения обыкновенных автокодировщиков. А именно:&lt;br /&gt;
* Каскадное обучение глубоких сетей (хотя сейчас применяется все реже, в связи с появлением новых методов инициализации весов);&lt;br /&gt;
* Уменьшение шума в данных;&lt;br /&gt;
* Уменьшение размерности данных (иногда работает лучше, чем [[метод главных компонент]]&amp;lt;sup&amp;gt;[на 28.01.19 не создан]&amp;lt;/sup&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Благодаря тому, что пользователь сам устанавливает нужное распределение скрытого вектора, вариационный кодировщик хорошо подходит для генерации новых объектов (например, картинок). Для этого достаточно разыграть скрытый вектор согласно его распределению и подать на вход декодера. Получится объект из того же распределения, что и датасет.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
*[[:Автокодировщик|Автокодировщик]] &lt;br /&gt;
*[[:Generative Adversarial Nets (GAN)|Порождающие состязательные сети]]&lt;br /&gt;
&lt;br /&gt;
== Примечания ==&lt;br /&gt;
*[https://habr.com/ru/post/429276/ Вариационные автокодировщики: теория и рабочий код]&lt;br /&gt;
*[https://jaan.io/what-is-variational-autoencoder-vae-tutorial/ Tutorial - What is a variational autoencoder?]&lt;br /&gt;
*[https://towardsdatascience.com/intuitively-understanding-variational-autoencoders-1bfe67eb5daf Intuitively Understanding Variational Autoencoders]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*[https://arxiv.org/abs/1606.05908 Tutorial on Variational Autoencoders]&lt;br /&gt;
*Datalore презентация Дениса Степанова&lt;br /&gt;
&lt;br /&gt;
[[Категория: Машинное обучение]]&lt;br /&gt;
[[Категория: Порождающие модели]]&lt;/div&gt;</summary>
		<author><name>46.0.164.18</name></author>	</entry>

	</feed>