Вероятностная интерпретация классических моделей машинного обучения

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

Классические задачи машинного обучения

Две классические задачи машинного обучения — это классификация и регрессия. Давайте посмотрим ближе на каждую из них. Рассмотрим постановку обеих задач и простейшие примеры их решения.

Классификация

Задача классификации — это задача присвоения меток объектам. Например, если объекты — это фотографии, то метками может быть содержание фотографий: содержит ли изображение пешехода или нет, изображен ли мужчина или женщина, какой породы собака изображена на фотографии. Обычно есть набор взаимоисключающих меток и сборник объектов, для которых эти метки известны. Имея такую коллекцию данных необходимо автоматически расставлять метки на произвольных объектах того же типа, что были в изначальной коллекции. Давайте формализуем это определение. Допустим, есть множество объектов $X$. Это могут быть точки на плоскости, рукописные цифры, фотографии или музыкальные произведения. Допустим также, что есть конечное множество меток $Y$. Эти метки могут быть пронумерованы. Мы будем отождествлять метки и их номера. Таким образом $Y=\{red, green, blue\}$ в нашей нотации будет обозначаться как $Y=\{1, 2, 3\}$. Если $Y=\{0, 1\}$, то задача называется задачей бинарной классификации, если меток больше двух, то обычно говорят, что это просто задача классификации. Дополнительно, у нас есть входная выборка $D=\{(x_i, y_i), x_i \in X, y_i \in Y, i=\overline{1,N}\}$. Это те самые размеченные примеры, на которых мы и будем обучаться проставлять метки автоматически. Так как мы не знаем классов всех объектов точно, мы считаем, что класс объекта — это случайная величина, которую мы для простоты тоже будем обозначать $y$. Например, фотография собаки может классифицироваться как собака с вероятностью 0.99 и как кошка с вероятностью 0.01. Таким образом, чтобы классифицировать объект, нам нужно знать условное распределение этой случайной величины на этом объекте $p(y|x)$.

Задача нахождения $p(y|x)$ при данном множестве меток $Y$ и данном наборе размеченных примеров $D=\{(x_i, y_i), x_i \in X, y_i \in Y,i=\overline{1,N}\}$ называется задачей классификации.

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

Чтобы решить эту задачу, удобно переформулировать ее на вероятностном языке. Итак, есть множество объектов $X$ и множество меток $Y$. $\xi: \Omega \to X$ — случайная величина, представляющая собой случайный объект из $X$. $\eta: \Omega \to Y$ — случайная величина, представляющая собой случайную метку из $Y$. Рассмотрим случайную величину $(\xi,\eta): \Omega \to (X, Y)$ с распределением $p(x, y)$, которое является совместным распределением объектов и их классов. Тогда, размеченная выборка — это сэмплы из этого распределения $(x_i, y_i) \sim p(x, y)$. Мы будем предполагать, что все сэмплы независимо и одинаково распределены (i.i.d в англоязычной литературе).

Задача классификации теперь может быть переформулирована как задача нахождения $p(x|y)$ при данном сэмпле $D=\{(x_i, y_i) \sim p(x, y), i=\overline{1,N}\}$.

Классификация двух нормальных распределений

Давайте посмотрим, как это работает на простом примере. Положим $X=R$, $Y=\{0, 1\}$, $p(x|y=0)=N(x; \mu_0,\sigma_0)$, $p(x|y=1)=N(x; \mu_1,\sigma_1)$, $p(y=0)=p(y=1)=1/2$. То есть, у нас есть две гауссианы, из которых мы равновероятно сэмплируем данные и нам нужно, имея точку из $R$, предсказать, из какой гауссианы она была получена.

Рис. 1. Плотности распределения $p(x|y=1)$ и $p(x|y=0)$.
Рис. 1. Плотности распределения $p(x|y=1)$ и $p(x|y=0)$.

Так как область определения гауссианы — вся числовая прямая, очевидно, что эти графики пересекаются, а значит, есть такие точки, в которых плотности вероятности $p(x|y=0)$ и $p(x|y=1)$ равны.

Найдем условную вероятность классов:

