.. _sec_optimization-intro: Оптимизация и глубокое обучение =============================== В этом разделе мы обсудим взаимосвязь между оптимизацией и глубоким обучением, а также проблемы, возникающие при использовании оптимизации в глубоком обучении. Для задачи глубокого обучения мы обычно сначала определяем *функцию потерь*. Получив функцию потерь, мы можем использовать алгоритм оптимизации для минимизации этой функции. В оптимизации функцию потерь часто называют *целевой функцией* задачи оптимизации. По традиции и соглашению большинство алгоритмов оптимизации ориентированы на *минимизацию*. Если же нам нужно максимизировать целевую функцию, решение простое: достаточно изменить знак целевой функции на противоположный. Цель оптимизации ---------------- Хотя оптимизация позволяет минимизировать функцию потерь в глубоком обучении, по своей сути цели оптимизации и глубокого обучения фундаментально различны. Первая в первую очередь сосредоточена на минимизации целевой функции, тогда как вторая — на поиске подходящей модели при наличии конечного объёма данных. В :numref:`sec_generalization_basics` мы подробно обсудили различие между этими двумя целями. Например, ошибка на обучающей выборке и ошибка обобщения, как правило, различаются: поскольку целевой функцией алгоритма оптимизации обычно является функция потерь, вычисленная на обучающем наборе данных, целью оптимизации является уменьшение ошибки на обучающей выборке. Однако цель глубокого обучения (или, шире, статистического вывода) заключается в уменьшении ошибки обобщения. Для достижения этой цели нам необходимо обращать внимание на переобучение, помимо использования алгоритма оптимизации для снижения ошибки на обучающей выборке. .. raw:: latex \diilbookstyleinputcell .. code:: python %matplotlib inline import numpy as np import torch from mpl_toolkits import mplot3d from d2l import torch as d2l Чтобы проиллюстрировать указанные выше различные цели, рассмотрим эмпирический риск и риск. Как описано в :numref:`subsec_empirical-risk-and-risk`, эмпирический риск — это средние потери на обучающем наборе данных, тогда как риск — это ожидаемые потери на всей совокупности данных. Ниже мы определяем две функции: функцию риска ``f`` и функцию эмпирического риска ``g``. Предположим, что у нас есть лишь конечный объём обучающих данных. В результате функция ``g`` менее гладкая, чем функция ``f``. .. raw:: latex \diilbookstyleinputcell .. code:: python def f(x): return x * torch.cos(np.pi * x) def g(x): return f(x) + 0.2 * torch.cos(5 * np.pi * x) На графике ниже показано, что минимум эмпирического риска на обучающем наборе данных может находиться в другом месте по сравнению с минимумом риска (обобщающей ошибки). .. raw:: latex \diilbookstyleinputcell .. code:: python def annotate(text, xy, xytext): #@save d2l.plt.gca().annotate(text, xy=xy, xytext=xytext, arrowprops=dict(arrowstyle='->')) x = torch.arange(0.5, 1.5, 0.01) d2l.set_figsize((4.5, 2.5)) d2l.plot(x, [f(x), g(x)], 'x', 'risk') annotate('min of\nempirical risk', (1.0, -1.2), (0.5, -1.1)) annotate('min of risk', (1.1, -1.05), (0.95, -0.5)) Проблемы оптимизации в глубоком обучении ---------------------------------------- В этой главе мы сосредоточимся именно на эффективности алгоритмов оптимизации при минимизации целевой функции, а не на ошибке обобщения модели. В :numref:`sec_linear_regression` мы провели различие между аналитическими и численными решениями в задачах оптимизации. В глубоком обучении большинство целевых функций сложны и не имеют аналитических решений. Вместо этого мы должны использовать алгоритмы численной оптимизации. Все алгоритмы оптимизации в этой главе относятся к этой категории. В оптимизации глубокого обучения существует множество проблем. Наиболее сложные из них — локальные минимумы, седловые точки и затухающие градиенты. Рассмотрим их. Локальные минимумы ~~~~~~~~~~~~~~~~~~ Для любой целевой функции :math:`f(x)`, если значение :math:`f(x)` в точке :math:`x` меньше значений :math:`f(x)` в любой другой точке окрестности :math:`x`, то :math:`f(x)` может быть локальным минимумом. Если значение :math:`f(x)` в точке :math:`x` является минимумом целевой функции на всей области определения, то :math:`f(x)` — глобальный минимум. Например, для функции .. math:: f(x) = x \cdot \textrm{cos}(\pi x) \textrm{ for } -1.0 \leq x \leq 2.0, мы можем аппроксимировать локальный и глобальный минимумы этой функции. .. raw:: latex \diilbookstyleinputcell .. code:: python x = torch.arange(-1.0, 2.0, 0.01) d2l.plot(x, [f(x), ], 'x', 'f(x)') annotate('local minimum', (-0.3, -0.25), (-0.77, -1.0)) annotate('global minimum', (1.1, -0.95), (0.6, 0.8)) Целевая функция моделей глубокого обучения обычно имеет множество локальных оптимумов. Когда численное решение задачи оптимизации находится вблизи локального оптимума, решение, полученное на финальной итерации, может минимизировать целевую функцию лишь *локально*, а не *глобально*, поскольку градиент целевой функции приближается к нулю или становится равным нулю. Лишь некоторый уровень шума может вывести параметр из локального минимума. На самом деле, это одно из полезных свойств стохастического градиентного спуска на мини-батчах, поскольку естественные колебания градиентов в рамках мини-батчей способны вывести параметры из локальных минимумов. Седловые точки ~~~~~~~~~~~~~~ Помимо локальных минимумов, седловые точки — ещё одна причина исчезновения градиентов. *Седловая точка* — это любая точка, в которой все градиенты функции обращаются в ноль, но которая не является ни глобальным, ни локальным минимумом. Рассмотрим функцию :math:`f(x) = x^3`. Её первая и вторая производные обращаются в ноль при :math:`x=0`. Оптимизация может застрять в этой точке, даже если она не является минимумом. .. raw:: latex \diilbookstyleinputcell .. code:: python x = torch.arange(-2.0, 2.0, 0.01) d2l.plot(x, [x**3], 'x', 'f(x)') annotate('saddle point', (0, -0.2), (-0.52, -5.0)) В многомерном пространстве седловые точки проявляют себя ещё коварнее, как показывает пример ниже. Рассмотрим функцию :math:`f(x, y) = x^2 - y^2`. Её седловая точка находится в точке :math:`(0, 0)`. Это максимум по направлению :math:`y` и минимум по направлению :math:`x`. Более того, она *выглядит* как седло, откуда и произошло название этого математического свойства. .. raw:: latex \diilbookstyleinputcell .. code:: python x, y = torch.meshgrid( torch.linspace(-1.0, 1.0, 101), torch.linspace(-1.0, 1.0, 101)) z = x**2 - y**2 ax = d2l.plt.figure().add_subplot(111, projection='3d') ax.plot_wireframe(x, y, z, **{'rstride': 10, 'cstride': 10}) ax.plot([0], [0], [0], 'rx') ticks = [-1, 0, 1] d2l.plt.xticks(ticks) d2l.plt.yticks(ticks) ax.set_zticks(ticks) d2l.plt.xlabel('x') d2l.plt.ylabel('y'); Мы предполагаем, что вход функции является вектором размерности :math:`k`, а выход — скаляром, поэтому матрица Гесса будет иметь :math:`k` собственных значений. Решение функции может соответствовать локальному минимуму, локальному максимуму или седловой точке в точке, где градиент функции равен нулю: - Когда все собственные значения матрицы Гессе функции в точке с нулевым градиентом положительны, мы имеем локальный минимум функции. - Если все собственные значения матрицы Гессе функции в точке с нулевым градиентом отрицательны, то функция имеет локальный максимум. - Когда собственные значения матрицы Гессе функции в точке с нулевым градиентом имеют как отрицательные, так и положительные значения, мы имеем дело с седловой точкой функции. Для задач высокой размерности вероятность того, что хотя бы *некоторые* из собственных значений отрицательны, довольно велика. Это делает седловые точки более вероятными, чем локальные минимумы. В следующем разделе, при введении понятия выпуклости, мы обсудим некоторые исключения из этой ситуации. Проще говоря, выпуклыми называются функции, у которых собственные значения гессиана никогда не бывают отрицательными. К сожалению, большинство задач глубокого обучения не относятся к этому классу. Тем не менее выпуклые функции являются отличным инструментом для изучения алгоритмов оптимизации. Исчезающие градиенты ~~~~~~~~~~~~~~~~~~~~ Вероятно, самой коварной проблемой является затухание градиентов. Вспомним часто используемые функции активации и их производные в :numref:`subsec_activation-functions`. Например, предположим, что мы хотим минимизировать функцию :math:`f(x) = \tanh(x)` и начинаем с точки :math:`x = 4`. Как видно, градиент функции :math:`f` близок к нулю. Более конкретно, :math:`f'(x) = 1 - \tanh^2(x)`, а следовательно, :math:`f'(4) = 0.0013`. В результате оптимизация надолго застывает, прежде чем мы сможем добиться прогресса. Это оказывается одной из причин, по которым обучение моделей глубокого обучения было довольно сложной задачей до появления функции активации ReLU. .. raw:: latex \diilbookstyleinputcell .. code:: python x = torch.arange(-2.0, 5.0, 0.01) d2l.plot(x, [torch.tanh(x)], 'x', 'f(x)') annotate('vanishing gradient', (4, 1), (2, 0.0)) Как мы видели, оптимизация в глубоком обучении полна трудностей. К счастью, существует широкий спектр надёжных алгоритмов, которые хорошо работают и просты в использовании даже для начинающих. Более того, не обязательно искать *единственное* лучшее решение. Локальные оптимумы или даже приближённые к ним решения по-прежнему очень полезны. **Резюме** ---------- - Минимизация ошибки на обучающей выборке *не* гарантирует, что мы найдем наилучший набор параметров для минимизации ошибки обобщающей способности. - Задачи оптимизации могут иметь множество локальных минимумов. - Задача может иметь ещё больше седловых точек, поскольку в общем случае задачи не являются выпуклыми. - Исчезающие градиенты могут приводить к остановке оптимизации. Часто помогает переопределение задачи. Также может быть полезна хорошая инициализация параметров. Упражнения ---------- 1. Рассмотрим простой многослойный перцептрон (MLP) с одним скрытым слоем, имеющим, скажем, :math:`d` размерностей, и одним выходом. Покажите, что для любого локального минимума существует как минимум :math:`d!` эквивалентных решений, ведущих себя идентично. 2. Предположим, что у нас есть симметричная случайная матрица :math:`\mathbf{M}`, элементы :math:`M_{ij} = M_{ji}` которой выбираются из некоторого распределения вероятностей :math:`p_{ij}`. Кроме того, предположим, что :math:`p_{ij}(x) = p_{ij}(-x)`, то есть распределение симметрично (см. :cite:t:`Wigner.1958` для подробностей). 1. Докажите, что распределение собственных значений также симметрично. То есть для любого собственного вектора :math:`\mathbf{v}` вероятность того, что соответствующее собственное значение :math:`\lambda` удовлетворяет условию :math:`P(\lambda > 0) = P(\lambda < 0)`. 2. Почему вышесказанное *не* подразумевает :math:`P(\lambda > 0) = 0.5`? 3. Какие ещё проблемы, связанные с оптимизацией в глубоком обучении, вы можете назвать? 4. Предположим, вы хотите удержать (реальный) мяч на (реальной) седловидной поверхности. 1. Почему это сложно? 2. Можно ли использовать этот эффект также для алгоритмов оптимизации? `Обсуждения `__