Генеративное Моделирование и AI

В предыдущей главе мы поговорили о классических дискриминативных моделях в машинном обучении и разобрали простейшие примеры таких моделей. Давайте теперь посмотрим на более общую картину.

05sx9a4nprmgcf26aulbzfi9qh4.gif

Задача Искусственного Интеллекта


Искусственный Интеллект (ИИ) — это алгоритм, умеющий решать задачи, типично решаемые людьми, на уровне сопоставимом или превосходящем человеческий. Это может быть распознавание визуальных образов, понимание и анализ текстов, управление механизмами и построение логических цепочек. Система искусственного интеллекта — это система, которая сможет эффективно решать сразу все подобные задачи. Решения этой задачи до сих пор не существует, но есть разнообразные подходы, которые можно назвать первыми шагами в направлении решения проблемы ИИ.

В двадцатом веке самым популярным был подход, основанный на правилах. Его идея заключается в том, что мир подчиняется законам, которые, например, изучает физика и другие естественные науки. И даже если их нельзя эффективно запрограммировать в ИИ напрямую, разумно предположить, что при достаточном числе запрограммированных правил, ИИ система, основанная на вычислительных машинах, сможет эффективно существовать в мире, основанном на этих правилах, и решать произвольные задачи. Этот подход не учитывает естественную стохастичность некоторых событий. Чтобы ее учесть, необходимо на этом списке правил построить вероятностную модель для принятия стохастических решений при условии случайных входных данных.

Полное описание мира потребовало бы настолько большого числа правил, что их невозможно задать и поддерживать вручную. Отсюда возникает идея провести достаточно наблюдений событий в реальном мире и вывести необходимые правила автоматически из этих наблюдений. Эта идея сразу же поддерживает как действительную стохастичность некоторых естественных процессов, так дополнительно и мнимую стохастичность, возникающую из-за того, что не до конца известно, какие факторы влияют на некий детерминированный процесс. Автоматическим выводом правил из наблюдений занимается раздел математики, называемый машинным обучением, и именно оно в данный момент является наиболее обещающим фундаментом для ИИ.

Машинно обученный ИИ


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

Эти методы способны автоматически выводить правила на основе наблюдений, и они очень успешно применяются в коммерческих приложениях. Однако, у них есть недостаток, из-за которого они недостаточны для использования в качестве ИИ-системы — они специально разработаны для решения конкретной узкоспециализированной задачи, например, различать кошек и собак на изображении. Очевидно, что модель, суммирующая изображение в одно число, теряет много данных. Чтобы определить на изображении кошку не обязательно понимать суть кошки, достаточно лишь научиться искать основные признаки этой кошки. Задача классификации изображения не предполагает полного понимания сцены, а только поиск в ней конкретных объектов. Определить классификатор для всех возможных комбинаций связей всех возможных комбинаций объектов не представляется возможным хотя бы из-за экспоненциально большого объема наблюдений, которые нужно собрать и разметить. Потому идеи классических задач машинного обучения с подкреплением, в которых решается конкретная поставленная задача, не подходят. Для ИИ нужен принципиально иной подход к постановке задачи для машинного обучения.

Вероятностная постановка задачи понимания мира


Итак, нам нужно, имея набор наблюдений, в каком-то смысле понять процесс, их порождающий. Переформулируем эту задачу на вероятностном языке. Пусть наблюдение — это реализация случайной величины 6da1d64f302a295b65cba84d4078eada.gif, и есть набор наблюдаемых событий 2d3d05cab4a4f1e57731c5657c74b243.gif. Тогда «понимание» всего разнообразия событий можно сформулировать как задачу восстановления распределения 3ac7d48a793626d97a397da494839421.gif.

Есть несколько подходов к решению этой задачи. Один из самых общих методов — введение латентной переменной. Допустим, существует некое представления 44f399470b605ab36a7b4e6bf9c3c661.gif наблюдения 7790dd0efb4a03a4c876741804d9b559.gif. Это представление описывает «понимание» наблюдения моделью. Например, для кадра компьютерной игры таким пониманием может служить релевантное состояние игрового мира и положение камеры. В таком случае 3c155f7927351f2043c3597a462d47a2.gif. Фиксируя ca35570735f832b9f0f49ac5ea35fbec.gif так, чтобы оно было простым для сэмплирования распределением, мы получаем модель, в которой 8361135504256f60decbf2f084de141b.gif и 4b0717f0ea04213a65d5a6f42ddb8386.gif можно приближать нейросетями. Обучая эту модель стандартными методами глубокого обучения можно получить 3ac7d48a793626d97a397da494839421.gif по формуле выше, после чего мы можем использовать ее в вероятностном выводе. Более точные формулировки таких моделей будут в последующих частях, но тут нужно заметить, что сложные версии таких моделей требуют аппроксимации сложных невычислимых интегралов, для чего обычно используются приближенные методы вроде MCMC или Variational Inference. Построение 3ac7d48a793626d97a397da494839421.gif для извлечения из нее сэмплов называют задачей генеративного моделирования.

