Электронная библиотека » Нихиль Будума » » онлайн чтение - страница 5


  • Текст добавлен: 27 января 2020, 12:00


Автор книги: Нихиль Будума


Жанр: Управление и подбор персонала, Бизнес-Книги


Возрастные ограничения: +16

сообщить о неприемлемом содержимом

Текущая страница: 5 (всего у книги 18 страниц) [доступный отрывок для чтения: 5 страниц]

Шрифт:
- 100% +
Насколько неприятны сомнительные локальные минимумы в нейросетях?

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

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

Для более эффективного анализа проблемы И. Гудфеллоу и его коллеги (команда исследователей, объединившая специалистов из Google и Стэнфордского университета) опубликовали в 2014 году статью[42]42
  Goodfellow I. J., Vinyals O., Saxe A. M. Qualitatively characterizing neural network optimization problems // arXiv preprint arXiv: 1412.6544 (2014).


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

Итак, при случайным образом инициализированном векторе параметров θi и решении стохастического градиентного спуска θf мы намерены вычислить функцию ошибок в каждой точке методом линейной интерполяции θα = α θf + (1 − α) θi.

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

Мы можем даже показать это сами на примере сети с прямым распространением сигнала из нейронов ReLU, созданной в главе 3. Запустив контрольный файл, который мы сохранили при обучении исходной сети, мы можем пересоздать компоненты inference и loss, сохраняя список указателей на переменные в оригинальном графе для дальнейшего использования в var_list_opt (где opt – оптимальные настройки параметров):

# mnist data image of shape 28*28=784

x = tf.placeholder("float", [None, 784])

# 0–9 digits recognition => 10 classes

y = tf.placeholder("float", [None, 10])

sess = tf.Session()

with tf.variable_scope("mlp_model") as scope:

output_opt = inference(x)

cost_opt = loss(output_opt, y)

saver = tf.train.Saver()

scope.reuse_variables()

var_list_opt = [

"hidden_1/W",

"hidden_1/b",

"hidden_2/W",

"hidden_2/b",

"output/W",

"output/b"

]

var_list_opt = [tf.get_variable(v) for v in var_list_opt]

saver.restore(sess, "mlp_logs/model-checkpoint-file")

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

with tf.variable_scope(«mlp_init») as scope:

output_rand = inference(x)

cost_rand = loss(output_rand, y)

scope.reuse_variables()

var_list_rand = [

"hidden_1/W",

"hidden_1/b",

"hidden_2/W",

"hidden_2/b",

"output/W",

"output/b"

]

var_list_rand = [tf.get_variable(v) for v in var_list_rand]

init_op = tf.initialize_variables(var_list_rand)

sess.run(init_op)

Инициализировав две эти сети, мы можем вывести линейную интерполяцию при помощи параметров alpha и beta:

with tf.variable_scope(«mlp_inter») as scope:

alpha = tf.placeholder("float", [1, 1])

beta = 1 – alpha

h1_W_inter = var_list_opt[0] * beta + var_list_rand[0] * alpha

h1_b_inter = var_list_opt[1] * beta + var_list_rand[1] * alpha

h2_W_inter = var_list_opt[2] * beta + var_list_rand[2] * alpha

h2_b_inter = var_list_opt[3] * beta + var_list_rand[3] * alpha

o_W_inter = var_list_opt[4] * beta + var_list_rand[4] * alpha

o_b_inter = var_list_opt[5] * beta + var_list_rand[5] * alpha

h1_inter = tf.nn.relu(tf.matmul(x, h1_W_inter) + h1_b_inter)

h2_inter = tf.nn.relu(tf.matmul(h1_inter, h2_W_inter) + h2_b_inter)

o_inter = tf.nn.relu(tf.matmul(h2_inter, o_W_inter) + o_b_inter)

cost_inter = loss(o_inter, y)

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

import matplotlib.pyplot as plt

summary_writer = tf.train.SummaryWriter("linear_interp_logs/", graph_def=sess.graph_def)

summary_op = tf.merge_all_summaries()

results = []

for a in np.arange(-2, 2, 0.01):

feed_dict = {

x: mnist.test.images,

y: mnist.test.labels,

alpha: [[a]],

}

cost, summary_str = sess.run([cost_inter, summary_op], feed_dict=feed_dict)

summary_writer.add_summary(summary_str, (a + 2)/0.01)

results.append(cost)

plt.plot(np.arange(-2, 2, 0.01), results, ‘ro')

plt.ylabel(‘Incurred Error')

plt.xlabel(‘Alpha')

plt.show()

Получаем рис. 4.3, который мы можем проанализировать сами. Если мы будем повторять этот эксперимент, окажется, что никаких локальных минимумов, которые всерьез поставили бы нас в тупик, и нет. Судя по всему, основная сложность с градиентным спуском – не они, а трудности с выбором нужного направления. К этому вопросу мы вернемся чуть позже.


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

Плоские области на поверхности ошибок

Хотя наш анализ и показал отсутствие проблем с локальными минимумами, можно отметить особенно плоскую область, в которой градиент доходит до нуля, а alpha = 1. Это не локальный минимум, и вряд ли она поставит нас в затруднение, но кажется, что нулевой градиент может замедлить обучение.

В общем случае для произвольной функции точка, на которой градиент становится нулевым вектором, называется критической. Критические точки бывают разных типов. Мы уже говорили о локальных минимумах, несложно представить себе и их противоположности: локальные максимумы, которые, впрочем, не вызывают особых проблем при стохастическом градиентном спуске. Но есть и странные точки, лежащие где-то посередине. Эти «плоские» области – потенциально неприятные, но не обязательно смертельные – называются седловыми точками. Оказывается, когда у нашей функции появляется все больше измерений (а у модели все больше параметров), седловые точки становятся экспоненциально более вероятными, чем локальные минимумы. Попробуем понять, почему так происходит.

Для одномерной функции ошибок критическая точка может принимать одну из трех форм, как показано на рис. 3.1. Представим себе, например, что все эти три конфигурации одинаково вероятны. Если взять случайную критическую точку случайной одномерной функции, то вероятность того, что это локальный минимум, будет равна 1/3. И если у нас есть k критических точек, то можно ожидать, что локальными минимумами окажутся k/3 из них.


Рис. 4.4. Анализ критической точки в одном измерении


Можно распространить это утверждение на функции с большим числом измерений. Представим функцию потерь в d-мерном пространстве. Возьмем произвольную критическую точку. Оказывается, определить, будет ли она локальным минимумом, локальным максимумом или седловой точкой, сложнее, чем для одномерного случая. Рассмотрим поверхность ошибок на рис. 4.5. В зависимости от того, как выбирать направление (от A к B или от C к D), критическая точка будет казаться либо минимумом, либо максимумом. В реальности она ни то ни другое. Это более сложный тип седловой точки.


Рис. 4.5. Седловая точка на двумерной поверхности ошибок


В целом в d-мерной области параметров мы можем провести через критическую точку d различные оси. Она может быть локальным минимумом, только если оказывается локальным минимумом в каждой из d одномерных подобластей. Зная, что критическая точка в одномерной подобласти может относиться к одному из трех типов, мы понимаем: вероятность того, что случайная критическая точка принадлежит случайной функции, равна . Это значит, что случайная функция с k критических точек имеет ожидаемое количество локальных минимумов. С ростом размерности области параметров число локальных минимумов экспоненциально уменьшается. Более строгое рассмотрение этой темы выходит за рамки настоящей книги; ознакомиться с вопросом можно в работе Яна Дофина и его коллег (2014)[43]43
  Dauphin Y. N. et al. Identifying and attacking the saddle point problem in high-dimensional non-convex optimization // Advances in Neural Information Processing Systems. 2014.


[Закрыть]
.

Что все это значит в контексте оптимизации моделей глубокого обучения? Для стохастического градиентного спуска – пока непонятно. Судя по всему, плоские области на поверхности ошибок неприятны, но не мешают получить приемлемый ответ с использованием этого метода. Но они создают серьезные проблемы для методов, которые пытаются найти прямое решение в точке, где градиент равен 0. Именно это обстоятельство снижает пользу некоторых методов оптимизации второго порядка для моделей глубокого обучения, о чем мы поговорим ниже.

Когда градиент указывает в неверном направлении

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


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


Вновь обратившись к контурным диаграммам, о которых шла речь в главе 2, мы отмечаем, что градиент – обычно не лучший индикатор правильной траектории. Он указывает в направлении локального минимума, только если контуры идеально круглые. Если же они эллиптические (как обычно и бывает с поверхностями ошибок глубоких сетей), градиент может указывать на 90° в сторону от верного направления!

Распространим этот анализ на произвольное число измерений, введя несколько математических обозначений. Для каждого веса wi в области параметров градиент вычисляет значение , или то, как меняется значение ошибки при вариациях значения wi. Определив и объединив все веса в области параметров, градиент дает направление кратчайшего спуска. Однако, прежде чем сделать уверенный шаг в этом направлении, нужно вспомнить о проблеме: градиент может меняться у нас на глазах в процессе движения! Этот простой факт показан на рис. 4.7. Возвращаясь к двумерному примеру, скажем: если наши контуры идеально круглые и мы делаем значительный шаг в направлении наискорейшего спуска, градиент больше направления не меняет. Но для сильно эллиптических контуров это неверно.


Рис. 4.7. Мы показываем, как направление градиента меняется, когда мы следуем в направлении скорейшего спуска (определенного от начальной точки). Векторы нормализованы до идентичной длины, чтобы подчеркнуть смену их направления


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



что дает возможность определить, как градиентный компонент wj модифицируется с изменением значения wi. Эту информацию мы можем свести в особую матрицу, известную как матрица Гессе, или гессиан (Н). При описании поверхности ошибок, когда градиент меняется в ходе пути в направлении кратчайшего спуска, она называется плохо обусловленной.

Для математически подкованных читателей подробнее расскажем о том, как гессиан ограничивает оптимизацию только с помощью градиентного спуска. Определенные свойства матрицы Гессе (реальность и симметричность) позволяют успешно определить вторую производную (которая аппроксимирует кривизну поверхности) при движении в определенном направлении. А именно: если есть единичный вектор d, вторая производная в этом направлении задается dHd. Теперь можно использовать аппроксимацию второго порядка с помощью ряда Тейлора и понять, что происходит с функцией ошибок при переходе от текущего вектора параметров x(i) к новому x по вектору градиента g[44]44
  Более строго, мы движемся в направлении, противоположном градиенту, так как градиент указывает направления наиболее быстрого возрастания функции, а нам нужно направление убывания. Прим. науч. ред.


[Закрыть]
, выраженному в x(i):



Если мы будем и далее двигаться в направлении градиента, можно упростить наше выражение:



Оно состоит из трех членов: 1) значение функции потерь для исходного вектора параметров; 2) улучшение функции потерь, обеспеченное величиной градиента; 3) корректирующий член, который выражает кривизну пространства, представленную матрицей Гессе.

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

