Эндрю Ын: «Самый эффективный способ вычисления производных — справа налево»

DeepLearning.AI 120 тыс. 14 мин 5 мин 25.08.2017
Главное

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

🧮 Основы графа вычислений и первая производная 0:00

Рассматриваемый граф вычислений служит для пошагового нахождения функции $J$. Основная задача алгоритма обратного распространения — определить, как изменение промежуточных и входных параметров влияет на конечный результат. Если рассмотреть производную функции $J$ по отношению к переменной $v$, то математически это означает оценку изменения значения $J$ при небольшом сдвиге (или «нудже») переменной $v$. В базовом состоянии графа значение $v$ равно $11$, а функция определена как $J = 3v$, что дает начальный результат $33$.

Если искусственно увеличить значение $v$ на минимальную величину — до $11.001$, то итоговое значение функции $J$ вырастет до $33.003$. Этот простой численный эксперимент наглядно показывает, что прирост целевой переменной ровно в три раза превышает прирост аргумента. Таким образом, производная $\frac{dJ}{dv}$ равна $3$. Этот шаг аналогичен классическому дифференцированию функции вида $f(a) = 3a$, где производная $\frac{df}{da} = 3$. В терминах машинного обучения выполнение этой операции означает прохождение первого шага назад по графу вычислений.

🔗 Цепное правило и расчет производной для промежуточных переменных 2:20

Следующей задачей становится вычисление производной $\frac{dJ}{da}$, которая показывает влияние изменения входной переменной $a$ на финальную функцию $J$. Исходное значение $a$ в примере равно $5$. Если увеличить его на $0.001$ (до $5.001$), то значение следующего узла графа $v$, определяемого как $v = a + u$, также возрастет на $0.001$ и составит $11.001$. Это изменение распространяется дальше по графу слева направо, приводя к тому, что итоговое значение $J$ увеличивается до $33.003$.

Поскольку увеличение $a$ на $0.001$ вызывает рост $J$ на $0.003$, искомая производная также равна $3$. В математическом анализе этот механизм декомпозиции описывается как цепное правило (chain rule): изменение переменной $a$ напрямую влияет на $v$, а уже изменение $v$ меняет значение $J$. Величина общего изменения является произведением локальных скоростей изменений. Формула цепного правила выглядит следующим образом:

$$\frac{dJ}{da} = \frac{dJ}{dv} \cdot \frac{dv}{da}$$

Из расчетов очевидно, что при увеличении $a$ на единицу значение $v$ увеличивается ровно на столько же, то есть локальная производная $\frac{dv}{da} = 1$. Подставляя ранее найденное значение производной $\frac{dJ}{dv} = 3$, получаем итоговый результат: $3 \cdot 1 = 3$. Данная иллюстрация доказывает, что предварительное вычисление производных на более поздних этапах графа значительно упрощает нахождение градиентов для предыдущих переменных.

💻 Нотация в программном коде: упрощение имен переменных 5:40

При практической реализации алгоритма обратного распространения ошибки разработчики сталкиваются с необходимостью эффективно именовать переменные в коде. Так как ключевой задачей оптимизации является расчет производных финальной целевой переменной (которой обычно выступает функция стоимости $J$ или функция потерь $L$) по отношению ко всем остальным параметрам, стандартные математические обозначения могут перегрузить программный код. Использование длинных имен вроде dJ_over_dv или final_output_with_respect_to_v делает код трудночитаемым.

Для упрощения архитектуры ПО была принята единая конвенция именования: в коде производная финального выхода по конкретной переменной обозначается префиксом d перед именем этой переменной. Эта конвенция работает следующим образом:

В рамках рассматриваемого примера на языке Python программисту достаточно присвоить переменной dv значение $3$, а переменной da — также значение $3$.

🔄 Полный обратный проход: вычисление градиентов для всех узлов 7:57

После очистки графа вычислений и фиксации промежуточных значений dv = 3 и da = 3, алгоритм продолжает движение в обратном направлении для расчета оставшихся производных. Рассмотрим переменную $u$, базовое значение которой равно $6$. При увеличении $u$ на $0.01$ (до $6.01$) значение переменной $v$ увеличивается до $11.01$, а значение $J$ закономерно возрастает до $33.03$. Применяя цепное правило, мы получаем, что производная $\frac{dJ}{du} = \frac{dJ}{dv} \cdot \frac{dv}{du} = 3 \cdot 1 = 3$, что в программном коде соответствует переменной du = 3.

Более сложный расчет требуется для определения производной по переменной $b$, которая находится на самом левом (входном) уровне графа. Чтобы понять, как изменение $b$ влияет на $J$, необходимо вычислить произведение локальных производных по цепочке: $\frac{dJ}{db} = \frac{dJ}{du} \cdot \frac{du}{db}$. Если изменить значение $b$ с $3$ до $3.01$, это напрямую повлияет на узел $u$, который рассчитывается как произведение $b \cdot c$. При неизменном значении $c = 2$ величина $u$ возрастет с $6$ до $6.02$.

Это показывает, что локальная производная $\frac{du}{db}$ равна $2$. Перемножая её со значением du = 3, получаем финальный градиент $\frac{dJ}{db} = 3 \cdot 2 = 6$, записываемый в коде как db = 6. Сквозная проверка математических вычислений подтверждает этот вывод: при $b = 3.01$ значение $u$ становится равным $6.02$, переменная $v = 5 + 6.02 = 11.02$, а итоговая функция $J = 3 \cdot 11.02 = 33.06$, что ровно на $0.06$ больше исходного значения.

Аналогичным образом вычисляется производная для последней переменной $c$. Она определяется через произведение du на локальный коэффициент изменения, который равен значению переменной $b$ (то есть $3$). В результате расчетов градиент $\frac{dJ}{dc}$ равен $3 \cdot 3 = 9$, что на уровне программной реализации соответствует переменной dc = 9.

🎯 Главный вывод и практическое применение алгоритма 13:19

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

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

💬 Цитаты

«Основной вывод, который формулирует Эндрю Ын, заключается в том, что последовательный расчет производных справа налево (против хода основных вычислений) является наиболее эффективным вычислительным методом»

«Прямой проход (слева направо) служит для вычисления самой оптимизируемой функции стоимости, тогда как обратный проход (справа налево) предназначен исключительно для быстрого вычисления производных»

👥 Спикер
📖 Термины
Граф вычислений
Графическое представление математических операций в виде узлов и направленных ребер, используемое для визуализации и оптимизации вычислений.
Обратное распространение ошибки (Backpropagation)
Алгоритм вычисления градиентов, используемый для обучения нейронных сетей путем последовательного применения цепного правила от выхода к входу.
Цепное правило (Chain rule)
Математическое правило дифференцирования сложной функции, позволяющее находить производную как произведение производных ее составляющих.
Функция стоимости (Cost function)
Математическая функция, оценивающая качество работы модели машинного обучения путем измерения разницы между предсказаниями и реальными данными.
📊 Цифры
Искусственный интеллект Эндрю Ын граф вычислений обратное распространение цепное правило