1.17. Модели нейронных сетей (контролируемые)

Предупреждение

Данная реализация не предназначена для крупномасштабных приложений. В частности, scikit-learn не предлагает поддержки GPU. Более быстрые реализации на базе GPU, а также фреймворки, обеспечивающие гораздо большую гибкость при построении архитектур глубокого обучения, см. в Related Projects.

1.17.1. Многослойный перцептрон

Многослойный перцептрон (Multi-layer Perceptron - MLP) - это алгоритм контролируемого обучения, который обучает функцию \(f(\cdot): R^m \rightarrow R^o\) путем обучения на наборе данных, где \(m\) - количество размерностей для входа, а \(o\) - количество размерностей для выхода. Учитывая набор признаков \(X = {x_1, x_2, ..., x_m}\) и цель \(y\), он может выучить аппроксиматор нелинейной функции для классификации или регрессии. Она отличается от логистической регрессии тем, что между входным и выходным слоем может быть один или несколько нелинейных слоев, называемых скрытыми слоями. На рисунке 1 показан MLP с одним скрытым слоем и скалярным выходом.

../_images/multilayerperceptron_network.png

Figure 1 : One hidden layer MLP.

Самый левый слой, известный как входной, состоит из набора нейронов \(\{x_i | x_1, x_2, ..., x_m\}\), представляющих входные признаки. Каждый нейрон в скрытом слое преобразует значения из предыдущего слоя с помощью взвешенного линейного сложения \(w_1x_1 + w_2x_2 + ... + w_mx_m\), за которым следует нелинейная функция активации \(g(\cdot):R \rightarrow R\) - подобно гиперболической функции tan. Выходной слой получает значения из последнего скрытого слоя и преобразует их в выходные значения.

Модуль содержит публичные атрибуты coefs_ и intercepts_. coefs_ - это список матриц весов, где матрица весов с индексом \(i\) представляет собой веса между слоем \(i\) и слоем \(i+1\). intercepts_ - список векторов смещения, где вектор с индексом \(i\) представляет значения смещения, добавленные к слою \(i+1\).

Преимуществами многослойного перцептрона являются:

  • Возможность обучения нелинейным моделям.

  • Возможность обучения моделей в реальном времени (on-line обучение) с помощью partial_fit.

К недостаткам многослойного перцептрона (MLP) относятся:

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

  • MLP требует настройки ряда гиперпараметров, таких как количество скрытых нейронов, слоев и итераций.

  • MLP чувствительна к масштабированию признаков.

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

1.17.2. Классификация

Класс MLPClassifier реализует алгоритм многослойного перцептрона (MLP), который обучается по методу Метод обратного распространения ошибки (Backpropagation).

MLP обучается на двух массивах: массиве X размером (n_samples, n_features), который содержит обучающие выборки, представленные в виде векторов признаков с плавающей точкой, и массиве y размером (n_samples,), который содержит целевые значения (метки классов) для обучающих выборок:

>>> from sklearn.neural_network import MLPClassifier
>>> X = [[0., 0.], [1., 1.]]
>>> y = [0, 1]
>>> clf = MLPClassifier(solver='lbfgs', alpha=1e-5,
...                     hidden_layer_sizes=(5, 2), random_state=1)
...
>>> clf.fit(X, y)
MLPClassifier(alpha=1e-05, hidden_layer_sizes=(5, 2), random_state=1,
              solver='lbfgs')

После обучении модель может предсказывать метки для новых образцов:

>>> clf.predict([[2., 2.], [-1., -2.]])
array([1, 0])

MLP может обучать нелинейную модель к обучающим данным. clf.coefs_ содержит весовые матрицы, определяющие параметры модели:

>>> [coef.shape for coef in clf.coefs_]
[(2, 5), (5, 2), (2, 1)]

В настоящее время MLPClassifier поддерживает только функцию потерь Cross-Entropy, которая позволяет оценить вероятность, выполнив метод predict_proba.

MLP обучается с помощью обратного распространения. Точнее, он обучается с помощью некоторой формы градиентного спуска, а градиенты вычисляются с помощью Backpropagation. Для классификации он минимизирует функцию потерь Cross-Entropy, давая вектор оценок вероятности \(P(y|x)\) на выборку \(x\):

