Редактирование: Вариационный автокодировщик

Перейти к: навигация, поиск

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

Правка может быть отменена. Пожалуйста, просмотрите сравнение версий, чтобы убедиться, что это именно те изменения, которые вас интересуют, и нажмите «Записать страницу», чтобы изменения вступили в силу.
Текущая версия Ваш текст
Строка 1: Строка 1:
'''Вариационный автокодировщик''' (англ. ''Variational Autoencoder'', ''VAE'') {{---}} [[автокодировщик]] (генеративная модель, которая учится отображать объекты в заданное скрытое пространство (и обратно)) основанный на вариационном выводе.
+
'''Вариационный автокодировщик''' (англ. ''Variational Autoencoder'', ''VAE'') {{---}} это [[автокодировщик]] (a.k.a. генеративная модель, которая учится отображать объекты в заданное скрытое пространство (и обратно)) основанный на вариационном выводе.
  
  
Строка 8: Строка 8:
  
 
== Описание ==
 
== Описание ==
'''Порождающее моделирование''' (англ. ''Generative modelling'') {{---}} область машинного обучения, имеющая дело с распределением <math>P(X)</math>, определенном на датасете <math>X</math> из пространства (возможно многомерного) <math>X</math>. Так, например, популярные задачи генерации картинок имеют дело с огромным количеством измерений (пикселей).  
+
'''Генеративное моделирование''' (англ. ''Generative modelling'') {{---}} область машинного обучения, имеющая дело с распределением P(X), определенном на датасете X из пространства (возможно многомерного) <math>\Chi</math>. Так, например, популярные задачи генерации картинок имеют дело с огромным количеством измерений (пикселей).  
  
Также как и в обыкновенных кодировщиках у нас имеется скрытое вероятностное пространство <math>Z</math> соответствующее случайной величине <math>(z, P(z))</math> (распределенной как-нибудь фиксированно, здесь <math>\sim N(0, 1)</math>). И мы хотим иметь декодер <math>f(z, \theta) \colon Z \times \Theta \to X </math>. При этом мы хотим найти такие <math>\theta</math>, чтобы после разыгрывания <math>z</math> по <math>P(z)</math> мы получили "что-то похожее" на элементы <math>X</math>.  
+
Также как и в обыкновенных кодировщиках у нас имеется скрытое вероятностное пространство Z соответствующее случайной величине (z, P(z))(распределенной как-нибудь фиксированно, здесь ~N(0, 1)). И мы хотим иметь декодер <math>f(z, \theta) \colon Z \times \Theta \to \Chi </math>. При этом мы хотим найти такие <math>\theta</math>, чтобы после разыгрывания z по P(z) мы получили <<что-то похожее>> на элементы X.
 +
Вообще, мы хотим, чтобы для любого <math>x \in X</math> мы хотим считать <math>P(x) = \int P(x|z; \theta)P(z)dz</math> здесь мы заменили <math>f(x, \theta)</math> на <math>P(x|z; \theta)</math>, чтобы явно сделать зависимость между x и z и после этого применить формулу полной вероятности. Обычно <math>P(x|z; \theta)</math> около нуля почти для всех пар (x, z). Основная идея в том, что мы хотим теперь генерировать z, который бы давали что-то около x и только их суммировать в P(x). Для этого нам требуется ввести еще одно распределение Q(z|X), которое будет получать x и говорить распределение на z которое наиболее вероятно будет генерировать нам такой x. Теперь нам нужно как-то сделать похожими распределения <math>E_{z~Q}P(X|z)</math> и P(X). Рассмотрим следующую дивергенцию Кульбака-Лейблера
  
Вообще, для любого <math>x \in X</math> мы хотим считать <math>P(x) = \int P(x|z; \theta)P(z)dz</math>, здесь мы заменили <math>f(z, \theta)</math> на <math>P(x|z; \theta)</math>, чтобы явно показать зависимость между <math>x</math> и <math>z</math> и после этого применить формулу полной вероятности. Обычно <math>P(x|z; \theta)</math> около нуля почти для всех пар <math>(x, z)</math>. Основная идея в том, что мы хотим теперь генерировать <math>z</math>, который бы давали что-то около <math>x</math> и только их суммировать в <math>P(x)</math>. Для этого нам требуется ввести еще одно распределение <math>Q(z|X)</math>, которое будет получать <math>x</math> и говорить распределение на <math>z</math> которое наиболее вероятно будет генерировать нам такой <math>x</math>. Теперь нам нужно как-то сделать похожими распределения <math>E_{z\sim Q}P(X|z)</math> и <math>P(X)</math>.
+
<math>D[Q(z)||P(z|X)] = E_{z∼Q} [log Q(z|X) − log P(z|X)]</math>
  
