Интуиция, лежащая в основе определения весов нейронной сети, на примере.

В этой статье я продолжу обсуждение искусственных нейронных сетей и приведу пример очень простой нейронной сети, написанной на Python. Цель этой серии статей, которые я пишу, - дать полное объяснение ИНС с нуля, не скрываясь за специальными библиотеками. Tensorflow отлично подходит для создания прототипов и производства, но когда дело доходит до образования, единственный способ научиться - это взять карандаш и бумагу и испачкаться в математике.

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

Сопоставление входов с выходами

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

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

Если вы не понимаете, почему линейная связь дает нам только один слой с функцией активации идентичности; просто потерпите меня. Прежде чем объяснять, позвольте мне визуализировать нашу нейронную сеть и показать функцию, которую она представляет.

Если бы у нас было больше слоев, использующих функцию идентичности, мы всегда могли бы упростить ее до приведенного выше уравнения. Попробуйте сами, добавив средний слой с 2 ​​нейронами, каждый с функцией активации идентичности, затем напишите уравнение, соответствующее сети, и упростите его.

Здесь вы можете легко вычислить веса, используя множество различных методов. В конце концов, это всего лишь система линейных уравнений. Но давайте попробуем решить это в общем случае, когда у нас НЕ существует линейной зависимости.

Измерение того, насколько мы неправы, с помощью функции ошибок

Итак, давайте повеселимся. Как мы могли найти вес, не рассматривая это как систему линейных уравнений? Что ж, вам нужно с чего-то начать, поэтому давайте сначала попробуем слепо предположить, какими они могут быть. Я собираюсь предположить, что W1 = 0,2, W2 = 1,4 и W3 = 30.

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

Напомним, правильный результат (или ожидаемый результат) должен быть 13,5 по нашим данным; мы далеко! Давайте определим, насколько мы ошибаемся, с помощью функции ошибок. Когда NN выводит правильное значение, мы хотим, чтобы ошибка была равна 0. Начнем с; Ошибка = правильный вывод-вывод нашей ИНС (например, 0 = 13,5–13,5, если наши веса были правильными).

Мы почти на месте. Подумайте практически, нашу ошибку мы хотим минимизировать. Ну, каков минимум нашей текущей функции ошибок? Нет минимума! Как бы то ни было, мы можем получить ошибку -∞. Мы исправляем это возведением функции в квадрат, поэтому она не может быть отрицательной, Error = (правильный вывод-вывод нашей ИНС) ². Обратите внимание, что форма этой функции ошибок представляет собой просто параболу с центром в 0. Теперь это ошибка в одном выходном нейроне. Если у нас есть несколько выходов, мы просто берем среднюю ошибку для всех из них. Итак, у нас есть;

Сведение к минимуму того, насколько мы неправы (минимизация нашей ошибки)

Когда вы изменяете вес на очень небольшую величину (∂W), вы получаете и изменяете ошибку (∂E). Итак, если мы хотим выяснить, насколько изменение этого веса влияет на ошибку, мы можем взять отношение 2, ∂E / ∂W. Это можно распознать как частную производную функции ошибок по этому весу или как небольшое изменение этого веса изменяет ошибку.

Как это нам помогает? Что ж, если вы хорошо разбираетесь в расчетах, вы можете знать, к чему это приведет. Но если это не так, взгляните на график ниже.

Это просто произвольная функция. Возьмите любую точку на этой линии и приложите к ней палец. Теперь скажите вслух, является ли наклон в этой точке положительным или отрицательным. Если наклон положительный, немного проведите пальцем по линии в направлении + X. Если он отрицательный, переместите его в направлении -X. Если наклон равен 0… выберите другую точку. Сделайте это для пары очков. Заметили что-нибудь?

Несмотря ни на что, вы всегда будете двигать пальцем в сторону более высокого значения на линии.

Направление производной всегда является направлением подъема.

Если производная отрицательна, уменьшение X увеличит Y. Если производная положительна, увеличение X увеличит Y.

Вернемся к нашей NN с ∂E / ∂W. Мы хотим уменьшить нашу ошибку, поэтому мы хотим переместить вес в направлении спуска. Мы можем сделать это, вычислив эту производную, а затем отрицая ее. Теперь мы перемещаем наш вес на крошечный шаг в направлении этой отрицательной производной. Или;

Это только для одного веса в нашей сети. Мы можем записать это выражение в матричной форме, помня, что градиент - это просто вектор, содержащий все производные ∂E / ∂Wi. Матричная форма показана ниже;

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

Краткое резюме

Позвольте мне резюмировать последние 2 страницы. У нас есть данные и некоторые выводы. Мы знаем, что между этими данными и результатами есть некоторая связь. Вдохновленные человеческим мозгом, мы можем построить искусственную нейронную сеть. Мы инициализируем эту нейронную сеть со случайными весами, а затем начинаем тестировать ее на данных и выходных данных, которые у нас есть. Во время тестирования мы количественно оцениваем, насколько ошибочна наша сеть, с помощью функции ошибок, а затем минимизируем эту функцию ошибок с помощью градиентного спуска.

Пример

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

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

Нахождение градиента нашей функции

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

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

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

Обновление весов 2000 раз обычно бывает достаточно, если вы угадали нелепые веса, которые были в десятках тысяч или больше, может потребоваться больше. Взгляните на веса, которые вы получили после запуска этого кода, вы получили [.5, .9,1.2]? Что ж, это точные веса, которые я использовал для создания этих данных.

Разве это не невероятно ?! Используя вычисления и данные, мы можем приблизительно определить взаимосвязь между любыми двумя взаимосвязанными вещами! Вы можете сказать: Ну, это простой пример, я мог бы решить его за 2 минуты, рассматривая его как систему линейных уравнений. Что ж, вы совершенно правы. Но что, если бы было 5 или 6 слоев, каждый с более чем 1000 нейронами, каждый из которых использовал функцию активации сигмовидной кишки. Решать вручную любым способом просто за окном. Что нам нужно, так это систематический алгоритм, который может найти градиент для весов в нашей сети, который я просматриваю здесь.

Спасибо за чтение! Если этот пост вам чем-то помог или у вас есть комментарий или вопрос, оставьте, пожалуйста, ответ ниже и дайте мне знать! Кроме того, если вы заметили, что я где-то допустил ошибку или я мог бы объяснить что-то более четко, я был бы признателен, если бы вы сообщили мне об этом в своем ответе.

Это продолжение серии статей, которые дают интуитивное объяснение нейронных сетей с нуля. Для других статей перейдите по ссылкам ниже:

Часть 1: Что такое искусственная нейронная сеть

Часть 2: Как обучить нейронную сеть с нуля

Часть 3: Полная реализация градиентного спуска

Часть 4: Реализация градиентного спуска (пример)

Часть 5: Как классифицировать рукописные цифры в Python