Что такое градиентный спуск в нейронных сетях
Перейти к содержимому

Что такое градиентный спуск в нейронных сетях

  • автор:

Понимание градиентного спуска и обучения нейронных сетей

Play video

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

Ключевые выводы

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

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

Направление, в котором нужно сделать шаг, чтобы уменьшить функцию наиболее быстро, — это отрицательное значение градиента, которое указывает вам направление спуска и его крутизну.

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

Summarize any YouTube video by yourself

Download on the App Store

Desktop options: Safari Chrome

Summarize any YouTube video by yourself

Other options: iOS App Chrome

Summarize any YouTube video by yourself

Other options: iOS App Safari

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

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

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

Градиентный спуск — это способ обучения нейронных сетей путем корректировки весовых коэффициентов связей между нейронами на основе погрешности выходных данных по сравнению с желаемыми выходными данными.

Просмотреть больше Искусственный интеллект и машинное обучение

  • Сергей Марков: «Искусственный интеллект и машинное обучение 2021»
  • MIT Introduction to Deep Learning | 6.S191
  • ChatGPT Advanced Data Analysis — A New Era of Data Science Begins

Отмеченное временем резюме

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

Нейронные сети корректируют веса и смещения, чтобы найти минимум функции, измеряемый функцией затрат, которая вычисляет среднюю разницу между выходными и желаемыми значениями.

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

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

Summarize any YouTube video by yourself

Download on the App Store

Desktop options: Safari Chrome

Summarize any YouTube video by yourself

Other options: iOS App Chrome

Summarize any YouTube video by yourself

Other options: iOS App Safari

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

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

Книга содержит пошаговое руководство и бесплатный код и данные для обучения нейронных сетей, одновременно поднимая вопросы о важности структурированных наборов данных.

Facebook запускает новую функцию под названием «Окрестности», которая позволяет пользователям общаться со своим местным сообществом.

Summarize any YouTube video by yourself

Download on the App Store

Desktop options: Safari Chrome

Summarize any YouTube video by yourself

Other options: iOS App Chrome

Summarize any YouTube video by yourself

Математика за оптимизаторами нейронных сетей

В этой статье мы поговорим о математике градиентного спуска, почему при обучении нейронных сетей применяется стохастический градиентный спуск и о вариации SGD (Stochastic Gradient Descent) с использованием скользящего среднего (SGD с momentum и Nesterov Accelerated Gradient).

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

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

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

где — это номер шага, — размер шага обучения (learning rate). В результате шага оптимизации веса нейронной сети принимают новые значения.

Виды градиентного спуска

    Пакетный градиентный спуск (batch gradient descent).

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

image

Источник

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

SGD с импульсом и Nesterov Accelerated Gradient

Следующие две модификации SGD призваны помочь в решении проблемы попадания в локальные минимумы при оптимизации невыпуклого функционала.

Гладкая выпуклая функция

Функция с множеством локальных минимумов (источник)

Первая модификация

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

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

Вторая модификация

Nesterov accelerated gradient отличается от метода с импульсом, его особенностью является вычисление градиента при обновлении в отличной точке. Эта точка берётся впереди по направлению движения накопленного градиента:

На картинке изображены различия этих двух методов.

image

источник

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

Заключение

В этой статье мы детально рассмотрели начала градиентного спуска с точки зрения оптимизации нейронных сетей. Поговорили о трёх разновидностях спуска с точки зрения используемых данных, и о двух модификациях SGD, использующих импульс, для достижения лучшего качества оптимизации невыпуклых и негладких функционалов ошибки. Дальнейшее изучение темы предполагает разбор адаптивных к частоте встречающихся признаков подходов таких как Adagrad, RMSProp, ADAM.

Данная статья была написана в преддверии старта курса «Математика для Data Science» от OTUS.

Приглашаю всех желающих записаться на demo day курса, в рамках которого вы сможете подробно узнать о курсе и процессе обучения, а также познакомиться с экспертами OTUS

  • машинное обучение
  • градиентный спуск
  • нейронные сети
  • deep learning

Градиентный спуск: алгоритм и пример на Python

Градиентный спуск: алгоритм и пример на Python

Разбираем популярный метод, с помощью которого обучают нейронные сети

Градиентный спуск — это один из методов оптимизации, который позволяет нейронной сети обучаться. О том, как он работает и почему сеть начинает «понимать», что правильно, а что нет, — читайте в этом материале.