Рассмотрим следующую дивергенцию Кульбака-Лейблера (''Kullback–Leibler divergence'', ''KL-div'').
+
Распишем P(z|X) как P(X|z) * P(z) / P(X):
:<math>D[Q(z)||P(z|X)] = E_{z∼Q} [log Q(z) − log P(z|X)]</math>,
 
  
Распишем <math>P(z|X)</math> как <math>P(X|z) * P(z) / P(X)</math>.
+
<math>D[Q(z)||P(z|X)] = E_{z∼Q} [log Q(z) − log P(X|z) - log P(z)] + log P(X)</math>
:<math>D[Q(z)||P(z|X)] = E_{z∼Q} [log Q(z) − log P(X|z) - log P(z)] + log P(X)</math>,
 
  
 
Что эквивалентно:
 
Что эквивалентно:
:<math>logP(x) - D[Q(z)||P(z|X)] = E_{z∼Q}[log P(X|z)] - D[Q(z)||P(z)]</math>,
+
<math>logP(x) - D[Q(z)||P(z|X)] = E_{z∼Q}[log P(X|z)] - D[Q(z)||P(z)]</math>
  
Рассмотрим эту штуку для <math>Q(z|X)</math>, тогда:
+
Рассмотрим эту штуку для Q(z|X), тогда:
:<math>logP(x) - D[Q(z|X)||P(z|X)] = E_{z∼Q}[log P(X|z)] - D[Q(z|X)||P(z)]</math>,
+
<math>logP(x) - D[Q(z|X)||P(z|X)] = E_{z∼Q}[log P(X|z)] - D[Q(z|X)||P(z)]</math>
  
 
Посмотрим, на это равенство. Правую часть мы можем оптимизировать градиентным спуском (пусть пока и не совсем понятно как).
 
Посмотрим, на это равенство. Правую часть мы можем оптимизировать градиентным спуском (пусть пока и не совсем понятно как).
В левой же части первое слагаемое {{---}} то, что мы хотим максимизировать. В то же время <math>D[Q(z|X)||P(z|X)]</math> мы хотим минимизировать. Если у нас <math>Q(z|X)</math> {{---}} достаточно сильная модель, то в какой-то момент она будет хорошо матчить <math>P(z|X)</math>, а значит их дивергенция Кульбака-Лейблера будет почти 0. Значит, при оптимизации можно исключить эту часть и стараться максимизировать только правую. В качестве бонуса мы еще получили более "податливую" <math>P(z|X)</math>, вместо нее можно смотреть на <math>Q(z|X)</math>.
+
В левой же части первое слагаемое -- то, что мы хотим максимизировать. В то же время <math>D [Q(z|X)||P(z|X)]</math> мы хотим минимизировать. Если у нас Q(z|X) -- достаточно сильная модель, то в какой-то модель она будет хорошо матчить P(z|X), а значит их дивергенция Кульбака Лейблера будет почти 0. А значит на это слагаемое можно забить. И стараться максимизировать правую часть. В качестве бонуса мы еще получили более "поддатливую" P(z|X), вместо нее можно смотреть на Q(z|X).
  
Теперь разберемся как оптимизировать правую часть. Сначала нужно определиться с моделью для <math>Q(z|X)</math>. Обычно ее берут равной <math>N(z|\mu(X, \theta), \sigma(X, \theta))</math>. Где <math>\mu</math> и <math>\sigma</math> какие-то детерминированные функции на X с обучаемыми параметрами <math>\theta</math>, которые мы впредь будем опускать (обычно используются нейронные сети).  
+
Теперь разберемся как оптимизировать правую часть. Сначала нужно определиться с <math>Q(z|X)</math> обычно ее берут равной <math>N(z|\mu(X, \theta), \sigma(X, \theta))</math>. Где <math>\mu</math> и <math>\sigma</math> какие-то детерминированные функции на X с обучаемыми параметрами <math>\theta</math>, которые мы впредь будем опускать (ага, нейронки)).  
  
  
Нетрудно проверить, что для дивергенция Кульбака-Лейблера двух нормальных распределений имеет следующий вид:
+
Нетрудно проверить, что для двух нормальных распределений с параметрами <math>D_{KL}[N(\mu_1, \Sigma_0)||N(\mu_1, \Sigma_0)]</math>, KLD есть <math>\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})) </math>.
:<math>D_{K}[N(\mu_1, \Sigma_0)||N(\mu_1, \Sigma_0)]</math>, KLD есть <math>\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})) </math>.
 
  
Это значит, что
+
Это значит, что <math>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)))</math>. Теперь здесь можно считать градиенты, для BackProp-a. С первым слагаемым в правой части, все немного сложнее. E_{z∼Q}[log P(X|z)] мы можем считать методом монте-карло(МК), но тогда такая штука (из-за того, что переменные спрятаны в распределении, из которого мы генерируем себе выборку, для МК) не является гладкой, относительно их, а значит непонятно как проталкивать через это градиент. Для того, чтобы все-таки можно было протолкнуть градиент, применяется так называемый reparametrization trick, который базируется на простой формуле <math>N(\Sigma(X), \mu(X)) = \mu(X) + \Sigma^{\frac12}(X) * N(0, I) </math>. <math>E_{z∼Q}[log P(X|z)] = E_{\epsilon~N(0, I)}[log P(X = f(\mu(X) + \Sigma^{\frac12}(X) * \epsilon), \theta)]</math>. В такой форме мы уже можем использовать BackPropagation для переменных из функций <math>\Sigma</math> и <math>\mu</math>.
:<math>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)))</math>.  
 