Импульсная оптимизация

Проблема плохо обусловленной матрицы Гессе проявляется в серьезных флуктуациях градиентов. Один из популярных вариантов решения – отказ от вычисления гессиана и сосредоточение на борьбе с этими флуктуациями во время обучения. Один из способов понять, как такой подход может быть полезен, – изучить, как мяч катится по холмистой поверхности. Под действием силы тяжести он в итоге оказывается в низшей точке, но почему-то не страдает от серьезных флуктуаций и отклонений, которые случаются при градиентном спуске. В чем же дело? В отличие от стохастического градиентного спуска (при котором используется только градиент), движение мяча по поверхности ошибки определяется еще двумя основными компонентами. Первый, который мы моделируем в виде градиента при стохастическом спуске, в обиходе называется ускорением. Но не только оно определяет движение мяча. Гораздо важнее его скорость. Ускорение влияет именно на нее и лишь опосредованно – на положение мяча.

Движение под действием скорости желательно, поскольку оно противодействует значительным флуктуациям градиента, постепенно спрямляя траекторию мяча. Скорость – форма памяти, позволяющая эффективно аккумулировать движение к минимуму, сглаживая колебания ускорения в ортогональных направлениях. Наша задача – создать аналог скорости в алгоритме оптимизации. Это можно сделать, отслеживая экспоненциально взвешенное затухание предыдущих градиентов. Каждое обновление вычисляется с помощью сочетания обновления предыдущей итерации с текущим градиентом. Изменения вектора параметров определяются так:

vi = mvi − 1 – ϵ gi,

θi = θi − 1 + vi.

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

Чтобы нагляднее представить себе, как работает импульс, рассмотрим пример, как он влияет на обновления в ходе случайных блужданий, то есть совершения последовательности бессистемно выбранных шагов. Представим себе точку на линии, которая в каждый интервал времени случайно выбирает размер шага между –10 и 10 и перемещается в этом направлении. Это выражается просто:

step_range = 10

step_choices = range(-1 * step_range,step_range + 1)

rand_walk = [random.choice(step_choices) for x in xrange(100)]

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

momentum_rand_walk = [random.choice(step_choices)]

for i in xrange(len(rand_walk) – 1):

prev = momentum_rand_walk[-1]

rand_choice = random.choice(step_choices)

new_step = momentum * prev + (1 – momentum) * rand_choice

momentum_rand_walk.append()

Результаты при варьировании импульса от 0 до 1 удивительны. Импульс существенно снижает волатильность обновлений. Чем он больше, тем мы менее чувствительны к новым обновлениям (например, серьезная неточность при первой оценке траектории сохраняется в течение значительного периода). Результаты эксперимента приведены на рис. 4.8.


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