>>> clf.predict_proba([[2., 2.], [1., 2.]])
array([[1.967...e-04, 9.998...-01],
       [1.967...e-04, 9.998...-01]])

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

Кроме того, модель поддерживает классификацию по нескольким меткам, в которой образец может принадлежать более чем одному классу. Для каждого класса исходный результат проходит через логистическую функцию. Значения, большие или равные 0.5, округляются до 1, в противном случае - до 0. Для предсказанного вывода выборки индексы, в которых значение равно 1, представляют собой назначенные классы этой выборки:

>>> X = [[0., 0.], [1., 1.]]
>>> y = [[0, 1], [1, 1]]
>>> clf = MLPClassifier(solver='lbfgs', alpha=1e-5,
...                     hidden_layer_sizes=(15,), random_state=1)
...
>>> clf.fit(X, y)
MLPClassifier(alpha=1e-05, hidden_layer_sizes=(15,), random_state=1,
              solver='lbfgs')
>>> clf.predict([[1., 2.]])
array([[1, 1]])
>>> clf.predict([[0., 0.]])
array([[0, 1]])

Более подробную информацию см. в примерах ниже и в строке документации MLPClassifier.fit.

1.17.3. Регрессия

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

MLPRegressor также поддерживает многовыходную регрессию, в которой выборка может иметь более одной цели.

1.17.4. Регуляризация

Как в MLPRegressor, так и в MLPClassifier используется параметр alpha для регуляризации (L2 regularization), который помогает избежать переобучения, штрафуя веса с большими величинами. Следующий график показывает изменение функции принятия решения в зависимости от значения параметра alpha.

../_images/sphx_glr_plot_mlp_alpha_001.png

Смотрите примеры ниже для получения дополнительной информации.

1.17.5. Алгоритмы

MLP обучается с помощью Стохастический градиентный спуск (Stochastic Gradient Descent), Adam, или L-BFGS. Стохастический градиентный спуск (SGD) обновляет параметры, используя градиент функции потерь относительно параметра, требующего адаптации, т.е.

\[w \leftarrow w - \eta (\alpha \frac{\partial R(w)}{\partial w} + \frac{\partial Loss}{\partial w})\]

где \(\eta\) - скорость обучения, которая управляет размером шага в поиске пространства параметров. \(Loss\) - функция потерь, используемая для сети.

Более подробную информацию можно найти в документации к SGD.

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

В SGD и Adam обучение поддерживается в режиме онлайн и в мини-пакетах.

L-BFGS - это алгоритм, который аппроксимирует матрицу Гессиана, представляющую собой частную производную функции второго порядка. Далее он аппроксимирует обратную матрицу Гессиана для выполнения обновления параметров. В реализации используется Scipy-версия L-BFGS.

Если выбран алгоритм ‘L-BFGS’, обучение не поддерживает ни онлайн, ни мини-пакетное обучение.

1.17.6. Сложность

Предположим, что есть \(n\) обучающих выборок, \(m\) признаков, \(k\) скрытых слоев, каждый из которых содержит \(h\) нейронов - для простоты, и \(o\) выходных нейронов. Временная сложность обратного распространения равна \(O(n\cdot m \cdot h^k \cdot o \cdot i)\), где \(i\) - количество итераций. Поскольку обратное распространение имеет высокую временную сложность, рекомендуется начинать с меньшего числа скрытых нейронов и нескольких скрытых слоев для обучения.

1.17.7. Математическая формулировка

Дан набор обучающих примеров \((x_1, y_1), (x_2, y_2), \ldots, (x_n, y_n)\) где \(x_i \in \mathbf{R}^n\) и \(y_i \in \{0, 1\}\), один скрытый слой, один скрытый нейрон, MLP изучает функцию \(f(x) = W_2 g(W_1^T x + b_1) + b_2\) где \(W_1 \in \mathbf{R}^m\) и \(W_2, b_1, b_2 \in \mathbf{R}\) параметры модели. \(W_1, W_2\) представляют веса входного и скрытого слоев соответственно; и \(b_1, b_2\) представляют смещение, добавленное к скрытому слою и выходному слою соответственно. \(g(\cdot) : R \rightarrow R\) - это функция активации, установленная по умолчанию как гиперболический тангенс. Это дано как,

\[g(z)= \frac{e^z-e^{-z}}{e^z+e^{-z}}\]

Для бинарной классификации \(f(x)\) проходит через логистическую функцию \(g(z)=1/(1+e^{-z})\) для получения выходных значений между нулем и единицей. Порог, установленный на 0.5, отнесет выборки с выходом, большим или равным 0.5, к положительному классу, а остальные - к отрицательному.

Если классов больше двух, то \(f(x)\) сам по себе будет вектором размера (n_classes,). Вместо того чтобы проходить через логистическую функцию, он проходит через функцию softmax, которая записывается как,

\[\text{softmax}(z)_i = \frac{\exp(z_i)}{\sum_{l=1}^k\exp(z_l)}\]

где \(z_i\) представляет \(i\)-й элемент входа в softmax, который соответствует классу \(i\), а \(K\) - количество классов. Результатом является вектор, содержащий вероятности того, что выборка \(x\) принадлежит каждому классу. Выходом является класс с наибольшей вероятностью.

В регрессии выход остается как \(f(x)\); поэтому функция активации выхода - это просто функция тождества.

MLP использует различные функции потерь в зависимости от типа задачи. Для классификации используется функция потерь Average Cross-Entropy, которая в двоичном случае имеет вид,

\[Loss(\hat{y},y,W) = -\dfrac{1}{n}\sum_{i=0}^n(y_i \ln {\hat{y_i}} + (1-y_i) \ln{(1-\hat{y_i})}) + \dfrac{\alpha}{2n} ||W||_2^2\]

где \(\alpha ||W||_2^2\) - L2-регуляризационный член (он же штраф), который наказывает сложные модели; и \(\alpha > 0\) - неотрицательный гиперпараметр, который управляет величиной штрафа.

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

\[Loss(\hat{y},y,W) = \frac{1}{2n}\sum_{i=0}^n||\hat{y}_i - y_i ||_2^2 + \frac{\alpha}{2n} ||W||_2^2\]

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

При градиентном спуске вычисляется градиент \(\nabla Loss_{W}\) потерь по отношению к весам и вычитается из \(W\). Более формально это выражается как,

\[W^{i+1} = W^i - \epsilon \nabla {Loss}_{W}^{i}\]

где \(i\) - шаг итерации, а \(\epsilon\) - скорость обучения со значением больше 0.

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

1.17.8. Советы по практическому использованию

  • Многослойный перцептрон чувствителен к масштабированию признаков, поэтому настоятельно рекомендуется масштабировать ваши данные. Например, масштабируйте каждый признак входного вектора X на [0, 1] или [-1, +1], или стандартизируйте его так, чтобы среднее значение было 0, а дисперсия - 1. Обратите внимание, что для получения значимых результатов необходимо применить такое же масштабирование к тестовому набору. Для стандартизации можно использовать StandardScaler.

    >>> from sklearn.preprocessing import StandardScaler  
    >>> scaler = StandardScaler()  
    >>> # Don't cheat - fit only on training data
    >>> scaler.fit(X_train)  
    >>> X_train = scaler.transform(X_train)  
    >>> # apply same transformation to test data
    >>> X_test = scaler.transform(X_test)  
    

    Альтернативным и рекомендуемым подходом является использование StandardScaler в Pipeline

  • Для поиска разумного параметра регуляризации \(\alpha\) лучше всего использовать GridSearchCV, обычно в диапазоне 10.0 ** -np.arange(1, 7).

  • Эмпирически мы заметили, что L-BFGS сходится быстрее и имеет лучшие решения на небольших наборах данных. Однако для относительно больших наборов данных Adam очень устойчив. Обычно он быстро сходится и дает довольно хорошую производительность. С другой стороны, SGD с импульсом или импульсом Нестерова может работать лучше, чем эти два алгоритма, если правильно настроить скорость обучения.

1.17.9. Больше контроля с помощью warm_start

Если вы хотите получить больше контроля над критериями остановки или скоростью обучения в SGD, или хотите провести дополнительный мониторинг, использование warm_start=True и max_iter=1 и самостоятельных итераций может быть полезным:

>>> X = [[0., 0.], [1., 1.]]
>>> y = [0, 1]
>>> clf = MLPClassifier(hidden_layer_sizes=(15,), random_state=1, max_iter=1, warm_start=True)
>>> for i in range(10):
...     clf.fit(X, y)
...     # additional monitoring / inspection
MLPClassifier(...