Можно подойти к вопросу иначе. На самом деле, в явном виде рассчитывать 3ac7d48a793626d97a397da494839421.gif, аппроксимируя сложные интегралы, не обязательно. Одна из идей состоит в том, что если модель может «вообразить» себе мир, значит, она понимает, как он устроен. Например, если я могу нарисовать человека в разных позах и ракурсах, значит я понимаю, как устроена его анатомия и перспектива в целом. Если люди не могут отличить сгенерированные моделью объекты от настоящих, значит модель смогла честно «понять», как работает то или иное явление настолько же хорошо, насколько его понимают эти люди. Эта идея вдохновляет развитие генеративного моделирования с неявной 3ac7d48a793626d97a397da494839421.gif — разработке моделей, которые, имея конечное число наблюдений, способны обобщать их и генерировать новые наблюдения, неотличимые от настоящих. Предположим, что 7f4615ad4e764c0dda1b500623cb6e9b.gif, или любое другое простое для сэмплирования распределение. Тогда при достаточно общих условиях существует функция 201c43efc4ec0b6139801bc8b66df669.gif, такая, что fcd9d766bd1120934aed1a6e3049fada.gif. В этом случае мы не получаем 3ac7d48a793626d97a397da494839421.gif в явном виде, но модель все равно содержит информацию о нем неявно. Вместо восстановления 3ac7d48a793626d97a397da494839421.gif можно восстановить a7ade42fbdb03eddb77600e3f9ae2bfe.gif, после чего сэмплы из 3ac7d48a793626d97a397da494839421.gif могут быть получены как 3f715d2c3abbe583d6f29a1822af9710.gif. a7ade42fbdb03eddb77600e3f9ae2bfe.gif нельзя использовать в вероятностном выводе напрямую, но, во-первых, это не всегда нужно, а во-вторых, когда это нужно, часто можно воспользоваться методами Монте-Карло, для которых как раз и нужно получать сэмплы. К методам этого типа относится и модель Generative Adversarial Networks, исследуемая в следующей части.

Principal Component Analysis


Давайте посмотрим на простую генеративную модель. Пусть есть некая наблюдаемая величина ae2aaefc6f763bd300279266de63ecb4.gif. Например это может быть рост человека или пиксельное изображение. Предположим, что эта величина полностью объясняется некой скрытой (латентной) величиной 44f399470b605ab36a7b4e6bf9c3c661.gif. В нашей аналогии это может быть вес человека или объект и его ориентация на изображении. Предположим теперь, что для скрытой величины 8e98142d609bd2e16e35679151ea55db.gif, а наблюдаемое величина линейно зависит от с нормальным шумом, т.е. de55b69567ac6599a60e4a26e433b480.gif. Эта модель называется Probabilistic Principal Component Analysis (PPCA) и она, по сути, является вероятностной переформулировкой классической модели Principal Component Analysis (PCA), в которой видимая переменная 7790dd0efb4a03a4c876741804d9b559.gif линейно зависит от латентной переменной f5cc9e47883d3f86d5795d82e36323c4.gif без шума.

Expectation Maximization


Expectation Maximization (EM) — алгоритм для обучения моделей с латентными переменными. Детали можно найти в специализированной литературе, но общая суть алгоритма довольно проста:

  1. Инициализировать модель начальными значениями параметров.
  2. E-шаг. Заполнить латентные переменные их ожидаемыми значениями в текущей модели.
  3. M-шаг. Максимизировать правдоподобие модели с фиксированными значениями латентных переменных. Например, градиентным спуском по параметрам.
  4. Повторять (2, 3), пока ожидаемые значения латентных переменных не перестанут изменяться.


Если на М-шаге не максимизировать правдоподобие до конца, а только делать шаг в направлении максимума, это называется Generalized EM (GEM).

Решение PCA с помощью EM


Применим к нашей модели PCA EM алгоритм и метод максимума правдоподобия для поиска оптимальных параметров 73c8e43cf4fc8ec0fe30f50441e7c1b1.gif модели. Совместное правдоподобие наблюдаемых и латентных параметров можно записать как:

8a0879de6fc0f26e8f43cfe4c2afec55.gif


Где 623c539132e71fa79a9088c940c4bf33.gif — это произвольное распределение. Далее будем опускать условность распределений по параметрам для облегчения формул.

471fdecc1edf92fc4b59314c8d233724.gif


bbab4d779c205d76a65fc7078ab45b22.gif


d6d2d463ccdf4891d4195a7a8a165879.gif


Где величина eef01738fb8b22cb3ceabb2126bdd51b.gif называется dcf936eab85d6d0539498d793c847eaa.gif-дивергенцией между распределениями 623c539132e71fa79a9088c940c4bf33.gif и 4b0717f0ea04213a65d5a6f42ddb8386.gif. Величина b5a67a0fa3b56e982b1ac0dcc013b892.gif называется энтропией 623c539132e71fa79a9088c940c4bf33.gif. 66eae465795b50b44d1af7a3f15abc0c.gif не зависит от параметров d74edaaf2305d2d981f9c13219e34f36.gif, поэтому это слагаемое мы можем игнорировать при оптимизации:

71014b63aedba03d5b154a45dafacc98.gif


46c6e05a4976e20fe646665343cd6f98.gif


d78071a3efe1643c98fc5d97990f5f14.gif


141d42011206d4237c7ad23456027b66.gif


Величина daed3aaf1aea81782be4d3f8f38a1878.gif неотрицательна и равна нулю когда c45d9d43f8eefb054db07da4844e5bf9.gif. В связи с этим давайте определим следующий EM алгоритм:

  1. E: 121baefa6432a90d29b8b85f198b935d.gif. Это обнулит второе слагаемое daed3aaf1aea81782be4d3f8f38a1878.gif.
  2. M: Максимизация первого слагаемого a574f35907709b2aa9a32b55ec5c9066.gif.


PPCA — линейная модель, потому ее можно решить аналитически. Но вместо этого мы попробуем решить ее с помощью обобщенного EM-алгоритма, когда максимизация выполняется не до конца, а только одним шагом градиентного подъема в сторону оптимума. Более того, мы будем использовать стохастический градиентный подъем, т.е. его шаг будет шагом в сторону оптимума только в среднем. Так как наши данные i.i.d., то

488cc5188714316b339d1c82b233649b.gif


Заметим, что выражение вида 63552368adfd483194dfb7984809eaec.gif является математическим ожиданием 0db00dabb27cf9b363a9f519fae3914f.gif. Тогда

f79ac55865207217729606a40cef2a30.gif


Так как единичный сэмпл является несмещенной оценкой математического ожидания, то можно приближенно записать следующее равенство:

201fdb9667b3fb0569ed5f95489fb185.gif


Итого, подставляя de55b69567ac6599a60e4a26e433b480.gif, получим:

bb1e4cd911a8de5ab6adb338da78db38.gif


0b2d43fc19680963c1ca56edfd716920.gif


84ccc2e8fff30f3082ba362ca191be45.gif


7349525fb2ecd57b55c3e533d8c403e5.gif


или

d021cc6d45dc02c7f18b80ba26d1ddde.gif


Формула 1. Функция потерь, пропорциональная правдоподобию данных в модели PPCA.

Где dab8f201ba10fb5a14e991ab157a9c7c.gif — размерность наблюдаемой переменной 7790dd0efb4a03a4c876741804d9b559.gif. Теперь выпишем GEM-алгоритм для PPCA. de55b69567ac6599a60e4a26e433b480.gif, а 77544815ecc8152dfb82a7332bfbaf86.gif. Тогда GEM-алгоритм будет выглядеть так:

  1. Инициализируем параметры a09bfcd75045bc4ff04418f04cb289c2.gif разумными случайными начальными приближениями.
  2. Сэмплируем a00af10bc510d574f9ddfb2a6298ae4c.gif — выборка минибатча из данных.
  3. Рассчитываем ожидаемые значения латентных переменных e571c5e73152d7a3b37f5e0162c981a7.gif или eaec23e96173a89c36c897fbfde1461f.gif.
  4. Подставляем 7de633f3f2eff57c39c70e342761c825.gif в формулу (1) для 7e075493316fca3e9542548c38116492.gif и делаем шаг градиентного подъема по параметрам. Важно помнить, что b6c074598e5cedd50d95fe57d5bce90b.gif надо воспринимать как входы, и не пускать обратное распространение ошибки внутрь него.
  5. Если правдоподобие данных и ожидаемые значения латентных переменных для контрольных видимых переменных не сильно изменяются, останавливаем обучение. Иначе, идем на шаг (2).


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

dc181083be65d41ddad5e18d0897fed5.gif

Численное решение задачи PCA


Давайте обучим модель PPCA с помощью стандартного SGD. Мы опять будем изучать работу модели на игрушечном примере, чтобы понять все детали. Полный код модели можно найти тут, а в этой статье будут освещены лишь ключевые моменты.

Положим f939887b4f4ea46f31f77bbb830f4e3f.gif — двумерное нормальное распределение с диагональной ковариационной матрицей. 8e98142d609bd2e16e35679151ea55db.gif — одномерное нормальное латентное представление.

kbaascwgzdhtpctkeiamtvrisis.png


Рис. 1. Эллипс вокруг среднего, в который попадает 95% точек из распределения 3ac7d48a793626d97a397da494839421.gif.

Итак, первое, что нужно сделать — это сгенерировать данные. Мы генерируем сэмплы из 3ac7d48a793626d97a397da494839421.gif:

def normal_samples(batch_size):
  def example():
    return tf.contrib.distributions.MultivariateNormalDiag(
     [5, 10], [1.2, 2.4]).sample(sample_shape=[1])[0]
  return tf.contrib.data.Dataset.from_tensors([0.])
    .repeat()
    .map(lambda x: example())
    .batch(batch_size)


Теперь нужно определить параметры модели:

input_size = 2
latent_space_size = 1
stddev = tf.get_variable(
  "stddev", initializer=tf.constant(0.1, shape=[1]))
biases = tf.get_variable(
  "biases", initializer=tf.constant(0.1, shape=[input_size]))
weights = tf.get_variable(
  "Weights",
   initializer=tf.truncated_normal(
     [input_size, latent_space_size], stddev=0.1))


После этого можно получить для сэмпла видимых переменных их латентные представления:

def get_latent(visible, latent_space_size, batch_size):
  matrix = tf.matrix_inverse(
    tf.matmul(weights, weights, transpose_a=True)
      + stddev**2 * tf.eye(latent_space_size))
  mean_matrix = tf.matmul(matrix, weights, transpose_b=True)
  # Multiply each vector in a batch by a matrix.
  expected_latent = batch_matmul(
    mean_matrix, visible - biases, batch_size)
  stddev_matrix = stddev**2 * matrix
  noise =
    tf.contrib.distributions.MultivariateNormalFullCovariance(
      tf.zeros(latent_space_size),
      stddev_matrix)
        .sample(sample_shape=[batch_size])
  return tf.stop_gradient(expected_latent + noise)


Тут нужно обратить внимание на tf.stop_gradient (…). Эта функция не дает значениям параметров внутри входного подграфа влиять на градиент по этим параметрам. Это нужно, чтобы 121baefa6432a90d29b8b85f198b935d.gif оставалось фиксированным в течении M-шага, что необходимо для корректной работы EM-алгоритма.

Давайте теперь запишем функцию потерь 7e075493316fca3e9542548c38116492.gif для оптимизации на M-шаге:

sample = dataset.get_next()
latent_sample = get_latent(sample, latent_space_size, batch_size)
norm_squared = tf.reduce_sum((sample - biases -
  batch_matmul(weights, latent_sample, batch_size))**2, axis=1)
loss = tf.reduce_mean(
  input_size * tf.log(stddev**2) + 1/stddev**2 * norm_squared)
train = tf.train.AdamOptimizer(learning_rate)
  .minimize(loss, var_list=[bias, weights, stddev], name="train")

Итак, модель готова для тренировки. Давайте взглянем на кривую обучения модели:

vblcggfdlrodyjqrsbf68elbmxy.png


Рис. 2. Кривая обучения модели PPCA.

Видно, что модель достаточно регулярно и быстро сходится, что хорошо отражает простоту модели. Давайте посмотрим на выученные параметры распределения.

lwu6yde05yixhwky3zsvjuluyz0.png


6ax2y24xzzhbip5g8cbtmvcglog.png


Рис. 3. Графики смещения от начала координат (параметра a07675eb420c5a094218ccaf1bb3763f.gif).