Чтобы понять, как импульс влияет на обучение реальных нейросетей с прямым распространением сигнала, мы можем вернуться к MNIST и применить импульсный оптимизатор TensorFlow. Будем использовать тот же темп обучения (0,01) с типичным импульсом 0,9:

learning_rate = 0.01

momentum = 0.9

optimizer = tf.train.MomentumOptimizer(learning_rate, momentum)

train_op = optimizer.minimize(cost, global_step=global_step)

Ускорение вычислений поразительно. Изменение функции потерь со временем видно на примере сравнения визуализаций TensorBoard на рис. 4.9. Здесь показано, что для достижения потерь в 0,1 без импульса (слева) требуется почти 18 000 шагов (мини-пакетов), а с импульсом (справа) – чуть более 2000.


Рис. 4.9. Сравнение для сети с прямым распространением сигнала с импульсом (справа) и без импульса (слева) показывает значительное сокращение времени обучения


В последнее время появилось много исследований, направленных на улучшение классического импульсного метода. В работе Ильи Суцкевера и его коллег (2013) предложена альтернатива: импульсный метод Нестерова, который вычисляет градиент на поверхности ошибок во время обновления скорости при θ + vi − 1, а не θ[45]45
  Sutskever I. et al. On the importance of initialization and momentum in deep learning // ICML (3). 2013. Vol. 28. Pp. 1139–1147.


[Закрыть]
. Эта тонкая разница позволяет более эффективно изменять скорость. Было доказано, что этот метод имеет явные преимущества при пакетном градиентном спуске (гарантирует сходимость и может использовать большее значение импульса для заданного темпа обучения по сравнению с классическим). Но не до конца понятно, есть ли выгоды при стохастическом мини-пакетном градиентном спуске, который используется в большинстве подходов оптимизации для глубокого обучения. На момент написания этой книги импульсный метод Нестерова в TensorFlow не поддерживался[46]46
  Сейчас импульсный метод Нестерова уже реализован в TensorFlow: https://www.tensorflow.org/api_docs/python/tf/train/MomentumOptimizer. Прим. науч. ред.


[Закрыть]
.

Краткий обзор методов второго порядка

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

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

Этот метод приводит к разнообразным зигзагам (рис. 4.10), ведь каждый раз, когда мы движемся в сторону кратчайшего спуска, мы немного откатываемся в другом направлении. Решение – движение в сопряженном направлении относительно предыдущего, а не к кратчайшему спуску. Направление выбирается методом косвенного аппроксимирования гессиана для линейного сочетания градиента и предыдущего направления. При небольших модификациях метод обобщается до невыпуклых поверхностей ошибок, характерных для глубоких сетей[47]47
  Møller M. F. A Scaled Conjugate Gradient Algorithm for Fast Supervised Learning // Neural Networks. 1993. Vol. 6. No. 4. Pp. 525–533.


[Закрыть]
.


Рис. 4.10. Метод кратчайшего спуска часто дает зигзаги; сопряженный спуск направлен на решение этой проблемы


Альтернативный алгоритм оптимизации называется алгоритмом Бройдена – Флетчера – Гольдфарба – Шанно (BFGS)[48]48
  Broyden C. G. A new method of solving nonlinear simultaneous equations // The Computer Journal. 1969. Vol. 12. No. 1. Pp. 94–99.


[Закрыть]
и заключается в итеративном вычислении обратной матрицы Гессе для более эффективной оптимизации вектора параметров. Изначально BFGS предъявлял значительные требования к памяти, но уже разработана более эффективная версия – L-BFGS[49]49
  Bonnans J.-F. et al. Numerical Optimization: Theoretical and Practical Aspects. Springer Science & Business Media, 2006.


[Закрыть]
.

Эти подходы перспективны, но методы второго порядка по-прежнему остаются областью активных исследований и у практиков непопулярны. TensorFlow на момент написания этой книги не поддерживал ни метода сопряженных градиентов, ни L-BFGS.

Внимание! Это не конец книги.

Если начало книги вам понравилось, то полную версию можно приобрести у нашего партнёра - распространителя легального контента. Поддержите автора!

Страницы книги >> Предыдущая | 1 2 3 4 5
  • 4 Оценок: 5

Правообладателям!

Данное произведение размещено по согласованию с ООО "ЛитРес" (20% исходного текста). Если размещение книги нарушает чьи-либо права, то сообщите об этом.

Читателям!

Оплатили, но не знаете что делать дальше?


Популярные книги за неделю


Рекомендации