\begin{equation} p(y|x)=\frac{p(x,y)}{p(x)}=\frac{p(x|y)p(y)}{\displaystyle\sum_{l \in Y}{p(x|l)p(l)}}=\{p(y)=\frac{1}{2}\}= \frac{p(x|y)}{\displaystyle\sum_{l \in Y}{p(x|l)}} \end{equation}

Т.е. \begin{equation} p(y=i|x)=\frac{N(x;\mu_i, \sigma_i)}{\displaystyle\sum_{l \in Y}{N(x;\mu_l, \sigma_l)}} \end{equation}

Вот так будут выглядеть график плотности вероятностей $p(y=1|x)$:

Рис. 2. Плотности распределения $p(x|y=1)$, $p(x|y=0)$ и $p(y=1|x)$. $p(y=1|x)=1/2$ там, где две гауссианы пересекаются.
Рис. 2. Плотности распределения $p(x|y=1)$, $p(x|y=0)$ и $p(y=1|x)$. $p(y=1|x)=1/2$ там, где две гауссианы пересекаются.

Видно, что близко к модам гауссиан уверенность модели в принадлежности точки конкретному классу очень высока (вероятность близка к нулю или единице), а там, где графики пересекаются модель может только случайно угадывать и выдает $p(x|y=1)=p(x|y=0)=1/2$.

Метод максимизации правдоподобия

Большая часть практических задач не может быть решена вышеописанным способом, так как $p(x|y)$ обычно не задано явно. Вместо этого обычно имеется набор данных $D=\{(x_i, y_i) \sim p(x, y), i=\overline{1,N}\}$ с некоторой неизвестной совместной плотностью распределения $p(x, y)$. В таком случае для решения задачи используется метод максимального правдоподобия. Формальное определение и обоснование метода можно найти в вашей любимой книге по статистике или по ссылке выше, а в данной статье я опишу его интуитивный смысл.

Принцип максимизации правдоподобия говорит, что если есть некоторое неизвестное распределение $p(x)$, из которого есть набор сэмплов $D=\{x_i \sim p(x), i=\overline{1,N}\}$, и некоторое известное параметрическое семейство распределений $q(x|\theta)$, то для того, чтобы $q(x|\theta)$ максимально приблизило $p(x)$, нужно найти такой вектор параметров $\theta$, который максимизирует совместную вероятность данных (правдоподобие) $q(x_1,\dotsc, x_N|\theta)$, которое еще называют правдоподобием данных. Доказано, что при разумных условиях эта оценка является состоятельной и несмещенной оценкой истинного вектора параметров. Если сэмплы выбраны из $p(x)$, то есть данные i.i.d., то совместное распределение распадается на произведение распределений:

\begin{equation} \arg\ \max_{\theta} q(x_1, \dotsc, x_N|\theta)=\arg\ \max_{\theta} \prod_{i=1..N} q(x_i|\theta) \end{equation}

Логарифм и умножение на константу — монотонно возрастающие функции и не меняют положений максимумов, потому совместную плотность можно внести под логарифм и умножить на $\frac1N$:

\begin{equation} \arg\ \max_{\theta} \prod_{i=1..N} q(x_i|\theta)= \arg\ \max_{\theta} \frac{1}{N}\log\prod_{i=1..N} q(x_i|\theta)= \end{equation} \begin{equation} =\arg\ \max_{\theta} \frac{1}{N}\sum_{i=1..N} \log q(x_i|\theta) \end{equation}

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

\begin{equation} \arg\ \max_{\theta} \frac{1}{N}\sum_{i=1..N} \log q(x_i|\theta)= \arg\ \max_{\theta} \mathbb E_{x\sim p(x)} \log q(x|\theta) \end{equation}

Задачу максимизации можно переписать как задачу минимизации:

\begin{equation} \arg\ \max_{\theta} \mathbb E_{x\sim p(x)} \log q(x|\theta)= \arg\ \min_{\theta} \left( -\mathbb E_{x\sim p(x)} \log q(x|\theta) \right)= \arg\ \min_{\theta} H(p, q) \end{equation}

Последняя величина называется кросс-энтропией распределений $p$ и $q$. Именно ее и принято оптимизировать для решения задач обучения с подкреплением (supervised learning).

Минимизацию на протяжении этого цикла статей мы будем проводить с помощью Stochastic Gradient Descent (SGD), а точнее, его расширения на основе адаптивных моментов, пользуясь тем, что сумма градиентов по подвыборке (так называемому “минибатчу”) является несмещенной оценкой градиента минимизируемой функции.

Классификация двух нормальных распределений логистической регрессией

Давайте попробуем решить ту же задачу, что была описана выше, методом максимального правдоподобия, взяв в качестве параметрического семейства $q(y|x, \theta)$ простейшую нейронную сеть. Получившаяся модель называется логистической регрессией. Полный код модели можно найти тут, в статье же освещены только ключевые моменты.

Для начала нужно сгенерировать данные для обучения. Нужно сгенерировать минибатч меток классов и для каждой метки сгенерировать точку из соответствующей гауссианы:

def input_batch(dataset_params, batch_size):
    input_mean = tf.constant(dataset_params.input_mean, dtype=tf.float32)
    input_stddev = tf.constant(dataset_params.input_stddev,dtype=tf.float32)
    count = len(dataset_params.input_mean)
    labels = tf.contrib.distributions.Categorical(probs=[1./count] * count)
        .sample(sample_shape=[batch_size])
    components = []
    for i in range(batch_size):
        components
            .append(tf.contrib.distributions.Normal(
                loc=input_mean[labels[i]],
                scale=input_stddev[labels[i]])
            .sample(sample_shape=[1]))
    samples = tf.concat(components, 0)
    return labels, samples


Определим наш классификатор. Он будет простейшей нейронной сетью без скрытых слоев:

def discriminator(input):
    output_size = 1
    param1 = tf.get_variable(
        "weights",
        initializer=tf.truncated_normal([output_size], stddev=0.1)
    )
    param2 = tf.get_variable(
        "biases",
        initializer=tf.constant(0.1, shape=[output_size])
    )
    return input * param1 + param2

И запишем функцию потерь — кросс-энтропию между распределениями реальных и предсказанных меток:

labels, samples = input_batch(dataset_params, training_params.batch_size)
predicted_labels = discriminator(samples)
loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(
    labels=tf.cast(labels, tf.float32),
    logits=predicted_labels)
)

Ниже приведены графики обучения двух моделей: базовой и с L2-регуляризацией:

Рис. 3. Кривая обучения логистической регрессии.
Рис. 3. Кривая обучения логистической регрессии.

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

Рис. 4. Процесс обучения логистический регрессии.
Рис. 4. Процесс обучения логистический регрессии.

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

Регрессия

Задача регрессии — это задача предсказания одной случайной величины $\eta: \Omega \to Y$ на основе значений других случайных величин $\xi_i: \Omega \to X_i$. Например, предсказание роста человека по его полу (дискретная случайная величина) и возрасту (непрерывная случайная величина). Точно так же, как и в задаче классификации, нам дана размеченная выборка $D=\{(x_i,y_i) \sim p(x, y), i=\overline{1,N}\}$. Предсказать значение случайной величины напрямую невозможно, ведь она случайная и, по сути, является функцией, поэтому формально задача записывается как предсказание ее условного ожидаемого значения:

\[ f(x)=\mathbb E(\eta|\xi=x)= \int\limits_Y y\ p(y|x)\mathrm{d}y \]

Регрессия линейно зависимых величин с нормальным шумом

Давайте посмотрим, как решается задача регрессии на простом примере. Пусть есть две независимые случайные величины $\xi \sim Uniform(0, 10), \varepsilon \sim N(0,1)$. Например, это высота дерева и нормальный случайный шум. Тогда мы можем предположить, что возраст дерева является случайной величиной $\eta=a \xi + b + \varepsilon$. В таком случае по линейности математического ожидания и независимости $\xi$ и $\varepsilon$:

\[ f(x)=E(\eta|\xi=x)= a\ E(\xi|\xi=x)+b+E(\varepsilon|\xi=x)= \] \[ =a\ E(\xi|\xi=x)+b+E(\varepsilon)= a\ x+b+0=a\ x+b \]

Рис. 5. Линия регрессии задачи про линейно зависимые величины с шумом.
Рис. 5. Линия регрессии задачи про линейно зависимые величины с шумом.

Решение задачи регрессии методом максимального правдоподобия

