Автоматическое дифференцирование

Введение

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

Основа обучения современных нейронных сетей - это обратное распространение ошибки. Представляет это собой вот что: пусть имеется некоторая модель, определяемая набором параметров \theta (в случае нейронных сетей - веса модели), и дана обучающая выборка, состоящая из l + 1 пар "объект-ответ" {(x_0, y_0),...,(x_l, y_l)}. Также определена целевая функция (функция потерь) в общем виде - J(\theta) или J(\theta)_i для i-го объекта выборки.

Сеть со случайно инициализированными весами (хотя случайность случайности рознь: существуют различные методы инициализации весов, которые напрямую влияют на обучение сети) прогоняет через себя входные данные x_i, получая итоговый ответ y_i^p, который потом сравнивается с реальным ответом y_i (речь здесь идёт об обучении с учителем) с помощью подобранной функции ошибки. Очевидно, что наша задача является оптимизационной, т.е. необходимо подобрать такие значения параметров сети, при которых значение функции ошибки минимально:

\sum_{i=0}^{l} J(\theta) \to \min\limits_{\theta}

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

\theta_{t+1} = \theta_t - \eta \cdot \frac{1}{l}\sum_{i=0}^{l} \nabla_{\theta}{J_i(\theta_t)}

где

\theta_{t+1} - обновлённый набор параметров для следующего шага оптимизации;
\theta_t - набор параметров на текущем шаге;
\eta - скорость обучения (learning rate);
\nabla_{\theta}J_i(\theta_t) - градиент функции ошибки для i-го объекта обучающей выборки.

Естественно существует множество тонких моментов и подводных камней, но здесь мы на них останавливаться не будем, главное - общий принцип. Но как градиент функции ошибки повлияет не только на параметры непосредственно выходного слоя, но и скрытых, а также входного слоя (что, собственно, и делает алгоритм обратного распространения ошибки)? Как продифференцировать функцию от миллионов параметров и не сойти с ума? Как это реализовано в PuzzleLib? Ответы на эти вопросы содержатся в трёх туториалах:

  1. Восстановление линейной функции одним нейроном;
  2. Восстановление линейной функции слоем нейронов;
  3. Восстановление нелинейной функции слоем нейронов.

Для упрощения восприятия примеры будут разобраны для двумерного случая.

Источники

  • Отличная статься на habr, которая дала толчок для написания этой серии туториалов;
  • Ещё одна замечательная статья, которая также пригодится для интересующихся темой.