Как учится машина. Революция в области нейронных сетей и глубокого обучения - Ян Лекун
Это значительно упрощает жизнь: если можно вычислить частные производные функции с помощью формулы, можно вычислить и ее вектор градиента в каждой из точек, вообще не прибегая к помехам!
Давайте возьмем линейную модель, такую как перцептрон, описанный в предыдущей главе, который вычисляет скалярное произведение между w и x:
f(x, w) = dot(w, x)
и возьмем функцию стоимости, которая меняет квадрат ошибки:
C(x, y, w) = (y – f(x, w)) ** 2
Градиент будет следующим:
dc_dw[0] = –2 * (y – f(x, w)) * x[0]
dc_dw[1] = –2 * (y – f(x, w)) * x[1]
…
dc_dw[n – 1] = –2 * (y – f(x, w)) * x[n – 1]
Обратите внимание, что есть два способа вычислить градиент: помехами и частными производными.
Стохастический градиентный спуск
Существует более эффективный вариант метода градиентного спуска, позволяющий добраться до дна долины еще быстрее. Вместо того, чтобы вычислять среднее значение стоимости и находить градиент этого среднего по всем примерам обучения, чтобы сделать шаг, используются частные производные для вычисления градиента стоимости для одного примера.
Представьте, если у нас миллион изображений, при помощи классического градиентного спуска нужно предсказать для каждого изображения, кошка это или собака, посмотреть на разницу вектора прогнозирования с реальным вектором и повторить миллион раз ту же операцию, чтобы рассчитать среднюю стоимость! Потребовалось бы огромное количество времени, чтобы просто сделать шаг вперед.
Поэтому мы поступим проще. Система случайным образом выбирает один пример из обучающего набора, вычисляет градиент стоимости для этого примера и увеличивает градиент. Затем она берет другой пример, вычисляет градиент стоимости для этого нового примера и делает новый шаг.
Повторяем операцию до тех пор, пока не сможем больше спускаться. Размер шага должен уменьшаться по мере приближения ко дну впадины. На практике вместо того, чтобы брать один пример для шага, усредняем градиент по небольшому количеству примеров, называемому «мини-пакетом».
При каждом шаге градиент указывает в другом направлении, что приводит к тому, что вектор параметров в процессе обучения идет по неустойчивой траектории. Но шаг за шагом он направляется к дну долины. Что удивительно: он делает это даже быстрее, чем вычисление градиента по всему обучающему набору.
Процедура выглядит следующим образом:
# процедура обучения стохастическому градиентному
# спуску
# n: количество итераций градиента
def SGD(X, Y, w, e, n):
p = len(X) # количество обучающих примеров
for i in range (n): # повторить n раз
k = random.randrange(0, p) # случайное число
g = gradC(X[k], Y[k], w) # расчет градиента
for j in range (len(w)): # цикл по параметрам
w[j] = w[j] – e * g[j] # обновление параметров
return w # возвращаем вектор параметров
Правда, вместо того чтобы следовать ровной траектории, вектор параметров блуждает, но в конечном итоге он быстрее достигает дна долины, потому что на каждом этапе требуется меньше вычислений.
Метод стохастического градиентного спуска – это простой, непохожий на другие и вместе с тем нелогичный способ оптимизации. Помните, что мы часто работаем с миллионами (или даже миллиардами!) обучающих примеров.
Рис. 4.4. Траектория стохастического градиентного спуска
При стохастическом градиентном спуске мы берем случайный пример из обучающего набора, вычисляем градиент функции стоимости для этого примера и делаем небольшой шаг в направлении, противоположном градиенту. Затем берем другой пример и повторяем операцию. Потом еще один и так далее, постепенно уменьшая размер шага градиента, т. е. эта процедура быстро снижает стоимость обучения (которая является средней стоимостью по примерам), следуя беспорядочной траектории из-за колебаний градиента стоимости между одним примером и другим. На этом рисунке обучающий набор содержит 100 примеров. После всего четырех шагов на обучающем наборе параметры уже будут колебаться вокруг минимума.
Фактически, только что описанная процедура с функцией стоимости, равной квадрату ошибки, используется близким родственником перцептрона: Adaline (адаптивный линейный нейрон).
Модель Adaline была предложена в 1960 г. (ей столько же лет, сколько и мне!) Бернардом Видроу и Тедом Хоффом. Полезно упомянуть данную модель здесь по двум причинам: во-первых, потому, что ее квадратичную функцию стоимости легко визуализировать; во-вторых, потому что данная модель исторически соперничала с перцептроном.
Как и перцептрон, Adaline вычисляет свои выходы, взяв взвешенную сумму входов, которая является скалярным произведением между вектором весов и вектором входов. Идея состоит в том, чтобы минимизировать квадрат ошибки между желаемым выходом и выходом модели с помощью процедуры стохастического градиентного спуска. Вы можете использовать Adaline в качестве классификатора: как и в случае с перцептроном, желаемый выход будет +1 для класса A и –1 для класса B.
Процедура перцептрона также представляет собой стохастический градиентный спуск для конкретной функции стоимости следующего вида:
C(x, y, w) = –y * f(w, x) * dot(w, x)
или
f(w, x) = sign(dot(w, x))
Частная производная по отношению к компоненту j вектора параметров равна:
g[j] = –(y – f(w, x)) * x[j]
что приводит к следующему обновления:
w[j] = w[j] + e * (y – f(w, x)) * x[j]
Данная формула представляет собой процедуру обучения перцептрона, приведенную в Главе 3. Технически график функции стоимости перцептрона не является полностью плавным: у него есть неровности, точки излома, где наклон резко меняется. Там, где возникают эти неровности, градиент четко не определяется. Вычисленный выше градиент на самом деле называется «субградиент». Впрочем, это уже вопрос математической дотошности.
Перцептрон и Adaline минимизируют функцию стоимости, которая имеет только долину. Отправная точка не имеет значения, так как процедура обучения всегда попадет в эту долину. Но что, если функция стоимости имеет несколько минимумов?
Висячие долины
Представим более сложную функцию, в которой есть два или более минимумов (см. рис. 4.5).
Мы в Альпах. Справа долина во Франции; слева долина в Италии. Наша функция имеет два минимума, а может, и несколько.
Перцептрон не сталкивается с такими проблемами, но когда мы используем нейронную сеть с двумя или более слоями, функция стоимости имеет несколько минимумов. Некоторые из них хороши в том смысле, что они связаны с хорошей эффективностью системы (при невысокой стоимости обучения). Другие не являются реальными минимумами, потому что они «нависают» над более