ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 22.11.2023
Просмотров: 134
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
(1) и W (2). Цель обратного распространения ошибки - вычислить градиенты ∂J / ∂W (1) и ∂J / ∂W (2). Для этого мы применяем цепное правило и вычисляем, в свою очередь, градиент каждой промежуточной переменной и параметра. Порядок вычислений меняется на противоположный по сравнению с вычислениями, выполняемыми при прямом распространении, поскольку нам нужно начать с результата вычислительного графа и продвигаться к параметрам. Первым шагом является вычисление градиентов целевой функции J = L + s относительно члена потерь L и условия регуляризации.
∂J/∂L = 1 и ∂J/∂s = 1. (5.7.8)
Затем мы вычисляем градиент целевой функции относительно переменной выходного слоя o в соответствии с цепным правилом:
∂J/∂o = prod (∂J/∂L, ∂L/∂o) = ∂L/∂o ∈ Rq, (5.7.9)
Затем мы вычисляем градиенты члена регуляризации по обоим параметрам:
∂s/∂W (1) = λW (1) и ∂s/∂W (2) = λW (2), (5.7.10)
Теперь мы можем вычислить градиент ∂J / ∂W (2) ∈ Rq × h параметров модели, ближайших к выходному слою. Использование цепного правила дает:
∂J/∂W (2) = prod (∂J/∂o, ∂o/∂W(2)) + prod (∂J/∂s, ∂s/∂W(2))
= ∂J/∂o h⊤ + λW(2), (5.7.11)
Чтобы получить градиент относительно W(1), нам нужно продолжить обратное распространение вдоль выходного слоя к скрытому слою. Градиент относительно скрытого слоя s выводит ∂J / ∂h ∈ Rh определяется так
∂J/∂h = prod (∂J/∂o, ∂o/∂h) = W(2)⊤ ∂J/∂o, (5.7.12)
Поскольку функция активации ϕ применяется поэлементно, вычисление градиента ∂J / ∂z ∈ Rh промежуточной переменной z требует использования оператора поэлементного умножения, который мы обозначим через ⊙:
∂J/∂z = prod (∂J/∂h, ∂h/∂z) = ∂J/∂h ⊙ ϕ'(z). (5.7.13)
Наконец, мы можем получить градиент ∂J / ∂W(1) ∈ Rh × d параметров модели, ближайших к входному слою. Согласно цепному правилу получаем
∂J/∂W(1) = prod (∂J/∂z, ∂z/∂W (1)) + prod (∂J/∂s, ∂s/∂W (1))
= ∂J/∂z x⊤ + λW (1) (5.7.14)
При обучении нейронных сетей прямое и обратное распространение зависят друг от друга. В частности, для прямого распространения мы проходим вычислительный граф в направлении зависимостей и вычисляем все переменные на его пути. Затем они используются для обратного распространения, когда порядок вычислений на графике меняется на противоположный.
В качестве примера возьмем вышеупомянутую простую сеть. С одной стороны, вычисление члена регуляризации (5.7.5) во время прямого распространения зависит от текущих значений параметров модели W(1) и W(2). Они задаются алгоритмом оптимизации согласно обратному распространению в последней итерации. С другой стороны, вычисление градиента для параметра eq_backprop-J-h во время обратного распространения зависит от текущего значения скрытой переменной h, которое задается прямым распространением.
Поэтому при обучении нейронных сетей после инициализации параметров модели мы чередуем прямое распространение с обратным распространением, обновляя параметры модели с использованием градиентов, заданных обратным распространением. Обратите внимание, что при обратном распространении повторно используются сохраненные промежуточные значения прямого распространения, чтобы избежать дублирования вычислений. Одним из последствий является то, что нам нужно сохранить промежуточные значения до завершения обратного распространения ошибки. Это также одна из причин, почему тренировка требует значительно больше памяти, чем простое предсказание. Кроме того, размер таких промежуточных значений примерно пропорционален количеству сетевых уровней и размеру пакета.
Таким образом, обучение более глубоких сетей с использованием пакетов большего размера легче приводит к ошибкам нехватки памяти.
Резюме
Упражнения
Обсуждение (см. https://discuss.d2l.ai/t/102)
До сих пор каждая реализованная нами модель требовала, чтобы мы инициализировали ее параметры в соответствии с некоторым заранее заданным распределением. До сих пор мы считали схему инициализации само собой разумеющейся, не обращая внимания на детали того, как делается этот выбор. Возможно, у вас даже сложилось впечатление, что эти варианты не особенно важны. Напротив, выбор схемы инициализации играет важную роль в обучении нейронной сети и может иметь решающее значение для поддержания вычислительной устойчивости. Более того, этот выбор может быть интересным образом связан с выбором нелинейной функции активации. От того, какую функцию мы выбираем и как мы инициализируем параметры, зависит, насколько быстро сойдется наш алгоритм оптимизации. Неправильный выбор здесь может привести к тому, что во время тренировки мы столкнемся со взрывными или исчезающими градиентами. В этом разделе мы углубимся в эти темы более подробно и обсудим некоторые полезные эвристики, которые вы найдете полезными на протяжении всей вашей карьеры в области глубокого обучения.
Рассмотрим глубокую сеть с L слоями, вход x и выход o. С каждым слоем l, определяемым преобразованием fl, параметризованным весами W(l), скрытая переменная которого равна h(l) (пусть h(0) = x), нашу сеть можно выразить как:
h(l) = fl (h(l − 1)) и, значит, o = fL ◦. . . ◦ f1 (x). (5.8.1)
Если все скрытые переменные и входные данные являются векторами, мы можем записать градиент o относительно любого набора параметров W(l) следующим образом:
∂W(l) o = ∂h (L − 1) h(L)M (L)def = ·. . . · ∂h (l) h(l + 1)M (l + 1) def =∂W (l) h(l)v(l)def =, (5.8.2)
Другими словами, этот градиент является произведением L − l матриц M (L)·. . . · M (l + 1) и вектор градиента v (l). Таким образом, мы подвержены тем же проблемам числового недолива, которые часто возникают при умножении слишком большого числа вероятностей. При работе с вероятностями распространенный трюк состоит в том, чтобы переключиться в лог-пространства, то есть сдвинуть давление с мантиссы на показатель степени числового представления. К сожалению, наша проблема более серьезна: изначально матрицы M
(l) могут иметь большое разнообразие собственных значений. Они могут быть маленькими или большими, а их произведение может быть очень большим или очень маленьким.
Риски, связанные с нестабильными градиентами, выходят за рамки численного представления. Градиенты непредсказуемой величины также угрожают стабильности наших алгоритмов оптимизации. Мы можем столкнуться с обновлениями параметров, которые либо (i) слишком велики, что разрушает нашу модель (проблема взрывающегося градиента); либо (ii) чрезмерно малы (проблема исчезающего градиента), что делает обучение невозможным, поскольку параметры практически не меняются при каждом обновлении.
Исчезающие градиенты
Одна из частых причин, вызывающих проблему исчезающего градиента, - это выбор функции активации σ, которая добавляется после линейных операций каждого слоя. Исторически сложилось так, что сигмовидная функция 1 / (1 + exp (−x)) (введено в: numref: sec_mlp) была популярна, потому что она напоминает функцию пороговой обработки. Поскольку первые искусственные нейронные сети были вдохновлены биологическими нейронными сетями, идея о нейронах, которые активируются либо полностью, либо совсем не активизируются (например, биологические нейроны), казалась привлекательной. Давайте внимательнее посмотрим на сигмоид, чтобы понять, почему он может вызывать исчезающие градиенты.
%matplotlib inline
from d2l import mxnet as d2l
from mxnet import autograd, np, npx
npx.set_np()
x = np.arange(-8.0, 8.0, 0.1)
x.attach_grad()
with autograd.record():
y = npx.sigmoid(x)
y.backward()
d2l.plot(x, [y, x.grad], legend=['sigmoid', 'gradient'], figsize=(4.5, 2.5))
Как видите, градиент сигмоиды исчезает как при больших, так и при малых входах. Более того, при обратном распространении через многие слои, если мы не находимся в зоне Златовласки, где входы для многих сигмоидов близки к нулю, градиенты всего продукта могут исчезнуть. Когда наша сеть может содержать много слоев, если мы не будем осторожны, градиент, вероятно, будет обрезан на каком-то слое. Действительно, раньше эта проблема мешала глубокому обучению сети.
Следовательно, ReLU, которые более стабильны (но менее правдоподобны), стали выбором по умолчанию для практикующих.
∂J/∂L = 1 и ∂J/∂s = 1. (5.7.8)
Затем мы вычисляем градиент целевой функции относительно переменной выходного слоя o в соответствии с цепным правилом:
∂J/∂o = prod (∂J/∂L, ∂L/∂o) = ∂L/∂o ∈ Rq, (5.7.9)
Затем мы вычисляем градиенты члена регуляризации по обоим параметрам:
∂s/∂W (1) = λW (1) и ∂s/∂W (2) = λW (2), (5.7.10)
Теперь мы можем вычислить градиент ∂J / ∂W (2) ∈ Rq × h параметров модели, ближайших к выходному слою. Использование цепного правила дает:
∂J/∂W (2) = prod (∂J/∂o, ∂o/∂W(2)) + prod (∂J/∂s, ∂s/∂W(2))
= ∂J/∂o h⊤ + λW(2), (5.7.11)
Чтобы получить градиент относительно W(1), нам нужно продолжить обратное распространение вдоль выходного слоя к скрытому слою. Градиент относительно скрытого слоя s выводит ∂J / ∂h ∈ Rh определяется так
∂J/∂h = prod (∂J/∂o, ∂o/∂h) = W(2)⊤ ∂J/∂o, (5.7.12)
Поскольку функция активации ϕ применяется поэлементно, вычисление градиента ∂J / ∂z ∈ Rh промежуточной переменной z требует использования оператора поэлементного умножения, который мы обозначим через ⊙:
∂J/∂z = prod (∂J/∂h, ∂h/∂z) = ∂J/∂h ⊙ ϕ'(z). (5.7.13)
Наконец, мы можем получить градиент ∂J / ∂W(1) ∈ Rh × d параметров модели, ближайших к входному слою. Согласно цепному правилу получаем
∂J/∂W(1) = prod (∂J/∂z, ∂z/∂W (1)) + prod (∂J/∂s, ∂s/∂W (1))
= ∂J/∂z x⊤ + λW (1) (5.7.14)
-
Обучение нейронных сетей
При обучении нейронных сетей прямое и обратное распространение зависят друг от друга. В частности, для прямого распространения мы проходим вычислительный граф в направлении зависимостей и вычисляем все переменные на его пути. Затем они используются для обратного распространения, когда порядок вычислений на графике меняется на противоположный.
В качестве примера возьмем вышеупомянутую простую сеть. С одной стороны, вычисление члена регуляризации (5.7.5) во время прямого распространения зависит от текущих значений параметров модели W(1) и W(2). Они задаются алгоритмом оптимизации согласно обратному распространению в последней итерации. С другой стороны, вычисление градиента для параметра eq_backprop-J-h во время обратного распространения зависит от текущего значения скрытой переменной h, которое задается прямым распространением.
Поэтому при обучении нейронных сетей после инициализации параметров модели мы чередуем прямое распространение с обратным распространением, обновляя параметры модели с использованием градиентов, заданных обратным распространением. Обратите внимание, что при обратном распространении повторно используются сохраненные промежуточные значения прямого распространения, чтобы избежать дублирования вычислений. Одним из последствий является то, что нам нужно сохранить промежуточные значения до завершения обратного распространения ошибки. Это также одна из причин, почему тренировка требует значительно больше памяти, чем простое предсказание. Кроме того, размер таких промежуточных значений примерно пропорционален количеству сетевых уровней и размеру пакета.
Таким образом, обучение более глубоких сетей с использованием пакетов большего размера легче приводит к ошибкам нехватки памяти.
Резюме
-
Прямое распространение последовательно вычисляет и сохраняет промежуточные переменные в пределах вычислительного графа, определенного нейронной сетью. Он переходит от входного к выходному слою. -
Обратное распространение последовательно вычисляет и сохраняет градиенты промежуточных переменных и параметров в нейронной сети в обратном порядке. -
При обучении моделей глубокого обучения прямое и обратное распространение взаимозависимы. -
Тренировка требует значительно больше памяти, чем предсказание.
Упражнения
-
Предположим, что входы X в некоторую скалярную функцию f являются матрицами размера n × m. Какова размерность градиента f по отношению к X? -
Добавьте смещение к скрытому слою модели, описанной в этом разделе.
-
Нарисуйте соответствующий вычислительный граф. -
Вывести уравнения прямого и обратного распространения.
-
Вычислите объем памяти для обучения и прогнозирования в модели, описанной в этом разделе. -
Предположим, вы хотите вычислить вторые производные. Что происходит с вычислительным графом? Сколько времени, по вашему мнению, займет расчет? -
Предположим, что вычислительный граф слишком велик для вашего графического процессора.-
Можете ли вы разделить его на несколько графических процессоров? -
Каковы преимущества и недостатки по сравнению с тренировкой на небольшой мини-партии?
-
Обсуждение (см. https://discuss.d2l.ai/t/102)
-
Числовая стабильность и инициализация
До сих пор каждая реализованная нами модель требовала, чтобы мы инициализировали ее параметры в соответствии с некоторым заранее заданным распределением. До сих пор мы считали схему инициализации само собой разумеющейся, не обращая внимания на детали того, как делается этот выбор. Возможно, у вас даже сложилось впечатление, что эти варианты не особенно важны. Напротив, выбор схемы инициализации играет важную роль в обучении нейронной сети и может иметь решающее значение для поддержания вычислительной устойчивости. Более того, этот выбор может быть интересным образом связан с выбором нелинейной функции активации. От того, какую функцию мы выбираем и как мы инициализируем параметры, зависит, насколько быстро сойдется наш алгоритм оптимизации. Неправильный выбор здесь может привести к тому, что во время тренировки мы столкнемся со взрывными или исчезающими градиентами. В этом разделе мы углубимся в эти темы более подробно и обсудим некоторые полезные эвристики, которые вы найдете полезными на протяжении всей вашей карьеры в области глубокого обучения.
-
Исчезающие и взрывающиеся градиенты
Рассмотрим глубокую сеть с L слоями, вход x и выход o. С каждым слоем l, определяемым преобразованием fl, параметризованным весами W(l), скрытая переменная которого равна h(l) (пусть h(0) = x), нашу сеть можно выразить как:
h(l) = fl (h(l − 1)) и, значит, o = fL ◦. . . ◦ f1 (x). (5.8.1)
Если все скрытые переменные и входные данные являются векторами, мы можем записать градиент o относительно любого набора параметров W(l) следующим образом:
∂W(l) o = ∂h (L − 1) h(L)M (L)def = ·. . . · ∂h (l) h(l + 1)M (l + 1) def =∂W (l) h(l)v(l)def =, (5.8.2)
Другими словами, этот градиент является произведением L − l матриц M (L)·. . . · M (l + 1) и вектор градиента v (l). Таким образом, мы подвержены тем же проблемам числового недолива, которые часто возникают при умножении слишком большого числа вероятностей. При работе с вероятностями распространенный трюк состоит в том, чтобы переключиться в лог-пространства, то есть сдвинуть давление с мантиссы на показатель степени числового представления. К сожалению, наша проблема более серьезна: изначально матрицы M
(l) могут иметь большое разнообразие собственных значений. Они могут быть маленькими или большими, а их произведение может быть очень большим или очень маленьким.
Риски, связанные с нестабильными градиентами, выходят за рамки численного представления. Градиенты непредсказуемой величины также угрожают стабильности наших алгоритмов оптимизации. Мы можем столкнуться с обновлениями параметров, которые либо (i) слишком велики, что разрушает нашу модель (проблема взрывающегося градиента); либо (ii) чрезмерно малы (проблема исчезающего градиента), что делает обучение невозможным, поскольку параметры практически не меняются при каждом обновлении.
Исчезающие градиенты
Одна из частых причин, вызывающих проблему исчезающего градиента, - это выбор функции активации σ, которая добавляется после линейных операций каждого слоя. Исторически сложилось так, что сигмовидная функция 1 / (1 + exp (−x)) (введено в: numref: sec_mlp) была популярна, потому что она напоминает функцию пороговой обработки. Поскольку первые искусственные нейронные сети были вдохновлены биологическими нейронными сетями, идея о нейронах, которые активируются либо полностью, либо совсем не активизируются (например, биологические нейроны), казалась привлекательной. Давайте внимательнее посмотрим на сигмоид, чтобы понять, почему он может вызывать исчезающие градиенты.
%matplotlib inline
from d2l import mxnet as d2l
from mxnet import autograd, np, npx
npx.set_np()
x = np.arange(-8.0, 8.0, 0.1)
x.attach_grad()
with autograd.record():
y = npx.sigmoid(x)
y.backward()
d2l.plot(x, [y, x.grad], legend=['sigmoid', 'gradient'], figsize=(4.5, 2.5))
Как видите, градиент сигмоиды исчезает как при больших, так и при малых входах. Более того, при обратном распространении через многие слои, если мы не находимся в зоне Златовласки, где входы для многих сигмоидов близки к нулю, градиенты всего продукта могут исчезнуть. Когда наша сеть может содержать много слоев, если мы не будем осторожны, градиент, вероятно, будет обрезан на каком-то слое. Действительно, раньше эта проблема мешала глубокому обучению сети.
Следовательно, ReLU, которые более стабильны (но менее правдоподобны), стали выбором по умолчанию для практикующих.