www.machinelearningmastery.ru

Машинное обучение, нейронные сети, искусственный интеллект
Header decor

Home

Shab Dev Story # 01: Попытка найти матричную форму градиентного спуска через backprop

Дата публикации Jun 7, 2017

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

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

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

В чем проблема?

Допустим, у нас есть двухслойная сеть (одна скрытая, одна выходная), и что мы используем матрицы для представления ее параметров (то есть весов), как для ее входных данных, и что мы используем матричную функцию активации:

Здесь X - это матрица, содержащая входные данные нашего мини-пакета (строки - это экземпляры, а столбцы - объекты). W1 и W2 - это матрицы, содержащие соответственно все веса, принадлежащие всем нейронам в скрытом слое и выходном слое (столбец представляет нейрон, а строки ниже - его веса). Нижняя сигма σ - это наша матричная функция активации (которая, например, в основном применяет сигмовидную функцию ко всем элементам входной матрицы). Что теперь, если мы хотим вычислить обновленное значение W1 для (мини-пакетного) шага градиентного спуска?

Тогда я пытался перенести производную некоторой функции потерь (например, MSE) с W.r.t на W1. Я закончил с чем-то вроде этого:

Это цепное правило не имеет смысла.

Это не работает вообще, на самом деле продукты матрицы не могут работать, потому что матрицы не имеют хороших размеров, чего я не знал в то время, почти год назад ». Я попытался изменить выражение, попытался добавить продукты Адамара, но ничего из этого не получилось. Затем я узнал об операции транспонирования матрицы и начал делать магические вещи, чтобы заставить формы и продукты матриц работать, гарантируя, что я получу эквивалентное выражение для частной производной функции потерь w.r.t весов W1 в ее скалярной форме. Это дало мне:

Дельта W1 дана после backprop.

Прошли месяцы, затем не так давно я начал работать над игрушечной нейронной библиотекой OCaml, даже если мой математический уровень немного выровнялся в течение года, я не смог найти реального математического обоснования, используя исчисление для Выражение выше. Даже когда дело доходит до математики, я думаю, что разработчик не должен использовать что-то настолько фундаментальное, по крайней мере, не пытаясь понять это. Андрей Карпатский«Да, вы должны понимать backprop»заставил меня решить, что я должен найти лучшее оправдание, чтобы найти мир.

Ищем способ выражения матричных производных

Реальная проблема, с которой мы здесь сталкиваемся, заключается в том, существует ли способ перенести частную производную функции стоимости w.r.t в W1 и, в более общем смысле, есть ли способ вывести производную матричной функции w.r.t в матрицу?

Какая производная?

Можно сказать, что производная от F (X) w.r.t по X является матрицей, имеющей форму X:

Производная матрицы (википедия)

В этом определении есть что-то интересное; матрица имеет форму X, что означает, что обновление наших параметров будет простым. Однако эта формула имеет недостаток:

Да, это не допускает правила цепочки, и нет правила цепочки -> нет backprop.

Нам нужно правило цепи, и это то, что JR. Магнус и Х. Нойдекер предлагают намМатричное дифференциальное исчисление (ch9.3), Они рассуждают о некоторых плохих обозначениях и хороших обозначениях для выражения производных матриц. Они в основном говорят, что перенос производной матрицы-функции w.r.t в матрицу несколько противоречив, и приводят аргументы в пользу обобщения якобиана на матрицы:

Формула 1. Векоператор vec

ЕслиF (X)имеет формупИксQа такжеИксимеет формумИксN,VEC (F (X))будет вектор-столбец, имеющий формурд.транспонирование (VEC (Х))будет вектор строки, имеющий формуМиннесотатаким образом, якобиан будет иметь формурдИксМиннесота, Хотя якобиан не совсем частная производнаяF (X)От X. к X он содержит всю информацию, которая нам необходима для его получения, и, прежде всего, он учитывает правило цепочки:

Формула 2 Производная композиции

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

Развертывание правила цепочки пошагово

Предупреждение /! \Этот раздел почти содержит только математику и может быть не очень интересным.
Теперь, когда у нас есть способ выражения производных матриц, мы можем заявить, что мы ищем в настоящее время:

Этот якобиан даст нам все, что нам нужно, чтобы обновить W1 для шага градиентного спуска. А пока давайте пошагово развернем правило цепочки:

Шаг 1.

Для первого блока мы видим, что ищем производную выражения, которое выполняет только поэлементное скалярное умножение на матрицу U (имя-заполнитель для квадрата вычитания). Мы знаем, что для скаляров производнаятопорw.r.tИксявляется(являясь константой), но для матрицы имеем:

Формула 3. Производная единичной функции - единичная матрица (dim - размерность вектора).

То есть матрица идентичности. Таким образом, мы просто имеем:

Затем для второго фрагмента мы ищем производную квадратной матрицы V (квадрат в смысле поэлементного произведения, а не матричного произведения):

Шаг 2.

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

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

Поскольку A, B и X все равны V в нашем случае; таким образом, выражение сводится к:

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

Шаг 3.

Для первого шага мы видим, что мы берем производную от вычитания, вот очевидная формула, которая нам нужна:

Формула 5. Производная вычитания

Тогда после простого применения мы получим:

Вот как выглядит наше выражение после развертывания функции потерь в цепочке правил:

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

Шаг 4