Видно, что e0ddd641d93ee0cb5bd7d1bb86f1a672.gif быстро сошлись к аналитическим значениям 134b46c4e9511d2584e1aac895f801e9.gif и 37eeaae1f44c27ea16c331c7cf54ee4a.gif. Давайте теперь посмотрим на параметры e419ae26568307428c20e5949e3c9341.gif:

xudthn7f8i6uaevdaxkddlebfes.png


Рис. 4. График изменения параметра 5a44d08a2c46ced5dd1a8786e2d30d12.gif.

Видно, что значение 5a44d08a2c46ced5dd1a8786e2d30d12.gif сошлось к 1.2, т.е. к меньшей оси отклонения входного распределения, как и ожидалось.

nr6rjqsz6cxka0zvzgcvb8xfu6u.png


ygv_4dohosewrh5kvhp2mdfvfre.png


Рис. 5. Графики изменения параметров c7d708483c844dcac146d4ccb8b1455f.gif.

982ba703f70cd3d04aa174ca0d31e9ac.gif, в свою очередь, сошлось к примерно такому значению, при котором c4d2c766c934af8c03c8e9cd6afdca59.gif. Подставляя эти значения в модель, мы получаем bc32ccc5bebfb35a0f8f146c32560095.gif, что значит, что мы восстановили распределение данных.

Давайте посмотрим на распределения данных. Латентная переменная одномерна, потому она отображена как одномерное распределение. Видимая переменная же двумерна, но ее заданная матрица ковариации диагональна, что значит, что ее эллипсоид выровнен с осями координат. Потому мы отобразим ее как две проекции ее распределения на оси координат. Так выглядят заданное и выученное распределение 3ac7d48a793626d97a397da494839421.gif в проекции на первую ось координат:

mckyw8nolc-a7gr3e5ye1ouurdi.png


Рис. 6. Проекция заданного распределения 3ac7d48a793626d97a397da494839421.gif на первую ось координат.

f7rvnqsuavrezx3hat5klm3maoi.png


Рис. 7. Проекция выученного распределения ea21e57713a2421d18493c52b4cc5945.gif на первую ось координат.

А так выглядят заданное и выученное распределение 3ac7d48a793626d97a397da494839421.gif в проекции на вторую ось координат:

cwq71k1uhhvjdzm33iyf1hpt1vg.png


Рис. 8. Проекция заданного распределения 3ac7d48a793626d97a397da494839421.gif на вторую ось координат.

iswapwivuoovhust5p0ccqtzfnq.png


Рис. 9. Проекция выученного распределения ea21e57713a2421d18493c52b4cc5945.gif на вторую ось координат.

А так выглядят аналитическое и выученное распределения ca35570735f832b9f0f49ac5ea35fbec.gif:
lbtgtiowdedumc_25cff0acshyk.png
Рис. 10. Заданное распределение 8e98142d609bd2e16e35679151ea55db.gif.

8l3hk3mj2-tldqe4j4pex3yinyw.png
Рис. 11. Выученное распределение 82965b7e8f7bfad6e3aa6ae3945271f8.gif.

Видно, что все выученные распределения сходятся к распределениям, очень похожим на заданные задачей. Давайте посмотрим на динамику обучения модели, чтобы убедиться в этом окончательно:

05sx9a4nprmgcf26aulbzfi9qh4.gif


Рис. 12. Процесс обучения модели PPCA, при котором выученное распределение 82965b7e8f7bfad6e3aa6ae3945271f8.gif сходится к распределению данных 3ac7d48a793626d97a397da494839421.gif.

Заключение


Приведенная модель — это вероятностная интерпретация классической модели PCA, которая является линейной моделью. Мы использовали математику из оригинальной статьи, построили GEM алгоритм поверх нее и показали, что получившаяся модель сходится к аналитическому решению на простом примере. Разумеется, если бы в задаче 3ac7d48a793626d97a397da494839421.gif не было нормальным, модель бы не справилась так хорошо. Точно так же, как PCA не справляется идеально с данными, не лежащими в некой гиперплоскости. Для решения более сложных задач аппроксимации распределений нам понадобятся более сложные и нелинейные модели. Об одной из таких моделей, Generative Adversarial Networks, и пойдет речь в следующей статье.

Благодарности


Спасибо Olga Talanova за ревью текста. Спасибо Andrei Tarashkevich за помощь с версткой этой статьи.

© Habrahabr.ru