Реализация базовой искусственной нейронной сети с использованием логистического регрессионного анализа

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

Наиболее популярным и широко используемым алгоритмом обучения, используемым для НС, является логистическая регрессия, которая решает проблемы классификации (ХА? Регрессия для классификации??? Да, название этого алгоритма сбивает с толку, но это название было дано по историческим причинам). Анализ линейной регрессии оценивает коэффициенты линейного уравнения, включая прогнозирование значения зависимой переменной с использованием независимых переменных.

В этой статье шаг за шагом будет показано построение базовой искусственной нейронной сети. Давайте начнем с самого базового уровня, параметров всего одного узла во всей NN. Как и в человеческом мозгу, активация необходима, чтобы позволить нейронам устанавливать связи. Чтобы имитировать это в NN, необходима функция активации, и наиболее распространенным типом является функция активации Sigmoid, которая определяется как:

Это реализовано в Python таким образом, что x может быть либо одним значением, либо массивом значений. Это легко реализовать с помощью встроенных функций Numpy:

Используемая здесь модель логистической регрессии — это модель, описанная Этемом Алпайдином в его книге Введение в машинное обучение, третье издание:

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

Теперь модель для одного персептрона с двумя входными переменными становится следующей:

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

Чтобы расширить матрицу X, добавив входные параметры смещения, записывается функция add_bias:

Обратите внимание, что до сих пор рассматривались только выходы одного узла, но НС строятся из слоев этих узлов. Эти слои состоят из комбинации одного или нескольких узлов Sigmoid. Используя несколько узлов на выходном слое, можно классифицировать несколько классов вместо использования только бинарных классификаций с использованием одного узла.

Каждому из узлов Sigmoid потребуется набор весов на основе их входных данных. Теперь, когда будет один слой, веса будут представлять собой матрицу формы (n, m+1), где n — это node, а m – количество входных данных плюс узел смещения. Эта матрица будет называться Θ, где каждая строка содержит веса для узла Sigmoid.

Однослойная сеть, определяющая Θ⁰, выглядит так:

В приведенном выше примере матрица Θ⁰ будет иметь размер 3x4. В более сложной сети матрица Θ индексируется следующим образом:

С помощью функции one_layer_init матрица Θ⁰ создается с учетом входного и выходного размера. Важно случайным образом инициализировать веса, потому что для нахождения оптимальных значений будут использоваться частные производные, и поэтому каждый узел должен иметь другую производную:

Теперь пришло время реализовать функции, вычисляющие активации для одного слоя. Поэтому написаны функции compute_layer и one_layer_output. Функция compute_layer принимает матрицы Aʲ и Θʲ и возвращает следующую матрицу A:

one_layer_output принимает матрицу X, состоящую из обучающих выборок, и Θ⁰, и возвращает матрицу выходных данных:

Градиентный спуск

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

Реализация этого на Python выглядит так:

Дельта-правило

Чтобы минимизировать функцию стоимости, необходимо взять частные производные каждого параметра. Сначала определяется δ, который содержит частные производные функции стоимости относительно входных узлов. Это определено для каждого узла i в каждом слое j:

Для выходного слоя δ определяется как (j — последний слой):

Для этого записывается функция output_delta:

После вычисления членов δ можно вычислить производные. Обновление веса определяется следующим уравнением:

Когда все полученные значения суммируются по всем M обучающим выборкам, получается общий градиент функции стоимости для всех параметров в одном слое, также известный как Пакетный градиентный спуск. Фактическое обновление веса тогда просто равно стандартному методу градиентного спуска:

Реализация этого для обновления веса одного слоя дает:

Комбинируя все эти дополнительные функции, можно обучить однослойную сеть. Учитывая набор обучающих данных, выходные данные будут просто повторно вычисляться для каждого обучающего входа. Затем на основе результатов обучения будут вычислены соответствующие δ, после чего, наконец, веса будут обновлены. Чем больше итераций, тем лучше результат и, следовательно, меньше ошибка:

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