Теперь здесь  
 
можно считать градиенты, для BackPropagation. С первым слагаемым в правой части все немного сложнее. <math>E_{z∼Q}[log P(X|z)]</math> мы можем считать методом Монте-Карло(МК), но тогда такая штука (из-за того, что переменные спрятаны в распределении, из которого мы генерируем себе выборку, для МК) не является гладкой относительно них, а значит непонятно, как проталкивать через это градиент. Для того, чтобы все-таки можно было протолкнуть градиент, применяется так называемый ''трюк репараметризации'', который базируется на простой формуле <math>N(\Sigma(X), \mu(X)) = \mu(X) + \Sigma^{\frac12}(X) * N(0, I) </math>.  
 
  
:<math>E_{z∼Q}[log P(X|z)] = E_{\epsilon \sim N(0, I)}[log P(X = f(\mu(X) + \Sigma^{\frac12}(X) * \epsilon), \theta)]</math>.
+
Следующая картинка лучше поможет осознать структуру VAE и, в частности, зачем нужен (и как работает) reparametrization trick.  
В такой форме мы уже можем использовать BackPropagation для переменных из функций <math>\Sigma</math> и <math>\mu</math>.
 
 
 
Следующая картинка лучше поможет осознать структуру VAE и, в частности, зачем нужен (и как работает) трюк репараметризации.
 
 
 
На левой части диаграмма без использования reparameterization trick.
 
На правой части диаграмма с использованием reparameterization trick.  
 
 
 
[[Файл:VAE.PNG]]
 
 
 
взято из https://arxiv.org/pdf/1606.05908.pdf
 
  
 
== Пример реализации ==
 
== Пример реализации ==
Строка 103: Строка 88:
 
== Применение ==
 
== Применение ==
 
Область применения вариационных автокодировщиков совпадает с областью применения обыкновенных автокодировщиков. А именно:
 
Область применения вариационных автокодировщиков совпадает с областью применения обыкновенных автокодировщиков. А именно:
* Каскадное обучение глубоких сетей (хотя сейчас применяется все реже, в связи с появлением новых методов инициализации весов);
+
* Каскадное обучение глубоких сетей (хотя сейчас применяется все реже, в связи с появлением новых методов инициализации весов)
* Уменьшение шума в данных;
+
* Уменьшение шума в данных
* Уменьшение размерности данных (иногда работает лучше, чем [[метод главных компонент]]<sup>[на 28.01.19 не создан]</sup>).
+
* Уменьшение размерности данных (иногда работает лучше, чем [[метод главных компонент]])
 
 
Благодаря тому, что пользователь сам устанавливает нужное распределение скрытого вектора, вариационный кодировщик хорошо подходит для генерации новых объектов (например, картинок). Для этого достаточно разыграть скрытый вектор согласно его распределению и подать на вход декодера. Получится объект из того же распределения, что и датасет.
 
 
 
== См. также ==
 
*[[:Автокодировщик|Автокодировщик]]
 
*[[:Generative Adversarial Nets (GAN)|Порождающие состязательные сети]]
 
 
 
== Примечания ==
 
*[https://habr.com/ru/post/429276/ Вариационные автокодировщики: теория и рабочий код]
 
*[https://jaan.io/what-is-variational-autoencoder-vae-tutorial/ Tutorial - What is a variational autoencoder?]
 
*[https://towardsdatascience.com/intuitively-understanding-variational-autoencoders-1bfe67eb5daf Intuitively Understanding Variational Autoencoders]
 
  
== Источники информации ==
+
Благодаря тому, что пользователь сам устанавливает нужное распределение скрытого вектора, вариационный кодировщик хорошо подходит для генерации новых объектов (например, картинок). Для этого достаточно разыграть скрытый вектор согласно его распределению и скормить ее в декодер. Получится объект из того же распределения, что и датасет.
*[https://arxiv.org/abs/1606.05908 Tutorial on Variational Autoencoders]
 
*Datalore презентация Дениса Степанова
 
  
 
[[Категория: Машинное обучение]]
 
[[Категория: Машинное обучение]]
[[Категория: Порождающие модели]]
 

Пожалуйста, учтите, что любой ваш вклад в проект «Викиконспекты» может быть отредактирован или удалён другими участниками. Если вы не хотите, чтобы кто-либо изменял ваши тексты, не помещайте их сюда.
Вы также подтверждаете, что являетесь автором вносимых дополнений, или скопировали их из источника, допускающего свободное распространение и изменение своего содержимого (см. Викиконспекты:Авторские права). НЕ РАЗМЕЩАЙТЕ БЕЗ РАЗРЕШЕНИЯ ОХРАНЯЕМЫЕ АВТОРСКИМ ПРАВОМ МАТЕРИАЛЫ!

Чтобы изменить эту страницу, пожалуйста, ответьте на приведённый ниже вопрос (подробнее):

Отменить | Справка по редактированию (в новом окне)

Шаблон, используемый на этой странице: