Это мой первый пост на Medium (пожалуйста, будьте любезны 😅), поэтому позвольте мне представиться.

Я Фабио, и после получения степени в области физики элементарных частиц я работаю в Quantyca (если вам интересно, я предлагаю вам посетить веб-сайт моей компании или нашу страницу linkedin, чтобы узнать, чем мы занимаемся).

Я хотел бы поделиться с вами некоторыми мыслями о градиентном спуске в машинном обучении, которые у меня были во время моей работы в Quantyca Analytics Team и моего последнего похода на мою родную гору.

«Безусловно, самая большая опасность искусственного интеллекта заключается в том, что люди слишком рано приходят к выводу, что они его понимают»

- Элиэзер Юдковский

Попробуем избежать этой опасности, рассматривая самый первый рабочий механизм искусственного интеллекта. В значительной степени Deep Learning решает проблемы оптимизации, кстати, очень серьезные. Итак, нейронная сеть - это функция (действительно очень сложная), в которой у нас есть масса параметров: эта функция представляет решение проблемы с математической точки зрения,

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

Функция потерь 🌄

В прошлое воскресенье я был на вершине горы Пресолана, очень красивой горной гряды недалеко от моего родного города. Тропа была очень каменистой, открытой и непростой, поэтому во время спуска я придерживался этой стратегии спуска на пресолане:

  1. 👀 Оценил все возможные пути вокруг моей позиции
  2. Отклонил поднимающиеся и все без опор. Эти пути на самом деле будут стоить мне больше энергии (кинетическая против потенциала) и сделать мою задачу еще более сложной.
  3. 📉 Выбрал путь, который, как мне кажется, имел самый крутой спуск и был безопаснее

Благодаря этим шагам я смогла благополучно добраться до дома.

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

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

По осям x и y нанесены значения двух весов. Ось z представляет значение функции потерь для пар весов. Цель обучения нейронной сети - найти конкретную пару весов, для которых потери минимальны (другими словами, цель - достичь минимумов для функции потерь).

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

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

Градиентный спуск 📉

Когда мы выбираем начальные значения наших весов, мы находимся в определенной точке ландшафта потерь. Как и в первой точке нашего алгоритма спуска с Презоланы, мы проверяем все возможные направления в плоскости xy. Когда выбрано направление, которое приводит к наиболее резкому снижению значения функции потерь, мы движемся по нему. Этот путь задается направлением, прямо противоположным направлению градиента (относительного в кратных измерениях одномерной производной). Итак, градиент дает нам направление наискорейшего подъема: так алгоритм получил свое название.

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

  • 🏇 Слишком быстро: мы можем выйти за минимумы и продолжать подпрыгивать по гребням «долины».
  • 🐌 Слишком медленно: тренировка может оказаться слишком долгой, чтобы быть устойчивой. Низкая скорость обучения делает алгоритм более склонным к застреванию в локальных минимумах (возможно, мы увидим эту опасность и как ее избежать в другом посте)

Теперь мы пересчитываем градиент в той позиции, в которой мы оказались, и повторяем процесс (точно так же, как спуск на гору Презолана).

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

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

Какие-то (не очень) скучные формулы 🔬

А теперь давайте попробуем вкратце формализовать весь наблюдаемый нами процесс. Базовым формализованным преобразованием, описывающим правило обновления градиентного спуска, является.

Это преобразование выполняется на каждой итерации и состоит из:

  • ω - вектор весов, лежащий в плоскости xy.
  • Lₘ (ω) - функция потерь
  • α - скорость обучения
  • ∇ω - градиент по размерам гирь

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

Практически одно и то же правило обновления применяется ко всем весам сети одновременно. Единственное изменение заключается в том, что, поскольку мы выполняем обновление индивидуально для каждого веса, градиент заменяется проекцией вектора градиента вдоль направления, представленного конкретным весом.

Это обновление выполняется одновременно для всех весов.

Перед вычитанием мы умножаем вектор градиента на скорость обучения: эта операция математически представляет шаг, который мы обсуждали ранее. Обратите внимание, что даже если мы сохраним постоянное значение α, размер шага может измениться из-за изменений значения градиента или крутизны контура потерь. Как только мы приближаемся к минимуму, градиент приближается к нулю, и мы делаем все меньшие и меньшие шаги к минимуму. Это полезно: слишком большой размер шага может привести к тому, что алгоритм перескочит минимум и отскочит между гребнями минимумов.

использованная литература

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

  • Дэвид Э. Рамелхарт и Джеймс Л. МакКлелланд, Изучение внутренних представлений путем распространения ошибок в статье Параллельная распределенная обработка: исследования микроструктуры познания: основы, MITP, 1987
  • В.А.Гарднер, Характеристики обучения алгоритмов стохастического градиентного спуска: общее исследование, анализ и критика в Обработке сигналов, том 6, выпуск 2, 1984 г.
  • Себастьян Рудер, Обзор алгоритмов оптимизации градиентного спуска в 1609.04747 arXiv, 2016 (здесь PDF-файл)
  • Марцин Андрыхович, Миша Денил, Серхио Гомес, Мэтью В. Хоффман, Дэвид Пфау, Том Шауль, Брендан Шиллингфорд и Нандо де Фрейтас, Обучение с помощью градиентного спуска путем градиентного спуска в 1606.04474 arXiv , 2016 (здесь pdf)
  • Рохан Кширсагар, Жизнь - это градиентный спуск на hackernoon.com (здесь статья)