Как обучают нейронки и зачем нужен градиентный спуск

Необученная нейронная сеть — плохой помощник: она ведет себя непредсказуемо и генерирует случайные ответы. Но если «подсказать» ей, что правильно, а что нет, она сможет делать прогнозы даже точнее, чем человек.

Но как именно этого достичь?

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

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

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

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

Чтобы понять суть метода, вспомним математику.

Градиент — это вектор, который направлен в сторону максимального изменения функции.

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

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

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

Алгоритм градиентного спуска

Математически градиентный спуск можно представить так:

1. Инициализировать параметры модели случайными значениями.

2. Подать входные данные в модель и получить предсказания.

3. Вычислить значение функции ошибки, сравнив предсказания с фактическими значениями. Как именно — зависит от конкретной задачи. Например, в задачах регрессии можно использовать формулу:

где n — количество примеров в обучающей выборке, y — фактическое значение, Y — предсказанное значение целевой переменной.

4. Определить градиент функции ошибки по каждому параметру модели. Формула выбирается в зависимости от выбранной функции ошибки.

5. Обновить значения параметров по формуле:

новое значение параметра = старое значение параметра − learning rate * градиент.

Learning rate (скорость обучения) — это гиперпараметр, который контролирует скорость сходимости алгоритма градиентного спуска и определяет размер шага, с которым обновляются параметры модели. Чем меньше шаг — тем больше времени понадобится на обучение нейронной сети и обновление параметров.

6. Повторить шаги 2–5 для каждого этапа прогонки обучения (эпохи) или до достижения критерия остановки.

Пример коррекции весов нейронной сети

Допустим, у нас есть полносвязная нейронная сеть прямого распространения. У нее есть веса связи (выбраны случайно), и они лежат в диапазоне значений [−0.5;0.5].

Полносвязная нейронная сеть прямого распространения

Верхний индекс означает принадлежность к тому или иному слою. У каждого нейрона есть активационная функция f(x). У каждого наблюдения есть свой отклик — d.

Проходя по этой сети, мы получаем вектор наблюдений:

Для первого узла первого слоя получаем:

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

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

Для каждого нейрона второго слоя:

На первом нейроне второго слоя:

Аналогично доходим до выходного значения y. Поскольку мы знаем желаемое выходное значение для нашего вектора x1 и x2d, несложно подсчитать ошибку на выходе:

С этого момента начинается процесс корректировки весов. Она выполняется в обратном направлении, с выхода на вход. Согласно алгоритму backpropagation мы должны вычислить локальный градиент для выходного нейрона. Делается это по формуле:

где f(vout) — производная функции активации выходного нейрона.

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

Эти функции отличаются лишь уровнем (для гиперболического тангенса это диапазон от −1 до 1, а для логистической функции — промежуток от −0.5 до 0,5).

Предположим, мы выбрали функцию:

Ее производная будет выглядеть как:

А локальный градиент можно вычислить как:

Если посмотреть на формулу, можно увидеть, что выходное значение последнего нейрона f(vout) — это и есть y, то есть значение функции активации от суммы vout. Поэтому формула приобретает простой вид:

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

Параметр λ — это шаг обучения нейронной сети. Чем меньше мы его возьмем, тем медленнее будет происходить процесс обучения сети. Он выбирается экспериментально (например, 0.1, 0.01, 0.001 и так далее), пока результат не будет удовлетворительным.

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

Далее корректируем входные связи этих нейронов по уже известной формуле с шагом обучения нейронной сети. Для первого:

И для другого нейрона:

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

А уже затем умножаем эти суммы на производную функции активации:

Осталось скорректировать веса первого слоя:

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

Цель алгоритма градиентного спуска: минимизировать критерий качества нейронной сети — сумму квадратов ошибки обучающей выборки:

где N — число итераций.