Давайте сформулируем задачу регрессии через метод максимального правдоподобия. Положим $q(y|x,\theta )=N(y; f(x; w), \sigma)$. Где $w$ — новый вектор параметров. Видно, что мы ищем $f(x; w)$ — математическое ожидание $q(y|x,\theta)$, т.е. это корректно поставленная задача регрессии. Тогда

\begin{equation} \arg\ \min_{\theta} H(p, q)= \arg\ \min_{\theta} \left( -\mathbb E_{x\sim p(x)} \log q(x|\theta) \right)= \end{equation} \begin{equation} =\arg\ \min_{\theta} \left( -\mathbb E_{x\sim p(x)} \log N\left(y;f\left(x,w\right),\sigma\right) \right)= \end{equation} \begin{equation} =\arg\ \min_{\theta} \left( -\mathbb E_{(x,y) \sim p(x, y)}\frac{\left(f\left(x; w\right) - y\right)^2}{\sigma^2} \right) \end{equation}

Состоятельной и несмещенной оценкой этого матожидания будет среднее по выборке

\[ \arg\ \min_{\theta}\left( -\sum_{i=1..N}\frac{\left(f\left(x_i; w\right) - y_i\right)^2}{\sigma^2} \right) \]

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

Регрессия величины линейной регрессией

Давайте попробуем решить ту же задачу, что была выше, методом из предыдущего раздела, взяв в качестве параметрического семейства $q(y|x, \theta)$ простейшую возможную нейронную сеть. Получившаяся модель называется линейной регрессией. Полный код модели можно найти тут, в статье же освещены только ключевые моменты.

Для начала нужно сгенерировать данные для обучения. Сначала мы генерируем минибатч входных переменных $\xi \sim Uniform(0, 10), \varepsilon \sim N(0,1)$, после чего получаем сэмпл исходной переменной $\eta=a \xi + b + \varepsilon$:

def input_batch(dataset_params, batch_size):
    samples = tf.random_uniform([batch_size], 0., 10.)
    noise = tf.random_normal([batch_size], mean=0., stddev=1.)
    labels = (dataset_params.input_param1 * samples + dataset_params.input_param2 + noise)
    return labels, samples


Определим нашу модель. Она будет простейшей нейронной сетью без скрытых слоев:

def predicted_labels(input):
    output_size = 1
    param1 = tf.get_variable(
        "weights",
        initializer=tf.truncated_normal([output_size], stddev=0.1)
    )
    param2 = tf.get_variable(
        "biases",
        initializer=tf.constant(0.1, shape=[output_size])
    )
    return input * param1 + param2


И запишем функцию потерь — L2-расстояние между распределениями реальных и предсказанных значений:

labels, samples = input_batch(dataset_params, training_params.batch_size)
predicted_labels = discriminator(samples)
loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(
    labels=tf.cast(labels, tf.float32),
    logits=predicted_labels)
)


Ниже приведены графики обучения двух моделей: базовой и с L2-регуляризацией:

Рис. 6. Кривая обучения линейной регрессии.
Рис. 6. Кривая обучения линейной регрессии.

Рис. 7. График изменения первого параметра с шагом обучения.
Рис. 7. График изменения первого параметра с шагом обучения.

Рис. 8. График изменения второго параметра с шагом обучения.
Рис. 8. График изменения второго параметра с шагом обучения.

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

Рис. 9. Процесс обучения линейной регрессии.
Рис. 9. Процесс обучения линейной регрессии.

Видно, что обучаемое математическое ожидание $\eta$ постепенно сходится к аналитически вычисленному, при чем, чем оно ближе, тем медленнее сходится из-за все более слабого градиента функции потерь.

Другие задачи

В дополнение к изученным выше задачам классификации и регрессии есть и другие задачи так называемого обучения с учителем, в основном сводящиеся к отображению между точками и последовательностями: Object-to-Sequence, Sequence-to-Sequence, Sequence-to-Object. Так же есть и большой спектр классических задач обучения без учителя: кластеризация, заполнение пробелов в данных, и, наконец, явная или неявная аппроксимация распределений, которая и используется для генеративного моделирования. Именно о последнем классе задач будет идти речь в этом цикле статей.

Генеративные модели

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

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

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