Выбрано из среды,Автор: Омар У. Флорес, участие: Нурхачу Нулл, Чжан Цянь.
Обучение модели и настройка параметров — очень трудоемкая и трудоемкая задача, а понимание математических принципов внутри нейронной сети помогает быстро разобраться в проблеме. Автор этой статьи начинает с нуля и шаг за шагом объясняет математический процесс, используемый для обучения нейронной сети.
Нейронная сеть — это продуманное сочетание линейных и нелинейных модулей. Когда эти модули выбраны и соединены с умом, мы получаем мощный инструмент для аппроксимации любой математической функции, такой как нейронная сеть, способная классифицировать с помощью нелинейных границ решений.
Шаги для запуска кода следующие:
git clone https://github.com/omar-florez/scratch_mlp/
python scratch_mlp/scratch_mlp.py
несмотря на то чтообратное распространениеЭтот метод интуитивно понятен и модульен, но он отвечает за обновление обучаемых параметров, тема, которая не была подробно объяснена. Давайте возьмем в качестве примера кубики Lego, будем добавлять по одной штуке и построим нейронную сеть с нуля, чтобы изучить ее внутренние функции.
Нейронные сети похожи на блоки Lego
На приведенной выше диаграмме показана часть математического процесса, используемого для обучения нейронной сети. Мы объясним это в этой статье. Читателю может быть интересно: нейронная сеть — это набор модулей с разными целями.
Входная переменная X передает необработанные данные нейронной сети, которые хранятся в матрице, где строки — это наблюдения, а столбцы — измерения.
Вес W_1 сопоставляет вход X с первым скрытым слоем h_1. Тогда вес W_1 действует как линейное ядро.
Сигмовидная функция предотвращает попадание чисел в скрытом слое за пределы диапазона 0-1. Результатом является массив нейронных активаций, h_1 = Sigmoid(WX).
На данный момент эти операции просто образуют общую линейную систему и не могут моделировать нелинейные взаимодействия. Это меняется, когда мы накладываем еще один слой, добавляя глубины структуре модуля. Чем глубже сеть, тем более тонкие нелинейные взаимодействия мы узнаем и тем более сложные проблемы мы можем решить, что может быть одной из причин появления глубоких нейронных моделей.
Почему я читаю эту статью?
Если вы разбираетесь во внутреннем устройстве нейронной сети, вы сможете быстро узнать, что нужно изменить в первую очередь, когда столкнетесь с проблемами, и сможете разработать стратегии для проверки того, что вы знаете о некоторых инвариантах и ожидаемом поведении алгоритма.
Потому что отладка моделей машинного обучения — сложная задача. Как правило, математические модели не работают с первой попытки. Они могут давать меньшую точность на новых данных, долго обучаться или занимать слишком много памяти, возвращать большой ложный отрицательный результат или прогнозы NAN... В некоторых случаях понять, как работает алгоритм Механизмы могут сделать нашу задачу более удобной:
Если обучение занимает слишком много времени, может быть хорошей идеей увеличить размер мини-пакета, что уменьшит дисперсию наблюдений и поможет алгоритму сходиться.
Если вы видите прогнозы NAN, возможно, алгоритм получил большие градиенты и переполнил память. Думайте об этом как об умножении матриц, которое взрывается после многих итераций. Уменьшение скорости обучения может уменьшить эти значения. Уменьшение количества слоев уменьшает количество умножений. Градиенты сдвига также могут значительно решить эту проблему.
Конкретный пример:Изучите функцию XOR
Давайте откроем черный ящик. Теперь мы собираемся построить обучение с нуляисключающее ИЛИфункция нейронной сети. Выбор этой нелинейной функции определенно не случаен. Без обратного распространения было бы трудно научиться классифицировать с помощью прямой линии.
Чтобы проиллюстрировать эту важную концепцию, обратите внимание на изображение ниже, почему прямая линия не может классифицировать 0 и 1 в выходных данных функции XOR. Проблемы реальной жизни также нелинейно разделимы.
Топология этой сети очень проста:
Входная переменная X представляет собой двумерный вектор
Веса W_1 представляют собой матрицу 2x3 со случайно инициализированными значениями.
Скрытый слой h_1 содержит 3 нейрона. Каждый нейрон получает на вход взвешенную сумму наблюдений, которая представляет собой внутренний продукт, выделенный зеленым цветом на изображении ниже: z_1 = [x_1, x_2][w_1, w_2]
Веса W_2 — это матрица 3x2 со случайными значениями инициализации
Выходной слой h_2 содержит два нейрона, потому что выход функции XOR равен либо 0 (y_1 = [0,1]), либо 1 (y_2 = [1,0]).
Следующий рисунок более нагляден:
Давайте обучим эту модель сейчас. В нашем простом примере обучаемыми параметрами являются веса, но следует знать, что текущие исследования изучают больше типов параметров, которые можно оптимизировать. Например, быстрые соединения между слоями,РегуляризацияРаспределения, топология, остатки, скорость обучения и многое другое.
Обратное распространение — это метод обновления весов (градиентов) в направлении, которое минимизирует предопределенную метрику ошибки (то есть функцию потерь) с учетом пакета помеченных наблюдений. Этот алгоритм неоднократно открывался заново как частный случай другого более общего метода, называемого автоматическим дифференцированием в режиме обратного накопления.
инициализация сети
Давайте инициализируем веса сети случайными числами
Шаги вперед:
Цель этого шага — передать входную переменную X вперед через каждый слой сети, пока не будет вычислен вектор для выходного слоя h_2.
Это процесс расчета, который происходит в нем:
Линейно проверьте входные данные X с весом W_1 как линейное преобразование:
Взвешенная сумма масштабируется с помощью сигмовидной функции активации, чтобы получить значение первого скрытого слоя h_1. Обратите внимание, что исходный 2D-вектор теперь отображается в 3D-пространстве.
Аналогичный процесс происходит в слое 2 h_2. Начнем с вычисления взвешенной суммы z_2 первого скрытого слоя, который теперь является входными данными.
Затем рассчитываются их сигмовидные функции активации. Вектор [0,37166596 0,45414264] представляет логарифмическую вероятность или вектор предсказания, вычисленный сетью для заданного входа X.
Подсчитайте общий убыток
Эта функция потерь, также известная как «фактическое минус предсказанное», предназначена для количественной оценки расстояния между предсказанным вектором h_2 и искусственной меткой y.
Обратите внимание, что эта функция потерь включает член регуляризации, который штрафует большие веса в форме гребневой регрессии. Другими словами, вес с большим квадратным значением увеличит функцию потерь, которую мы хотим минимизировать.
Обратные шаги:
Цель этого шага — обновить веса нейронной сети в направлении, которое минимизирует функцию потерь. Как мы увидим, это рекурсивный алгоритм, который повторно использует ранее вычисленные градиенты и сильно зависит от дифференциальных функций. Поскольку эти обновления уменьшают функцию потерь, нейронная сеть «научится» аппроксимировать метки наблюдений известными классами. Это свойство называется обобщением.
В отличие от шага вперед, этот шаг выполняется в обратном порядке. Сначала он вычисляет частную производную функции потерь в выходном слое по каждому весу (dLoss/dW_2), а затем вычисляет частную производную скрытого слоя (dLoss/dW1). Поясним подробно каждую производную.
dLoss/dW_2:
Цепное правило показывает, что мы можем разбить вычисление градиента нейронной сети на несколько дифференциальных частей:
Для облегчения памяти в следующей таблице перечислены некоторые определения функций, использованные выше, и их первые производные:
Более интуитивно, мы хотим обновить вес W_2 (синяя часть) на рисунке ниже. Для этого нам нужно вычислить три частные производные по цепочке производных.
Подставляя значения в эти частные производные, мы можем вычислить частные производные W_2 следующим образом:
Результатом является матрица 3x2 dLoss/dW_2, которая будет обновлять значение W_2 в направлении минимизации функции потерь.
dLoss/dW_1:
Вычисление цепного правила для обновления весов первого скрытого слоя W_1 показывает возможность повторного использования существующих вычислений.
Более интуитивно, путь от выходного слоя к весу W_1 сталкивается с частными производными, которые уже были вычислены в более поздних слоях.
Например, частные производные dLoss/dh_2 и dh_2/dz_2 были вычислены в предыдущем разделе как зависимости изученных весов выходного слоя dLoss/dW_2.
Собрав все производные вместе, мы можем снова выполнить цепное правило, чтобы обновить веса для W_1 скрытого слоя.
Наконец, мы присваиваем весам новые значения, завершая один шаг обучения нейронной сети.
выполнить
Давайте преобразуем приведенное выше математическое уравнение в код, используя только numpy в качестве механизма линейной алгебры. Нейронная сеть обучается в цикле, где каждая итерация предоставляет нейронной сети стандартные входные данные. В этом небольшом примере мы рассматриваем только весь набор данных на каждой итерации. Вычисления прямого шага, функции потерь и обратного шага обобщаются лучше, потому что мы обновляем обучаемые параметры с их соответствующими градиентами (матрицами dL_dw1 и dL_dw2) на каждой итерации.
Код хранится в этом репо:GitHub.com/Omar-Flore в…
Давайте запустим этот код!
Ниже вы можете увидеть некоторые нейронные сети, которые были обучены за множество итераций для аппроксимации функции XOR.
Во-первых, давайте посмотрим, почему нейронная сеть с 3 нейронами в скрытом слое слаба. Модель учится выполнять бинарную классификацию с простой границей решения, которая начинается как прямая линия, но затем демонстрирует нелинейное поведение. По мере продолжения обучения функция потерь на правом графике также значительно уменьшается.
Нейронная сеть с 50 нейронами в скрытом слое значительно увеличивает способность модели изучать границы сложных решений. Это не только приводит к более точным результатам, но и увеличивает градиенты, что является серьезной проблемой при обучении нейронных сетей. Когда градиент очень велик, непрерывное умножение при обратном распространении дает большие веса обновления. Вот почему функция потерь внезапно увеличивается на последних нескольких шагах обучения (шаг> 90). Член регуляризации функции потерь вычисляет квадрат значения (сумма (W²)/2N) весов, которые стали большими.
Как видите, этой проблемы можно избежать, уменьшив скорость обучения. Этого можно достичь, внедрив политику, которая со временем снижает скорость обучения. Или путем усиления регуляризации, возможно, L1 или L2. Исчезновение градиента и взрыв градиента — очень интересные явления, полный анализ которых мы проведем позже.