Что такое нейронная сеть?

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

Что такое нейронная сеть?

Нейронная сеть — это набор связанных узлов, называемых нейронами.

Что такое нейрон?

Нейрон — это узел, который имеет один или несколько входов и один выход, как показано на рис. 1. Внутри нейрона происходят три действия:

  • Вес связан с каждым входом для его усиления или деамплификации;
  • Все взвешенные входы суммируются;
  • Сумма используется в качестве входных данных для функции активации, которая определяет конечный результат.

Что такое функция активации?

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

Идея довольно проста: входные значения, близкие к нулю, вызовут существенное изменение на выходе, а слишком большие или слишком маленькие входные значения вызовут минимальную разницу.

Как связаны нейроны?

Выход одного нейрона может использоваться как вход для других нейронов. Как правило, нейроны объединены в слои. Слой — это общий термин, который применяется к набору узлов, работающих вместе на определенной глубине в нейронной сети. Выходы перемещаются от первого уровня к последнему слою. Как показано на рисунке 3, обычно существует входной слой, один или несколько средних слоев (называемых скрытыми слоями) и выходной слой.

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

Количество входных и выходных нейронов зависит от решаемой задачи. Количество скрытых нейронов часто равно сумме входных и выходных нейронов, но это не правило.

Как они работают?

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

Пример

Пример Hello-World для нейронных сетей обычно реализует нейронную сеть для распознавания оператора XOR. Нейронная сеть для этого имеет

  • два входа,
  • один выход и
  • мы будем использовать один скрытый слой с тремя нейронами — как рекомендуется, сумма входных и выходных нейронов.

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

Шаг 1. Инициализируйте веса и смещения

Первым шагом в работе с нейронной сетью является инициализация весов. Какие варианты у нас есть?

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

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

Шаг 2. Прямое распространение

Это причудливое название для предоставления сети одного входа и наблюдения за выходом. Мы начинаем с входного слоя и вычисляем выходные данные для скрытого слоя. Результаты передаются на следующий уровень. Затем мы вычисляем выходные данные выходного слоя, используя выходные данные скрытого слоя в качестве входных данных. Рисунок 5 показывает математику. Это просто линейная алгебра. Вот и все.

Шаг 3. Рассчитайте ошибку

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

Если нейронная сеть имеет более одного узла в выходном слое, ошибка рассчитывается как суммирование всех частичных ошибок.

Шаг 4. Обратное распространение

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

Как изменить значение весов, чтобы уменьшить ошибку?

Короткий ответ: используйте алгоритм градиентного спуска. Впервые он был предложен в 1847 году. Он применяет многомерное исчисление, в частности частные производные. Производная функции ошибок по каждому весу используется для корректировки значений весов. Производную функции ошибок можно умножить на выбранное число (называемое скорость обучения), чтобы убедиться, что новый обновленный вес минимизирует функцию ошибок. Скорость обучения представляет собой небольшую положительную величину, часто в диапазоне от 0,0 до 1,0.

Чтобы вычислить частные производные по весам, нам нужны производная функции ошибки и производная сигмовидной функции. На рисунке 7 показано общее уравнение для обновления весов и один пример решения уравнения для веса W₆ — веса первого входа для нейрона в выходном слое.

Принцип цепного исчисления применяется для вычисления производной составной функции. Имейте в виду, что вычисления похожи, но не одинаковы для нейронов в выходном слое и нейронов в скрытом слое.

Итак, мы начинаем со случайных значений веса, затем:

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

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

Кодирование примера

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

Во-первых, атрибуты:

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

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

Шаг 1. Инициализируйте веса и смещения

Мы можем использовать конструктор для инициализации массивов и ввода начальных значений весов и смещения. Помните, что изначально это просто случайные значения. Строки 11 и 13 выполняют инициализацию.

Шаг 2. Прямое распространение

Нам нужно решить уравнения, показанные на рисунке 5. Итак, давайте создадим для этого метод. Обратите внимание, что входные данные обрабатываются как узлы (во входном слое), но они не вычисляют для них выходные значения. Мы вычисляем выходы для узлов скрытого слоя и узлов выходного слоя. Выходные данные вычисляются путем умножения значений веса на входное значение, их суммирования и применения функции активации. Мы используем сигмоид в качестве функции активации и создаем сигмовидный метод только для того, чтобы сохранить разделение задач. Отмечая здесь сложность, в основном это реализация линейной алгебры, описанной на рисунке 5. Мы запустим это для каждого отдельного набора входных значений, таким образом, оно будет выполняться 4 раза с {0,0}, {0,1}, {1 ,0} и {1,1}

Шаг 3. Рассчитайте ошибку

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

Шаг 4. Обратное распространение

Наконец, давайте создадим обучающую часть — метод, который реализует математику, отвечающую за обновление значений весов. Многомерное исчисление живет там. Этот метод выполняется для каждого отдельного набора известных выходных значений, поэтому он будет выполняться 4 раза с {0.0}, {1.0}, {1.0} и {0.0}.

У нас есть все части; пришло время собрать их вместе и запустить нашу реализацию. Взгляните на метод main() для нашего класса в качестве резюме:

  • Данные обучения (входные и известные выходные данные) представлены в двух массивах.
  • Объект нейронной сети создается с двумя входами, тремя узлами в скрытом слое и одним узлом в выходном слое.
  • Прямое распространение, вычисление ошибок и обратное распространение выполняются 10 000 раз.

Наконец, давайте попробуем нашу нейронную сеть. После 10 000 итераций наша нейронная сеть жива и работает с приемлемой производительностью. На рис. 14 показано, как уменьшается частота ошибок. По оси X отложен номер итерации (от 0 до 10 000), а по оси Y — среднеквадратическая ошибка, рассчитанная в строках 18 и 23 метода main(), показанного на рис. 13.

Неплохо для ~100 строк кода (вы можете скачать полный исходный код из моего GitHub-репозитория). Однако мы могли бы сделать то же самое с ~10 строками кода, используя библиотеку. Одной из таких библиотек является Eclipse Deeplearning4j, распределенная библиотека глубокого обучения с открытым исходным кодом, написанная для Java. Мы можем использовать библиотеку и решать более сложные задачи, например, обучить нейронную сеть классификации изображений. Входные данные увеличатся, набор обучающих данных будет намного более значительным (чем наши четыре строки для XOR), и нам потребуется более одного скрытого слоя. Но это уже другая история. Спасибо за чтение. Не стесняйтесь оставлять свои отзывы и отзывы ниже.

использованная литература

Хотите узнать больше о деталях? Просмотрите здесь производную сигмовидной функции; просмотрите здесь цепное правило в исчислении; просмотрите здесь определение градиентного потомка; а здесь подробное описание математики обратного распространения.