Я подумал, что отвечу на отдельный пост здесь для всех, кто заинтересован. Это будет использовать обозначения, описанные здесь .
Вступление
Идея обратного распространения заключается в том, чтобы иметь набор «обучающих примеров», которые мы используем для обучения нашей сети. У каждого из них есть известный ответ, поэтому мы можем подключить их к нейронной сети и выяснить, насколько это было неправильно.
Например, при распознавании рукописного ввода у вас будет много рукописных символов наряду с тем, чем они были на самом деле. Затем нейронную сеть можно обучить с помощью обратного распространения, чтобы «научиться» распознавать каждый символ, а затем, когда он будет представлен неизвестным рукописным символом, он сможет определить, что это такое.
В частности, мы вводим некоторую обучающую выборку в нейронную сеть, видим, насколько она хороша, затем «стекаем назад», чтобы выяснить, насколько мы можем изменить вес и смещение каждого узла, чтобы получить лучший результат, и затем соответствующим образом скорректировать их. Пока мы продолжаем это делать, сеть «учится».
Есть и другие шаги, которые могут быть включены в учебный процесс (например, отсев), но я сосредоточусь в основном на обратном распространении, поскольку именно об этом и был этот вопрос.
Частные производные
Частная производная является производной от по некоторой переменной . фх∂f∂xfx
Например, если , , потому что является просто константой относительно . Аналогично, , потому что является просто константой относительно .∂ ff(x,y)=x2+y2y2x∂f∂f∂x=2xy2xй2у∂f∂y=2yx2y
Градиент функции, обозначенной , является функцией, содержащей частную производную для каждой переменной в f. В частности:∇f
∇f(v1,v2,...,vn)=∂f∂v1e1+⋯+∂f∂vnen
,
где - единичный вектор, указывающий в направлении переменной .eiv1
Теперь, как только мы вычислили для некоторой функции , если мы находимся в позиции , мы можем «скользить вниз» по в направлении .F ( v 1 , v 2 , . . . , V п ) е - ∇ F ( V 1 , V 2 , . . . , V п )∇ff(v1,v2,...,vn)f−∇f(v1,v2,...,vn)
В нашем примере единичными векторами являются и , потому что и , и эти векторы указывают в направлении осей и . Таким образом, .e 1 = ( 1 , 0 ) e 2 = ( 0 , 1 ) v 1 = x v 2 = y x y ∇ f ( x , y ) = 2 x ( 1 , 0 ) + 2 у ( 0 , 1 )f(x,y)=x2+y2e1=(1,0)e2=(0,1)v1=xv2=yxy∇f(x,y)=2x(1,0)+2y(0,1)
Теперь, чтобы «сдвинуть» нашу функцию , скажем, мы находимся в точке . Тогда нам нужно двигаться в направлении .( - 2 , 4 ) - ∇ f ( - 2 , - 4 ) = - ( 2 ⋅ - 2 ⋅ ( 1 , 0 ) + 2 ⋅ 4 ⋅ ( 0 , 1 ) ) = - ( ( - 4 , 0 ) + ( 0 , 8 ) ) = ( 4 ,f(−2,4)−∇f(−2,−4)=−(2⋅−2⋅(1,0)+2⋅4⋅(0,1))=−((−4,0)+(0,8))=(4,−8)
Величина этого вектора даст нам, насколько крутой холм (более высокие значения означают, что холм круче). В этом случае у нас есть .42+(−8)2−−−−−−−−−√≈8.944
Адамар продукт
Произведение Адамара двух матриц , аналогично сложению матриц, за исключением того, что вместо сложения матриц пошагово, мы умножаем их поэлементно.A,B∈Rn×m
Формально при матричном сложении есть , где такой, чтоC ∈ R n × mA+B=CC∈Rn×m
Cij=Aij+Bij
,
Произведение Адамара , где такое, чтоC ∈ R n × mA⊙B=CC∈Rn×m
Cij=Aij⋅Bij
Вычисление градиентов
(Большая часть этого раздела из книги Нильсена ).
У нас есть набор обучающих выборок , где - это одна входная обучающая выборка, а - ожидаемое выходное значение этой обучающей выборки. Мы также имеем нашу нейронную сеть, состоящую из пристрастий и веса . используется для предотвращения путаницы с , и используемыми в определении сети прямой связи.(S,E)SrErWBrijk
Затем мы определяем функцию стоимости, которая берет в нашей нейронной сети и один пример обучения, и выводит, насколько хорошо это было сделано.C(W,B,Sr,Er)
Обычно используется квадратичная стоимость, которая определяется
C(W,B,Sr,Er)=0.5∑j(aLj−Erj)2
где - выход в нашу нейронную сеть, данный входной образецaLSr
Затем мы хотим найти и для каждого узла в нашей нейронной сети с прямой связью.∂C∂wij∂C∂bij
Мы можем назвать это градиентом в каждом нейроне, потому что мы рассматриваем и как константы, так как мы не можем изменить их, когда мы пытаемся учиться. И это имеет смысл - мы хотим двигаться в направлении относительно и что минимизирует затраты, и движение в отрицательном направлении градиента относительно и сделает это.CSrErWBWB
Для этого мы определяем как ошибку нейрона в слое .δij=∂C∂zijji
Мы начнем с вычисления , подключив к нашей нейронной сети.aLSr
Затем мы вычисляем ошибку нашего выходного слоя, , черезδL
δLj=∂C∂aLjσ′(zLj)
.
Который также можно записать как
δL=∇aC⊙σ′(zL)
.
Далее мы находим ошибку в терминах ошибки в следующем слое , черезδiδi+1
δi=((Wi+1)Tδi+1)⊙σ′(zi)
Теперь, когда у нас есть ошибка каждого узла в нашей нейронной сети, вычислить градиент относительно наших весов и смещений легко:
∂C∂wijk=δijai−1k=δi(ai−1)T
∂C∂bij=δij
Обратите внимание, что уравнение для ошибки выходного слоя является единственным уравнением, зависящим от функции стоимости, поэтому, независимо от функции стоимости, последние три уравнения одинаковы.
В качестве примера с квадратичной стоимостью получаем
δL=(aL−Er)⊙σ′(zL)
для ошибки выходного слоя. и затем это уравнение можно вставить во второе уравнение, чтобы получить ошибку слоя :L−1th
δL−1=((WL)TδL)⊙σ′(zL−1)
=((WL)T((aL−Er)⊙σ′(zL)))⊙σ′(zL−1)
которые мы можем повторить этот процесс , чтобы найти ошибку любого слоя относительно , который затем позволяет вычислять градиент весов и смещения любого узла по отношению к .CC
Я мог бы написать объяснение и доказательство этих уравнений при желании, хотя можно также найти доказательства их здесь . Тем не менее, я бы посоветовал всем, кто читает это, доказать это сами, начиная с определения и применяя правило цепи свободно.δij=∂C∂zij
Для еще несколько примеров, я сделал список некоторых функций затрат наряду с их градиентов здесь .
Градиентный спуск
Теперь, когда у нас есть эти градиенты, нам нужно использовать их для обучения. В предыдущем разделе мы нашли, как двигаться, чтобы «скользить» вниз по кривой относительно некоторой точки. В этом случае, поскольку это градиент некоторого узла по отношению к весам и смещению этого узла, наша «координата» - это текущий вес и смещение этого узла. Поскольку мы уже нашли градиенты относительно этих координат, эти значения уже являются тем, сколько нам нужно изменить.
Мы не хотим скользить вниз по склону с очень высокой скоростью, иначе мы рискуем проскользнуть ниже минимума. Чтобы предотвратить это, мы хотим иметь «размер шага» .η
Затем найдите, насколько мы должны изменить каждый вес и смещение, потому что мы уже вычислили градиент по отношению к имеющемуся у нас току.
Δwijk=−η∂C∂wijk
Δbij=−η∂C∂bij
Таким образом, наши новые веса и уклоны
wijk=wijk+Δwijk
bij=bij+Δbij
Использование этого процесса в нейронной сети только с входным слоем и выходным слоем называется дельта-правилом .
Стохастический градиентный спуск
Теперь, когда мы знаем, как выполнять обратное распространение для одного образца, нам нужен какой-то способ использовать этот процесс, чтобы «изучить» весь наш тренировочный набор.
Один из вариантов - просто выполнить обратное распространение для каждого образца в наших данных обучения, по одному за раз. Это довольно неэффективно, хотя.
Лучший подход - Стохастический градиентный спуск . Вместо того, чтобы выполнять обратное распространение для каждого образца, мы выбираем небольшую случайную выборку (называемую серией ) нашего обучающего набора, а затем выполняем обратное распространение для каждого образца в этой партии. Надежда состоит в том, что, делая это, мы фиксируем «намерение» набора данных без необходимости вычислять градиент каждой выборки.
Например, если у нас было 1000 образцов, мы могли бы выбрать партию размером 50, а затем запустить обратное распространение для каждого образца в этой партии. Надежда состоит в том, что нам дали достаточно большой обучающий набор, чтобы он представлял распределение фактических данных, которые мы пытаемся изучить достаточно хорошо, что выбор небольшой случайной выборки достаточен для сбора этой информации.
Тем не менее, выполнение обратного распространения для каждого примера обучения в нашей мини-партии не является идеальным, потому что мы можем в конечном итоге «вертеться», когда обучающие образцы изменяют веса и смещения таким образом, что они взаимно компенсируют друг друга и не позволяют им добраться до минимум, к которому мы стремимся.
Чтобы предотвратить это, мы хотим перейти к «среднему минимуму», потому что есть надежда, что в среднем градиенты выборок указывают вниз по склону. Итак, после случайного выбора нашей партии мы создаем мини-партию, которая представляет собой небольшую случайную выборку нашей партии. Затем дается мини-партия с обучающими выборками, и обновляются только веса и смещения после усреднения градиентов каждой выборки в мини-партии.n
Формально мы делаем
Δwijk=1n∑rΔwrijk
и
Δbij=1n∑rΔbrij
где - вычисленное изменение веса для образца , а - вычисленное изменение смещения для образца .ΔwrijkrΔbrijr
Затем, как и раньше, мы можем обновить весовые коэффициенты с помощью:
wijk=wijk+Δwijk
bij=bij+Δbij
Это дает нам некоторую гибкость в том, как мы хотим выполнить градиентный спуск. Если у нас есть функция, которую мы пытаемся изучить с большим количеством локальных минимумов, такое поведение «шатания» на самом деле желательно, потому что это означает, что у нас гораздо меньше шансов «застрять» в одном локальном минимуме, и с большей вероятностью «выпрыгнуть» из одного локального минимума и, надеюсь, упасть в другом, который ближе к глобальным минимумам. Таким образом, мы хотим маленькие мини-партии.
С другой стороны, если мы знаем, что локальных минимумов очень мало, и, как правило, градиентный спуск направляется к глобальным минимумам, нам нужны более крупные мини-партии, потому что такое поведение "покачивания" не позволит нам спуститься по склону так быстро как мы хотели бы. Смотрите здесь .
Один из вариантов - выбрать самую большую мини-партию, учитывая всю партию как одну мини-партию. Это называется « Пакетный градиентный спуск» , поскольку мы просто усредняем градиенты пакета. Это практически никогда не используется на практике, потому что это очень неэффективно.