Обучение нейронной сети на Python

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

  • Подключаем библиотеку NumPy для работы с массивами.
  • Определяем две функции: f(x) и df(x) . Первая представляет собой сигмоидную функцию активации, вторая вычисляет производную этой функции.
  • Задаем матрицы весов W1 и W2 (веса между входным слоем и скрытым слоем — и между скрытым слоем и выходным слоем соответственно).
  • Определяем функцию go_forward(inp) , которая выполняет прямое распространение сигнала через сеть. Входной сигнал ( inp ) умножается на матрицу весов W1 , применяется функция активации, затем результат умножается на матрицу весов W2 и снова прогоняется через функцию активации. Возвращается выходное значение нейронной сети y и значения активаций скрытого слоя out .
  • Определяем функцию train(epoch) , которая выполняет обучение нейронной сети. Внутри этой функции происходит итеративное обновление весов с использованием градиентного спуска. Для каждого цикла обучения выбирается случайный входной сигнал x из обучающей выборки epoch . Затем выполняется прямое распространение сигнала через сеть с помощью функции go_forward , вычисляем ошибку e между выходным и ожидаемым значением, с помощью производной функции активации определяем градиенты. С помощью формул градиентного спуска обновляем веса W2 и W1 .
  • Генерируем обучающую выборку epoch , которая представляет собой набор входных и выходных значений для обучения сети.
  • Вызываем функцию train(epoch) для обучения нейронной сети на заданной выборке.
  • Далее происходит прямое распространение сигнала через обученную сеть для каждого элемента в обучающей выборке epoch , выводится выходное значение нейронной сети y и ожидаемое значение x[−1] .
import numpy as np # Подключаем NumPy для работы с массивами def f(x): # Определяем сигмоидную функцию активации return 2/(1 + np.exp(-x)) — 1 def df(x): # Рассчитываем производную сигмоидной функции return 0.5 * (1 + x) * (1 — x) W1 = np.array([[-0.2, 0.3, -0.4], [0.1, -0.3, -0.4]]) W2 = np.array([0.2, 0.3]) def go_forward(inp): sum = np.dot(W1, inp) out = np.array([f(x) for x in sum]) sum = np.dot(W2, out) y = f(sum) return (y, out) def train(epoch): global W2, W1 lmd = 0.001 N = 100000 count = len(epoch) for k in range(N): x = epoch[np.random.randint(0, count)] y, out = go_forward(x[0:3]) e = y — x[-1] delta = e * df(y) W2[0] = W2[0] — lmd * delta * out[0] W2[1] = W2[1] — lmd * delta * out[1] delta2 = W2 * delta * df(out) W1[0, :] = W1[0, :] — np.array(x[0:3]) * delta2[0] * lmd W1[1, :] = W1[1, :] — np.array(x[0:3]) * delta2[1] * lmd epoch = [(-1, -1, -1, -1), (-1, -1, 1, 1), (1, 1, -1, -1), (-1, 1, -1, -1), (-1, 1, 1, -1), (1, -1, -1, -1), (1, -1, 1, 1), (1, 1, 1, -1)] train(epoch) for x in epoch: y, out = go_forward(x[0:3]) print(f'Выходное значение нейронной сети: => ') 

Результат работы кода

Заключение

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

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

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

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

Разбираем нейросети по частям: как работает градиентный спуск

Нейросети сейчас везде, и даже цифровому гуманитарию от них не скрыться. Word2vec при помощи нейросети кодирует смысл слов (вот тут мы объясняли, как), а новые модели ELMO и BERT даже научились учитывать, что слова появляются в разных контекстах и от этого из смысл тоже может меняться. Этот текст — про то, что значит «обучить» нейросеть и кто «подбирает веса» отдельных нейронов.

А что вообще творится в нейросетях? Напомните!

Ранее мы рассказывали, как «сырые» данные (картинка, видео или текст) разбиваются на мелкие кусочки и подаются на каждый входной нейрон. Дальше входные нейроны анализируют что-то очень простое — есть ли в их кусочке картинки 10 белых пикселей, есть ли буква «Т» в слове — и если да, нейрон «активируется», то есть передает свой сигнал в следующий слой с определенной силой. Сигналы комбинируются, потом собираются в абстрактные комбинации десятков комбинаций сигналов, и в конце концов активируют один из нейронов, который классифицирует картинку как котика или хлеб.

А как активируется нейрон?

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

В данном случае, если какие-то значения на входе нейрона дали положительную сумму — нейрон активировался. Порог активации здесь выглядит как вертикальная палочка, простой переключатель вкл/выкл, а значит, нейрон может быть либо активен, либо нет — как лампочка. Есть и более сложные функции, которые могут изменять силу выходного сигнала, могут «чуть-чуть активировать» нейрон, или «активировать его посильнее»:

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

Вот главное: нейрон — это функция. Чем больше ее значение, тем важнее сигнал нейрона для всей сети.