Поскольку σ (A) является приложением для поэлементной функции, мы имеем:

Формула 6. Производная поэлементной функции

Где σ ’- его производная.

Шаг 5

Здесь для следующего шага нам нужны производные от векторизованного матричного произведения, так как же мы можем это сделать? Во-первых, давайте введем формулу:

Формула 7 и 8. Векторизованное произведение 3 матриц и его производная.

Что интересно в этих формулах, так это то, что они позволяют использовать известные матрицы. Но как мы применим их к текущей частной производной, которую мы хотим, поскольку у нас есть произведение только между двумя матрицами? Вот две «хитрости»:

nrow (Х)количество строк в X
Ncol (Х)количество столбцов в X

Мы добавляем продукт с единичной матрицей слева от выражения, что позволяет нам использовать формулу выше:

Мы могли бы спросить, что помешало нам взять частную производную векторизованного матричного произведения между двумя матрицами? Преимущество состоит в том, что производные выражаются с помощью известных матриц, а также потому, что нам не нужно выводить их самим (= меньше работы).

Шаг 6

Этот шаг довольно прост, поскольку мы повторно используем ту же формулу, что и раньше (Формула 6). Теперь последний шаг:

Шаг 7

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

Это довольно много, поэтому давайте уменьшим его настолько, насколько сможем:

Сокращение выражения.

Обратите внимание, что мы могли бы продолжать сокращать, например, транспонирование единичной матрицы само по себе, Diag может быть объединен и т.д.

Обновление весов

Хорошо, теперь, когда мы развернули правило цепочки, у нас осталась матрица Якоби, как мы можем использовать ее для обновления W1 (и наших параметров в целом)?

Якобиева матрица.

Как вы можете видеть, каждый столбец включает производные по одному элементу вектора, поэтому, чтобы получить «суммарные» производные по этому элементу, нам нужно суммировать строки, мы можем сделать это с вектором строк, полным единиц, содержит столько столбцов, сколько якобиан содержит строк:

Это дает нам вектор-строку, содержащую суммированную производную w.r.t для каждого элемента W1

Чтобы обновить W1, нам нужно получить матрицу, имеющую такую ​​же форму, поэтому нам нужна функция, обратная к vec:

обратное vecпреобразовать вектор столбца в матрицу.

Теперь у нас есть матрица, имеющая ту же форму, что и W1, содержащая производную потерь w.r.t для каждого элемента матрицы. Обратите внимание, что мы транспонировали вектор строки, потому чтоVECвыводит вектор столбца.

Наконец, давайте посмотрим на последнее выражение, которое обновляет W1:

Давайте вспомним выражение, которое мы нашли, сопоставив размеры:

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

Вернуться к бэкпропу

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

Напомним, что здесь есть форма backprop, полученная путем согласования размеров:

И заявление об обновлении:

Бэкпроп форма, которую мы нашли с помощью матричного исчисления:

Интуиция за обратным распространением ошибок заключается в том, что во-первых, у нас есть ошибка на уровне функции потерь, то есть, насколько изменяется потеря в зависимости от изменения.Н (Х).Затем, начиная с выходного слоя и возвращаясь к первому скрытому слою, мы вычисляем ошибку нейронов в текущем слое. Это выполняется путем выполнения матричного произведения между ошибкой на следующем уровне (кроме выходного слоя, кстати, потому что ошибка происходит от функции потерь, а не слоя) и производной функции активации по отношению к входам этого уровня. Тогда для весов этого слоя,Wl, общая ошибка с весами равна произведению ошибки в нейронах текущего слоя и их входных данных.

Вот шаги backprop для нашей двухслойной нейронной сети:

Затем обновить вес слоя:

Реализация

Следующая суть - реализация NumPy нейронной сети, обученной с использованием градиентного спуска через две формы backprop для проблемы XOR. Скорость обучения равна 1, и мы не делим дельты на 1/4, чтобы ускорить слияние нейронной сети.np.kronявляется продуктом Кронекера,np.diagэто функция Diag иnp.eyeвозвращает единичную матрицу

Какую форму backprop мы должны использовать

Я нашел векторизованное производное более простым в использовании и более педагогическим; Вы можете видеть, что нам никогда не приходилось обращаться к матричному элементу Aij, все, что мы делали, это разворачивали правило цепочки. Однако, конечно, мы должны использовать форму, которую нашли, сопоставляя формы, потому что она более эффективна в отношении памяти и производительности. Матрицы Diag и продукты Kronecker стоят дорого.

Вывод

Многие люди обеспокоены ИИ и тем фактом, что его можно использовать для плохих целей, но я думаю, что мы не должны пренебрегать тем фактом, что разработчики, использующие алгоритмы ИИ в качестве «черного ящика», также могут заставить ИИ совершать плохие действия непреднамеренно. Вот почему я думаю, что мы, разработчики, должны хотя бы попытаться понять, как работают модели. Не нужно быть математиком, вы даже можете читать газеты и просить помощи у вашего друга Google! Вещи, сделанные на местах прямо сейчас, поразительны (ДХО, ГАН ... ❤). Начать никогда не поздно, лично я заинтересовался нейронными сетями и вещами ML только в прошлом году после просмотра фильмов про Железного Человека 😅.

Оригинальная статья

Footer decor

© www.machinelearningmastery.ru | Ссылки на оригиналы и авторов сохранены. | map