Вероятностное глубокое обучение

Введение

Эта статья относится к серии «Вероятностное глубокое обучение». Эта еженедельная серия охватывает вероятностные подходы к глубокому обучению. Основная цель состоит в том, чтобы расширить модели глубокого обучения для количественной оценки неопределенности, то есть узнать, чего они не знают.

Мы разрабатываем наши модели, используя TensorFlow и TensorFlow Probability (TFP). TFP — это библиотека Python, построенная поверх TensorFlow. Мы собираемся начать с основных объектов, которые мы можем найти в TFP, и понять, как мы можем ими манипулировать. В течение следующих недель мы будем постепенно увеличивать сложность и объединять наши вероятностные модели с глубоким обучением на современном оборудовании (например, на графическом процессоре).

Статьи, опубликованные на данный момент:

  1. Нежное введение в вероятность TensorFlow: объекты распределения
  2. Нежное введение в вероятность TensorFlow: обучаемые параметры
  3. Оценка максимального правдоподобия с нуля в TensorFlow Probability
  4. Вероятностная линейная регрессия с нуля в TensorFlow
  5. Вероятностная и детерминированная регрессия с Tensorflow
  6. Частотник против байесовской статистики с Tensorflow

Как обычно, код доступен на моем GitHub.

Объекты распределения

В прошлой статье мы увидели, как манипулировать объектами распределения TFP. Помните, что объекты распределения охватывают основные операции над распределениями вероятностей. Мы начали с одномерных распределений, то есть распределений только с одной случайной величиной. Затем мы расширили наше понимание того, как представлять многомерные распределения с помощью свойств объектов распределения. Мы сохранили простоту, поскольку определили двумерное распределение Гаусса и не включили никакой корреляции между двумя измерениями. Наиболее важными свойствами, которые следует запомнить, являются batch_shape и event_shape. Если вы еще не знакомы с ними, пожалуйста, проверьте мою предыдущую статью. Мы будем широко использовать их в этой серии.

Мы рассмотрим еще одну концепцию, касающуюся объектов распределения, прежде чем перейти к введению обучаемых параметров распределения.

Независимое распространение

Бывают случаи, когда мы хотим интерпретировать набор независимых распределений по пространству событий как единое совместное распределение по продукту пространств событий. Это влияет на то, как мы обрабатываем свойства batch_shape и event_shape. Независимое распределение будет очень полезно, когда мы начнем создавать некоторые известные алгоритмы, такие как наивный байесовский классификатор. Причина в том, что в случае наивного байесовского метода функции не зависят от метки класса.

Для иллюстрации давайте определим два нормальных распределения.

Первый представляет собой многомерную нормаль вида:

Чтобы определить первый, мы собираемся использовать MultivariateNormalDiag, как и раньше, поскольку, опять же, измерения между ними не коррелируют.

mv_normal = tfd.MultivariateNormalDiag(loc=[0, 1], scale_diag=[1,2])

<tfp.distributions.MultivariateNormalDiag 'MultivariateNormalDiag' batch_shape=[] event_shape=[2] dtype=float32>

Мы привыкаем к свойствам формы, поэтому неудивительно, что у нас есть event_shape из 2.

Как обычно, мы можем вычислить логарифмическую вероятность:

mv_normal.log_prob([0.2, 1.5])

<tf.Tensor: shape=(), dtype=float32, numpy=-2.5822742>

Мы получаем одно значение, так как у нас есть одно распределение, хотя оно и многомерно.

Давайте возьмем образец из нашего независимого многомерного распределения Гаусса и построим совместное распределение. Мы делали что-то подобное раньше.

samples = mv_normal.sample(10000).numpy()
x1 = samples[:,0]
x2 = samples[:,1]
sns.jointplot(x = x1, y = x2, kind='kde', xlim=[-6, 7], ylim=[-6, 7]);

Как и ожидалось, корреляции между измерениями нашего многомерного распределения Гаусса нет.

Время для представления пакетного объекта распределения Гаусса.

locs = [0,1]
scales = [1, 2]

batched_normal = tfd.Normal(loc=locs, scale=scales)
batched_normal

<tfp.distributions.Normal 'Normal' batch_shape=[2] event_shape=[] dtype=float32>

Обратите внимание на batch_shape, равное 2.

batched_normal.log_prob([0.2, 1.5])

<tf.Tensor: shape=(2,), dtype=float32, numpy=array([-0.9389385, -1.6433357], dtype=float32)>

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

Мы можем построить функцию плотности вероятности (PDF) обоих одномерных распределений.

x = np.linspace(-4, 4, 10000)
densities = batched_normal.prob(np.repeat(x[:, np.newaxis], 2, axis=1))

sns.lineplot(x=x, y=densities[:, 0], label=f'loc={locs[0]}, scale={scales[0]}')
sns.lineplot(x=x, y=densities[:, 1], label=f'loc={locs[1]}, scale={scales[1]}')
plt.ylabel('Probability Density')
plt.xlabel('Value')
plt.legend()
plt.show()

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

Чтобы помочь нам понять, что такое независимое распределение и чем оно полезно, давайте поиграем с вероятностным жаргоном:

  • Независимое распределение — это упрощенный способ перехода от одномерного распределения к единственному многомерному распределению;
  • Независимое распределение позволяет перейти от нескольких распределений одной случайной величины к совместному распределению набора случайных величин;
  • Независимое распределение дает возможность перейти от нескольких пакетных распределений к единому многомерному распределению;
  • Независимое распределение — это интерфейс для поглощения любых измерений, которые мы хотим включить в измерение событий;
  • Наконец, более прагматичный способ описания TFP — независимое распределение — это способ переместить batch_shape размеров распределения в event_shape нового объекта распределения.

Будем надеяться, что такое многообразное описание сделало все эти вероятностные концепции и то, как они были переведены в абстракции TFP, более понятными.

Время применить теоретические концепции и увидеть практическую реализацию.

independent_normal = tfd.Independent(batched_normal, reinterpreted_batch_ndims=1)
independent_normal

<tfp.distributions.Independent 'IndependentNormal' batch_shape=[] event_shape=[2] dtype=float32>

Пакетное гауссово распределение теперь представляет собой объект распределения IndependentNormal, который является независимым многомерным гауссовым распределением, как мы определили выше. Мы можем видеть это по event_shape из 2. Точно так же логарифмическая вероятность теперь должна давать одно значение.

<tf.Tensor: shape=(), dtype=float32, numpy=-2.5822742>

Наконец, давайте сравним график независимого распределения Гаусса с тем, что мы показали выше.

samples = independent_normal.sample(10000).numpy()
x1 = samples[:,0]
x2 = samples[:,1]
sns.jointplot(x = x1, y = x2, kind='kde', space=0, color='b', xlim=[-6, 7], ylim=[-6, 7]);

Обучаемые параметры

Переменные

Теперь, когда мы знаем, что такое объекты TensorFlow Probability, пришло время понять, как мы можем обучать параметры для этих распределений. Это та связь, которой нам не хватает, чтобы начать применять то, что мы узнали, и строить алгоритмы.

В TensorFlow объекты Variable — это то, что мы используем для захвата значений параметров наших моделей глубокого обучения. Эти объекты обновляются во время обучения, например, путем применения градиентов, полученных из функции потерь и данных.

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

init_vals = tf.constant([[1.0, 2.0], [3.0, 4.0]])
new_variable = tf.Variable(init_vals)
new_variable

<tf.Variable 'Variable:0' shape=(2, 2) dtype=float32, numpy=
array([[1., 2.],
       [3., 4.]], dtype=float32)>

Variable очень похож на тензор. Они имеют схожие свойства, такие как shape и dtype, а также методы/операции, например. экспортировать в NumPy. У них есть некоторые отличия, например, они не могут быть изменены.

print("shape: ", new_variable.shape)
print("dType: ", new_variable.dtype)
print("as NumPy: ", new_variable.numpy())
print("Index of highest value:", tf.math.argmax(new_variable))

shape:  (2, 2)
dType:  <dtype: 'float32'>
as NumPy:  [[1. 2.]
 [3. 4.]]
Index of highest value: tf.Tensor([1 1], shape=(2,), dtype=int64)

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

variable_not_diff = tf.Variable(1, trainable=False)

<tf.Variable 'Variable:0' shape=() dtype=int32, numpy=1>

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

Существует API, который мы будем использовать для автоматической дифференциации — tf.GradientTape. При обратном подключении к объекту Variable этот API дает нам возможность вычислить градиент операции относительно наших входных данных, то есть одного или нескольких объектов Variable.

Давайте сделаем быстрый пример, используя tf.GradientTape API и объект Variable.

x = tf.Variable(3.0)

with tf.GradientTape() as tape:
    y = x**2

Как только мы определили операцию внутри контекста tf.GradientTape, мы можем вызвать метод gradient и передать потери и входные переменные.

dy_dx = tape.gradient(y, x)
dy_dx.numpy()

6.0

Пришло время применить эти концепции к нашей проблеме. Напомним, что нас интересует изучение параметров распределения.

normal = tfd.Normal(loc=tf.Variable(0., name='loc'), scale=5)
normal.trainable_variables

(<tf.Variable 'loc:0' shape=() dtype=float32, numpy=0.0>,)

В этом случае среднее значение распределения Гаусса, определенное выше, больше не простое значение, а Variable объект, который можно изучить.

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

PDF непрерывной случайной величины примерно указывает вероятность того, что выборка примет определенное значение. Обозначим эту функцию 𝑃(𝑥|𝜃), где 𝑥 — значение выборки, а 𝜃 — параметр, описывающий распределение вероятностей:

tfd.Normal(0, 1).prob(0)

<tf.Tensor: shape=(), dtype=float32, numpy=0.3989423>

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

Чтобы завершить это введение в параметры обучения, давайте свяжем эту концепцию с независимыми объектами распределения, которыми мы также поделились выше. Когда несколько выборок берутся независимо из одного и того же распределения (что мы обычно предполагаем), PDF значений выборки 𝑥1,…,𝑥𝑛 является продуктом PDF-файлов для каждого отдельного 𝑥𝑖. Мы можем записать это как:

Надеюсь, вы видите, как обе концепции пересекаются в приведенном выше определении.

Заключение

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

На следующей неделе мы более подробно изучим процедуру обучения распределений. Тогда увидимся!

Оставайтесь на связи: LinkedIn

Ссылки и материалы

[1] — Coursera: специализация глубокого обучения

[2] — Coursera: TensorFlow 2 для глубокого обучения Специализация

[3] — Руководства и учебные пособия по вероятностям TensorFlow

[4] — Сообщения о вероятностях TensorFlow в блоге TensorFlow