Почему это важно в контексте обучения нейросети?

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

Нейроны глупые! Без ручной настройки силы их выходных сигналов нейросеть даёт случайные предсказания. К выходному значению нейрона можно (и нужно) прибавлять некоторый вес. Вес прибавляется или отнимается в зависимости от того, насколько сильно в прошлый раз нейросеть ошиблась с предсказанием. Этот этап работы, когда нейроны штрафуются за все прошлые «косяки», называется обратным распространением ошибки. Какие-то нейроны активируются слишком сильно, какие-то — слабо, но все равно они уводят предсказание нейросети в сторону от правильного. Поскольку нейронов слишком много, и за какие конкретно признаки каждый из них отвечает — неясно, настроить каждый вес вручную невозможно. Люди придумали способ настраивать веса автоматически.

Для этого существует функция потерь. Что она делает?

Коротко: ее значение возрастает, если нейросеть сильно ошибается. Значит, надо найти такое решение, где функция возрастать не будет.

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

Кстати, функций потерь тоже существует много, они по-разному подходят для разных задач, и крутые программисты за 300к/сек знают, как в них сориентироваться. Функции потерь объединяет то, что они возрастают вместе с мерой ошибки предсказания. Она вычисляется просто: из числа X (предсказанного) вычитаем число Y (то, что должно было предсказаться) — получаем число Err. Оно становится одним из аргументов функции потерь.

Здесь надо вспомнить производные

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

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

Только сначала нужно найти минимальное значение функции.

Как это делали в школе?

Когда на уроке алгебры учительница давала какой-нибудь многочлен и просила найти его минимум, мы поступали следующим образом:

  • Находили производную функции и приравнивали ее к нулю;
  • Решали получившееся уравнение, то есть находили, при каких значениях переменной производная равна нулю;
  • Подставляли эти значения в функцию и проверяли, где получится минимальное значение.

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

Вот что это будут за точки: в них функция меняет направление. Такие точки обязательно становятся (хотя бы локальными) минимумами или максимумами функции. А вот как будут выглядеть касательные к этим точкам:

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

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

We need to go deeper

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

Поэтому вот вам таблица, попробуйте сказать, чему равна частная производная от переменной x функции

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

(Ответ будет чуть ниже, не подглядывайте!)

Математически фразу «производная функции y от переменной x» можно записать так:

Ответ к задаче: частная производная равна

Чему же равна частная производная в точке (x=3, z=4)? Теперь мы можем просто подставить значения 3 и 4 в полученное уравнение частной производной

Мы получим, что производная равна 23 + 44 = 22.

Пора рассказать, что такое градиент

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

Вот главное: градиент — это вектор, показывающий направление, в котором функция многих переменных быстрее всего возрастает или падает. «Градиент функции f» записывается так: ∇f (можно читать как «набла f»).

Вот небольшое упражнение. Попробуйте найти градиент функции

для переменных x, y, z?
Подсказка: должен получиться вектор с тремя элементами.

Сложность в том, чтобы уследить, какие из «констант» — множители переменной, что рассматриваются в данный момент, а какие — отбрасываются как слагаемые.

Объясните наконец, что такое градиентный спуск!

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

Стоит помнить, что говорим не о двумерных функциях. Представить, что происходит, можно по этой картинке:

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

Вот главное:

  1. Градиентный спуск выбирает случайную точку старая_точка, принадлежащую функции
  2. Новая_точка рассчитывается как старая_точка минус (размер_шага * градиент_в_старой_точке)
  3. ЕСЛИ модуль (новая_точка минус старая_точка)< порогового_предела
    ТО старая_точка = минимум функции
    ИНАЧЕ — повторить алгоритм для новая_точка

А зачем настраивать размер шага?

Коротко: чтобы не пропустить минимум.

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

А почему это вообще должно работать?

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

Тем не менее градиентный спуск как метод обучения почему-то работает хорошо. В 2015 группа ученых из Курантовского института математических наук в Нью-Йорке нашла этому объяснение, показав, что большая часть локальных минимумов функций потерь, используемых в нейросетях, располагается близко к глобальному минимуму. Эта близость и позволяет натренированным при помощи градиентного спуска нейросетям справляться с задачами достаточно эффективно.

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

Источники

  • Градиентный спуск: всё, что нужно знать
  • Математика для искусственных нейронных сетей для новичков, часть 2 — градиентный спуск

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *