Нейросетевые классификаторы¶

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

  • роста вычислительных возможностей (сети суперкомпьютеров, графические ускорители и облачные вычисления);

  • формирования огромных сетевых баз данных и эффективных зкстерриториальных технологий взаимодействия с ними;

  • разработки все более изощренных математических и программно-алгоритмических нейросетевых моделей.

Следует констатировать, что нейросетевые модели эффективно решают практически все задачи, которые обычно относят ML, но при этом следует иметь ввиду, что в зависимости от особенностей задачи ее размерности и.т. д. бывает целесообразно и более полезно использовать другие модели, которые менее ресурсоемки и результаты которых легко интерпретируются.Это в частности относится и к задачам классификации особенно тогда, когда они не требуют значительных информационно-вычислительных ресурсов и предпологают наличие внятных интерпритаций, получаемых решений. Чего трудно добиться, исходя из концепта 'черного ящика',на котором базируются нейросетевые модели. Но нейросетевые классификаторы занимают достойное место среди моделей ML, используемых для решения залач классификации. При этом часто здесь нет необходимости использовать всю совренную мощь нейросетевого моделирования. Эта мощь, требуюшая затрат больших ресурсов, используется в так называемым глубоком обучении DL (Deep learning). О нем мы будем говорить в соотвествующих разделах книги.А при рассмотрении нейросетевых классификаторов мы остановимся на базовых математических и алгоритмических основах давно известных нейросетевых моделей: перцептрона,многослойного перцептрона и сетей прямой передачи.На конкретных примеров покажем как они могут использоваться для решения задач классификации с python и R.

а.Базовые естественно-биологические и математические основания нейросетевых моделей.¶

Биологический нейрон и история возникновения искусственных нейронных сетей

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

Plot nn01

Рис 1 Структура биологического нейрона

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

  • дендриты, по которым принимаются импульсы

  • единственный аксон, по которому нейрон может передавать импульс.

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

Кора головного мозга человека содержит около 1011 нейронов. Каждый нейрон связан с $10^3–10^4$ другими нейронами. В целом мозг человека содержит приблизительно от $10^{14}$ до $10^{15}$ взаимосвязей. Первая математическая модель нейрона (базового элемента мозга) была создана в 1943 году, когда американский ученый Уоррен Маккаллок (McCullochW.) и его ученик У. Питтс (Pitts W.) сформулировали основные положения теории деятельности головного мозга.

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

В 1949 г. Д. Хебб (D. Hebb) высказал идеи о характере соединений нейронов мозга и их взаимодействии и описал правила обучения нейронной сети.

В 1957 г. Ф. Розенблатт (F. Rosenblatt) разработал принципы организации и функционирования собственной модели нейронной сети - персептрона,предложил вариант технической реализации первого в мире нейрокомпьютера Mark

В 1969 г. была опубликована книга М. Минского (М. Minsky) и С.Пейперта (S. Papert) «Персептроны», в которой доказывается принципиальная ограниченность возможностей персептронов, что послужило причиной угасания интереса к искусственным нейронным сетям. В начале 80-х годов происходит возобновление интереса к искусственным нейронным сетям, как следствие накопления новых знаний о деятельности мозга, а также значительного прогресса в области микроэлектроники и компьютерной техники.

В 1982–1985 гг. Дж. Хопфилд (J. Hopfield) предложил семейство оптимизирующих нейронных сетей, моделирующих ассоциативную память.

1987 г. послужил началом широкомасштабного финансирования разработок в области искусственных нейронных сетей (ИНС) в США, Японии и Западной Европе. Начиная 1989 года, разработки и исследования в области ИНС ведутся практически всеми крупными фирмами. Нейросети превращаются в один из самых динамичных секторов рынка и уровень их развития становиться одним из важнейших конкурентных факторов, как для отдельных фирм, так и для стран в целом.

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

Искусственный нейрон

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

Искусственный нейрон в первом приближении имитирует свойства биологического нейрона. Здесь множество входных сигналов, обозначенных $x_1,x_2, … ,x_n$ поступает на искусственный нейрон. Эти входные сигналы, в совокупности обозначаемые вектором столбцом: $X = \left[ {\begin{array}{*{20}c} {x_1 } \\ {\begin{array}{*{20}c} {x_2 } \\ \begin{array}{l} ... \\ x_n \\ \end{array} \\ \end{array}} \\ \end{array}} \right]$ соответствуют сигналам,приходящим в синапсы биологического нейрона. Каждый синапс характеризуется величиной синапcической связи или ее весом $w_i$. Весовой вектор строка $W = \left[ {w_1 ,w_1 ,....w_n ,b} \right]$ умножается на соответствующий входной вектор столбец $\left[ \begin{array}{l} X \\ 1 \\ \end{array} \right]$ Веса - это аналог эффективности синапса. Вес связи является положительным для возбуждающей связи и отрицательным для тормозящей связи нейрона. Взвешенные весами связей, входные сигналы поступают на блок суммации (по своей сути являющийся аналогом тела клетки в биологическом нейроне). Таким образом, нейрон реализует следующее выражение, определяющее уровень его возбуждения $S$:

$$S = \left[ {W,b} \right] \cdot \left[ \begin{array}{l} X \\ 1 \\ \end{array} \right] = \sum\limits_{i = 1}^n {x_i \cdot w_i } + b\;\;\;(1)$$

где: $b$ - порог возбуждения (смещение) нейрона.Затем над уровнем возбуждения S производится необходимое линейное или нелинейное преобразование:

$$Y=F(S)\;\;\;(2)$$

Эта функция называется активационной. Следовательно, искусственный нейрон можно представить следующим образом (рис.2) , а примеры функций активации приведены на рис.3.

Plot nn02

Рис. 2 Искусственный нейрон

Plot nn03

Рис.3. Основные виды функций активации

Приведенное формальное представление искусственного нейрона (ИН) с пороговой функцией активации представляет собой модель МакКаллока–Питтса, которую мы упоминали выше. Она предстадставляет собой линейный бинарный классификатор.

В общем виде задача классификации можно с сформулировать следующим образом:

Имеется пространство объектов $X$ и конечное множество имён классов $Y$.Существует целевая зависимость $y^* :X \to Y$ значения которой известны только на объектах обучающей выборки $X^l = \left( {x_i ,y_i } \right)_i^l ,y_i = y^* \left( {x_i } \right)$.Требуется построить алгоритм классификации $a: X → Y$ , аппроксимирующий целевую зависимость $y^*(x)$ на всём множестве $X$

Возникает вопрос может ли ИН решить задачу классификации (т.е эквивалентно ли выражения (1) и (2) отображению $a: X → Y$)? Если да, то при каких условиях, а если нет то почему.Для того чтобы ответить на данный вопрос нужно, прежде всего, иметь процедуру обучения то есть получения синаптических весов при различных функциях активации.

Методы обучения синаптических весов нейрона

Персептрон Розенблатта. В 1957 году Розенблатт предложил эвристический алгоритм обучения нейрона. Рассмотрим этот алгоритм. Как признаки, так и ответы будем пока полагать бинарными. Перед началом обучения вектор весов некоторым способом инициализируется, например, заполняется нулевыми или случайными значениями. Затем обучающие объекты $x_i$ по очереди подаются на вход модели МакКаллока–Питтса, и выданные ответы сравниваются с правильными.Если ответ $a(x_i)$ (т.е результат реализации функций (1) и (2) для ИН) совпадает с $y_i$ , то вектор весов не изменяется. Если $a(x_i) = 0$ и $y_i = 1$, то вектор весов $w$ увеличивается. Увеличивать имеет смысл только те веса $w_j$ , которые соответствуют ненулевым компонентам $x^j_i$ (здесь верхний индекс обозначает j компонету i-го вектора входных данных) , так как изменение других компонент не повлияет на результат. Поэтому можно положить:$w: = w + \eta x_i$ , где $\eta$ некоторая положительная константа, называемая темпом обучения (learning rate).Если $a(x_i) = 1$ и $y_i = 0$, то вектор весов $w$ уменьшается:$w: = w - \eta x_i$.Поскольку все величины бинарные, эти и случаи легко объединить в одну формулу:

$$w: = w - \eta \left( {a(x_i ) - y_i } \right)x_i\;\;\;(3)$$

Обучающие объекты проходят через это правило многократно, до тех пор, пока веса изменяются, см. Алгоритм 1.

Алгоритм 1. Обучение персептрона Розенблатта

Вход:

  • $X^l$ обучающая выборка;

  • $\eta$ темп обучения.

Выход:

  • синаптические веса $w_0,w_1, . . . ,w_n$;

  • 1: инициализировать веса $w_j$ ;

  • 2: повторять

  • 3: для всех $i = 1, . . . , l$

  • 4: $w: = w - \eta \left( {a(x_i ) - y_i } \right)x_i$

  • 5: пока веса $w$ изменяются;

Правило Хэбба. Иногда удобнее полагать, что классы помечены числами −1 и 1,а нейрон выдаёт знак скалярного произведения:

$$a\left( x \right) = sign(\left\langle {w,x} \right\rangle )$$

Тогда несовпадение знаков $\left\langle {w ,x_i } \right\rangle$ и $y_i$ означает, что нейрон ошибается на объекте $x_i$. При этом выражение (3) преобразуется в следующее правило модификации весов:

если $\left\langle {w,x_i } \right\rangle y_i < 0$, то $w: = w + \eta x_i y_i\;\;\;\;(4)$

Это правило называется правилом Хэбба. Соответственно, в Алгоритме 1 заменяется шаг 4.Для правила Хэбба была сформулирована и доказана теорема сходимости. Она справедлива не только для бинарных, но и для произвольных действительных признаков.

Теорема (Новиков, 1962). Пусть $X = \Re ^{n + 1}$, $Y = {−1, 1}$, и выборка $X^l$ линейно разделима существует вектор ${\tilde w}$ и положительное число $\delta$ такие, что $\left\langle {\tilde w,x_i } \right\rangle y_i > \delta$ для всех $i = 1, . . . , l$. Тогда Алгоритм 1 сходится за конечное число шагов к вектору весов, разделяющему обучающие объекты без ошибок, из любого начального положения $w_0$, при любом положительном $\eta$, независимо от порядка предъявления объектов. Если $w_0 = 0$, то достаточное число исправлений вектора весов не превосходит:

$t_{\max } = \left( {\frac{D}{\delta }} \right)^2$ , где $D = \mathop {\max }\limits_{x \in X^l } \left\| x \right\|$

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

Рассмотренный выше алгоритм обучения носит эвристический характер и не использует в явном виде активационной функции, но предпологает использование пороговой активационной функции (модель МакКаллока–Питтса). Ввидение в модель ИН других особенно нелинейных активационных функций имеет принципиально важное значение для формирования ансамблей ИН (искусственных нейросетей) и обеспечения их прогностических возможностей.Наиболее часто на практике применяется сигмоидальная (логистическая) функция вида:

$$Y = \frac{1}{{1 + e^{ - \beta S} }}\;\;\;(5)$$

Эта функция позволяет работать как со слабыми уровнями возбуждения (значения около 0), так и с большими уровнями возбуждения нейрона. При сильных уровнях сигнала происходит насыщение активационной функции, и таким образом, нейрон функционирует в широком диапазоне входных сигналов. Коэффициент β определяет крутизну сигмоида. Кроме того из теории известно, что ИН с сигмоидной функцией активации вычисляет вероятность принадлежности объекта x классу +1.

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

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

Метод стохастического градиента. Исходя из принципа минимизации эмпирического риска задача настройки синаптических весов может быть сведена к поиску вектора $w$, доставляющего минимум функционалу качества:

$$Q\left( w \right) = \sum\limits_{i = 1}^l {\Psi \left( {a\left( {x{}_i} \right),y_i } \right)} \to \mathop {\min }\limits_w\;\;\;(6)$$

Где $\Psi \left( {a,y} \right)$ )-заданная функция потерь, характеризующая величину ошибки ответа $a$ при правильном ответе $y$. Применим для минимизации $Q\left( w \right)$ метод градиентного спуска. Запишем правило изменения вектора весов на каждой итерации

$$w: = w - \eta \frac{{\partial Q}}{{\partial w}}$$

где $\eta > 0$ - величина шага в направлении антиградиента. Предполагая, что функция потерь $\Psi$ и функция активации $F$ дифференцируемы, распишем градиент:

$$w: = w - \eta \sum\limits_{i = 1}^l {\Psi '\left( {a\left( {x_i } \right),y_i } \right)} \cdot F'\left( {\left\langle {w,x_i } \right\rangle } \right) \cdot x_i\;\;\;(7)$$

Здесь каждый обучающий объект вносит свой аддитивный вклад в изменение вектора w, но вектор w изменяется только после предъявления всех $l$ объектов. Можно делать и по-другому - как и в персептроне Розенблатта, брать объекты по одному, и для каждого обновлять вектор весов. Этот метод называется стохастическим градиентом (stochastic gradient, $SG$). Объекты перебираются в случайном порядке, для каждого объекта $x_i$ делается градиентный шаг и сразу обновляется вектор весов:

$$w: = w - \eta \Psi '_a \left( {a\left( {x_i } \right),y_i } \right) \cdot F'\left( {\left\langle {w,x_i } \right\rangle } \right) \cdot x_i$$

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

Алгоритм 2. Обучение персептрона методом стохастического градиента

Вход:

  • $X^l$ обучающая выборка;

  • $\eta$ темп обучения.

Выход:

  • синаптические веса $w_0,w_1, . . . ,w_n$;

  • 1: инициализировать веса: $w_i : = {\rm random}\left( {{\rm - }\frac{{\rm 1}}{{{\rm 2n}}},\frac{1}{{2n}}} \right)$;

  • 2: инициализировать текущую оценку функционала:$Q: = \sum\limits_{i = 1}^l {\Psi \left( {a\left( {x_i } \right),y_i } \right)}$ ;

  • 3: повторять

  • 4: выбрать объект $x_i$ из $X^l$ случайным образом;

  • 5: вычислить выходное значение алгоритма $a(x_i)$ и ошибку: $\varepsilon _i : = \Psi \left( {a\left( {x_i } \right),y_i } \right)$;

  • 6: сделать шаг градиентного спуска: $w: = w - \eta \Psi '\left( {a\left( {x_i } \right),y_i } \right) \cdot F'\left( {\left\langle {w,x_i } \right\rangle } \right)x_i$ ;

  • 7: оценить значение функционала: $Q: = \frac{{l - 1}}{l}Q + \frac{1}{l}\varepsilon _i^2$

  • 8: пока значение $Q$ не стабилизируется;

Если все признаки вещественны: $X = \Re ^n$ , функция потерь квадратична: $\Psi \left( {a,y} \right) = \left( {a - y} \right)^2$ , функция активации линейна: $F(z) = z$. Тогда правило обновления весов в методе стохастического градиента в точности совпадает с правилом Розенблатта (3):

$$w: = w - \eta \left( {a(x_i ) - y_i } \right)x_i\;\;\;(6)$$

Это правило обучения было предложено Видроу и Хоффом в 1960 году и называется дельта-правилом (delta-rule), а сам линейный нейрон - адаптивным линейным элементом или ADALINE.

В Алгоритме 2 показана реализация метода $SG$ при произвольных функциях $\Psi(a, y)$ и $F(z)$. При этом инициализация весов и критерий останова не более чем эвристики.Преимущества метода $SG$ в том, что он легко реализуется, легко обобщается на нейронные сети более сложных архитектур, позволяет настраивать сети на выборках сколь угодно больших объёмов (за счёт того, что случайной подвыборки может оказаться достаточно для обучения). Метод стохастического градиента считает- ся классическим инструментом настройки нейронных сетей.Недостаток $SG$ в том, что сходимость в общем случае не гарантируется.На практике сходимость определяют методом проб и ошибок. Существует довольно обширный набор эвристик и рекомендаций, способствующих улучшению сходимости

Общий вывод относительно одиночного ИН как классификатора следующий: Отдельно взятый ИН вида (рис.2) позволяет реализовать только линейный классификатор или линейную регрессию. Теоретически вычислительные ограничения одиночного ИН (персептрона) были доказаны Минским и Пайпертом в их знаменитой книге 'Персептроны'. Решение этой проблемы состоит в построении многослойных нейронных сетей, состоящих из огромного количества связанных нейронов и напоминающих естественные нейронные сети.

Многослойные нейронные сети.

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

Plot nn04

Рис. 4 Простейшая однослойная нейронная сеть

Отметим, что вершины-круги слева служат лишь для распределения входных сигналов. Они не выполняют каких-либо вычислений и, поэтому, не будут считаться слоем. По этой причине они обозначены кругами, чтобы отличать их от вычисляющих нейронов, обозначенных квадратами. Каждый элемент из множества входов $X = \left[ {\begin{array}{*{20}c} {x_1 } \\ {x_2 } \\ {x_n } \\ \end{array}} \right]$ отдельным весом соединен с каждым искусственным нейроном. А каждый нейрон выдает взвешенную сумму входов в сеть. В искусственных и биологических сетях многие соединения могут отсутствовать, все соединения показаны в целях общности. Могут иметь место также соединения между выходами и входами элементов в слое. Удобно считать веса элементами матрицы $W = \left[ {\begin{array}{*{20}c} {w_{11} } & {w_{12} } & {w_{1n} } \\ {w_{21} } & {w_{22} } & {w_{2n} } \\ {w_{m1} } & {w_{m2} } & {w_{mn} } \\ \end{array}} \right]$ Матрица имеет $m$ строк и $n$ столбцов, где $n$ – число входов, а $m$ – число нейронов. Например, $w_{23}$ – это вес, связывающий третий вход со вторым нейроном. Таким образом, вычисление выходного вектора столбца $Y = \left[ {\begin{array}{*{20}c} {y_1 } \\ {y_2 } \\ {y_m } \\ \end{array}} \right]$ , компонентами которого являются выходы $y_i$ нейронов, сводится к матричному уравнению:

$Y = WX + b$ , где $b = \left[ {\begin{array}{*{20}c} {b_1 } \\ {b_2 } \\ {b_m } \\ \end{array}} \right]$ вектор столбец смещений

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

Plot nn05

Рис. 5.Пример многослойной нейронной сети

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

У сетей, рассмотренных до сих пор, не было обратных связей, т. е. соединений, идущих от выходов некоторого слоя к входам этого же слоя или предшествующих слоев. Этот специальный класс сетей, называемых сетями без обратных связей или сетями прямого распространения (Feed Forward FFNN), представляет большой интерес и широко используется.Именно этот класс нейросетей мы будем рассматривать и использовать в данном разделе для решения задач классификации. Рассмотрение других более сложных архитектур нейросетей отнем к другопу разделу посвященному DL.

Вычислительные возможности многослойных нейронных сетей.

Возникает вопрос: любую ли функцию можно представить (хотя бы приближённо) с помощью многослойной нейронной сети? Следующие факты позволяют ответить на этот вопрос утвердительно.

  1. Любая булева функция представима в виде двухслойной сети. Это тривиальное следствие нейронной представимости функций И, ИЛИ, НЕ и представимости произвольной булевой функции в виде дизъюнктивной нормальной формы

  2. Из простых геометрических соображений вытекает, что двухслойная сеть с пороговыми функциями активации позволяет выделить произвольный выпуклый многогранник в n-мерном пространстве признаков. Трёхслойная сеть позволяет вычислить любую конечную линейную комбинацию характеристических функций выпуклых многогранников, следовательно, аппроксимировать любые области с непрерывной границей, включая неодносвязные, а также аппроксимировать любые непрерывные функции.

  3. Достижения функционального анализа, выраженные в постановке и доказательстве ряда фундаментальных теорем:

  • Теорема (Колмогоров, 1957). Любая непрерывная функция n аргументов на единичном кубе $[0, 1]^n$ представима в виде суперпозиции непрерывных функций одного аргумента и операции сложения

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

  • Теорема Стоуна утверждающая, что любую непрерывную функцию на произвольном компакте X можно приблизить не только многочленом от исходных переменных, но и многочленом от любого конечного набора функций F,разделяющих точки

  • Догазательство (Горбань, 1998) ещё более общего утверждения,что вместо многочленов (суперпозиции операций сложения и умножения) можно пользоваться суперпозициями сложения и какой-нибудь (практически произвольной) непрерывной нелинейной функции одного аргумента

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

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

Обучение многослойных нейросетей прямого распространения.

Многослойные FF сети также, как ИН, можно настраивать градиентными методами, несмотря на огромное количество весовых коэффициентов. В середине 80-х одновременно несколькими исследователями был предложен эффективный способ вычисления градиента, при котором каждый градиентный шаг выполняется за число операций, лишь немногим большее, чем при обычном вычислении сети на одном объекте.Этого удается добиться благодаря аналитическому дифференцированию суперпозиции с сохранением необходимых промежуточных величин. Метод получил название обратного распространения ошибок (error back-propagation).

Метод обратного распространения ошибок.

Рассмотрим многослойную сеть, в который каждый нейрон предыдущего слоя связан со всеми нейронами последующего слоя, Рис. 6. Для большей общности положим $X = R^n$, $Y = R^M$.

Plot nn06

Рис. 6. Многослойная FF сеть с одним скрытым слоем

Введём следующие обозначения. Пусть выходной слой состоит из $M$ нейронов с функциями активации $\sigma _m$ и выходами $a_m$, $m = 1, . . . ,M$. Перед ним находится скрытый слой из $H$ нейронов с функциями активации $\sigma _h$ и выходами $u_h$, $h = 1, . . . ,H$.Веса синаптических связей между $h$-м нейроном скрытого слоя и m-м нейроном выходного слоя будем обозначать через $w_{hm}$. Перед этим слоем может находиться либо распределительный слой, либо ещё один скрытый слой с выходами $v_j$ , $j = 1, . . . , J$ и синаптическими весами $w_{jh}$. В общем случае число слоёв может быть произволь- ным. Если сеть двухслойная, то $v_j$ есть просто $j$-й признак: $v^j \equiv f_j \left( x \right) \equiv x^j$ ,и $J = n$. Обозначим через $w$ вектор всех синаптических весов сети. Выходные значения сети на объекте $x_i$ вычисляются как суперпозиция:

$a^m \left( {x_i } \right) = \sigma _m \left( {\sum\limits_{h = 0}^H {w_{hm} u^h \left( {x_i } \right)} } \right)\;\;\;$;$\;\;\;u^h \left( {x_i } \right) = \sigma _h \left( {\sum\limits_{j = 0}^J {w_{jh} v^j \left( {x_i } \right)} } \right)\;\;\;(7)$

Запишем функционал среднеквадратичной ошибки для отдельного объекта $x_i$:

$$Q\left( w \right) = \frac{1}{2}\sum\limits_{m = 1}^M {\left( {a^m \left( {x{}_i} \right) - y_i^m } \right)} ^2\;\;\;(8)$$

В дальнейшем нам понадобятся частные производные Q по выходам нейронов.Выпишем их сначала для выходного слоя:

$\frac{{\partial Q\left( w \right)}}{{\partial a^m }} = a^m \left( {x_i } \right) - y_i^m = \varepsilon _i^m$

Оказывается, частная производная $Q$ по $a_m$ равна величине ошибки $\varepsilon _i^m$ на объекте $x_i$.

Теперь выпишем частные производные по выходам скрытого слоя:

$\frac{{\partial Q\left( w \right)}}{{\partial u^h }} = \sum\limits_{m = 1}^M {\left( {a^m \left( {x_i } \right) - y_i^m } \right)} \cdot \sigma '_m w_{hm} = \sum\limits_{m = 1}^M {\varepsilon _i^m } \sigma '_m w_{hm} = \varepsilon _i^h$

Эту величину, по аналогии с , будем называть ошибкой сети на скрытом слое и обозначать через $\varepsilon _i^h$ . Через $\sigma '_m$ обозначена производная функции активации, вычисленная при том же значении аргумента, что и в (7). Если используется сигмоидная функция активации, то для эффективного вычисления производной можно воспользоваться формулой $\sigma '_m = \sigma _m (1 - \sigma _m )$.

Заметим, что $\varepsilon _i^h$ вычисляется по $\varepsilon _i^m$, если запустить сеть "задом наперёд", подав на выходы нейронов скрытого слоя значения $\varepsilon _i^m$ $\sigma '_m$, а результат $\varepsilon ^h$ получив на входе. При этом входной вектор скалярно умножается на вектор весов $w_{hm}$, находящихся справа от нейрона, а не слева, как при прямом вычислении (отсюда и название алгоритма - обратное распространение ошибок):

Plot nn07

Имея частные производные по $a_m$ и $u_h$, легко выписать градиент $Q$ по весам:

$$\frac{{\partial Q\left( w \right)}}{{\partial w_{hm} }} = \frac{{\partial Q\left( w \right)}}{{\partial a^m }}\frac{{\partial a^m }}{{\partial w_{hm} }} = \varepsilon _i^m \sigma '_m u^h ,\;\;m = 1,...,\;M,h = 0,...H\;\;\;(9)$$$$\frac{{\partial Q\left( w \right)}}{{\partial w_{jh} }} = \frac{{\partial Q\left( w \right)}}{{\partial u^h }}\frac{{\partial u^h }}{{\partial w_{jh} }} = \varepsilon _i^h \sigma '_h v^j ,\;\;h = 1,...,H,\;j = 0,...,J\;\;\;(10)$$

и так далее для каждого слоя. Если слоёв больше двух, то остальные частные производные вычисляются аналогично - обратным ходом по слоям сети справа налево.Теперь мы обладаем всем необходимым, чтобы полностью выписать алгоритм обратного распространения, см. Алгоритм 3.

Алгоритм 3. Обучение двухслойной сети методом back-propagation - обратного распространения ошибки

Вход:

$X^l = \left( {x_i ,y_i } \right)_{i = 1}^l$ - обучающая выборка, $x_i \in R^n ,y{}_i \in R^M$

$H$ - число нейронов в скрытом слое;

$\eta$ - темп обучения;

Выход:

синаптические веса $w_{jh}$, $w_{hm}$;

  • 1: инициализировать веса небольшими случайными значениями:

$w_{jh} = {\rm random}\left( {{\rm - }\frac{{\rm 1}}{{{\rm 2n}}},\frac{1}{{2n}}} \right)$

$w_{hm} = {\rm random}\left( {{\rm - }\frac{{\rm 1}}{{{\rm 2H}}},\frac{1}{{2H}}} \right)$

  • 2: повторять

  • 3: выбрать объект $x_i$ случайным образом;

  • 4: прямой ход

$u_i^h : = \sigma _h \left( {\sum\limits_{j = 0}^J {w_{jh} } v^j \left( {x_i } \right)} \right),\;\;h = 1,...,H$

$a_i^m : = \sigma _m \left( {\sum\limits_{h = 0}^H {w_{hm} } v^h \left( {x_i } \right)} \right),\;\;m = 1,...,M$

$\varepsilon _i^m : = a_i^m - y_i^m ,\;\;m = 1,....,M$

$Q_i : = \sum\limits_{m = 1}^M {\left( {\varepsilon _i^m } \right)^2 }$

  • 5: обратный ход:

$\varepsilon _i^h : = \sum\limits_{m = 1}^M {\varepsilon _I^m \sigma '_m w_{hm} } ,h = 1,....,H$

  • 6: градиентный шаг:

$w_{hm} : = w_{hm} - \eta \varepsilon _i^m \sigma '_m u^h ,h = 0,...,H,m = 1,...,M$

$w_{jh} : = w_{jh} - \eta \varepsilon _i^h \sigma '_h x^j ,j = 0,...,n,h = 1,...,H$

  • 7: $Q: = \frac{{l - 1}}{l}Q + \frac{1}{l}Q_i$

  • 8: пока $Q$ не стабилизируется

Достоинства метода обратного распространения.

  • Достаточно высокая эффективность. Прямой ход, обратный ход и вычисления градиента требуют порядка $O(Hn + HM)$ операций.

  • Через каждый нейрон проходит информация только о связных с ним нейронах.Поэтому back-propagation легко реализуется на вычислительных устройствах с параллельной архитектурой.

  • Высокая степень общности. Алгоритм легко записать для произвольного числа слоёв, произвольной размерности выходов и выходов, произвольной функции потерь и произвольных функций активации, возможно, различных у разных нейронов. Кроме того, back-propagation не накладывает никаких ограничений на используемый метод оптимизации. Его можно применять вместе с методом

скорейшего спуска, сопряженных градиентов, Ньютона-Рафсона и др.

Недостатки метода обратного распространения.

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

  • Процесс градиентного спуска склонен застревать в многочисленных локальных минимумах функционала $Q$.

  • Приходится заранее фиксировать число нейронов скрытого слоя $H$. В то же время, это критичный параметр сложности сети, от которого может существенно зависеть качество обучения и скорость сходимости.

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

  • Если применяются функции активации с горизонтальными асимптотами, типа сигмоидной или th, то сеть может попадать в состояние 'паралича'. Чем больше значения синаптических весов на входе нейрона, тем ближе значение производной σ′ к нулю, тем меньше изменение синаптических весов в соответствии с формулами (9)–(10). Если нейрон один раз попадает в такую 'мёртвую зону', то у него практически не остаётся шансов из неё выбраться. Парализоваться могут отдельные связи, нейроны, или вся сеть в целом.

Улучшение сходимости и качества градиентного обучения

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

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

Выбор функций активации. Сигмоидная функция $\sigma \left( z \right) = \left( {1 + e^{ - z} } \right)^{ - 1}$ часто применяется при решении задач классификации. Её преимущества - возможность оценить вероятность принадлежности объекта классу, эффективность вычисления производной, ограниченность выходного значения. Применение нечётных функций, таких как − $th\left( z \right) = 2\sigma \left( {2z} \right) - 1$, увеличивает скорость сходимости примерно в полтора раза. Для предотвращения эффекта паралича имеет смысл добавлять небольшой линейный член: $th\left( z \right) + \gamma z$. Можно использовать и другие медленно растущие функции

Выбор начального приближения. Из тех же соображений предотвращения паралича синаптические веса должны инициализироваться небольшими по модулю значениями. В Алгоритме 3 на шаге 1 веса инициализируются случайными значениями из отрезка $\left[ { - \frac{1}{{2k}},\frac{1}{{2k}}} \right]$ , где $k$ - число нейронов в том слое, из которого выходит данный синапс. В этом случае (и при условии, что все признаки нормализованы) значения скалярных произведений гарантированно попадают в 'рабочую зону' функций активации.

Существует и более тонкий способ формирования начального приближения.Идея заключается в том, чтобы сначала настроить нейроны первого слоя поотдельности, как $H$ однослойных персептронов. Затем поотдельности настраиваются нейроны второго слоя, которым на вход подаётся вектор выходных значений первого слоя. Чтобы сеть не получилась вырожденной, нейроны первого слоя должны быть существенно различными. Ещё лучше, если они будут хоть как-то приближать целевую зависимость, тогда второму слою останется только усреднить результаты первого слоя, сгладив ошибки некоторых нейронов. Добиться этого совсем несложно, если обучать нейроны первого слоя на различных случайных подвыборках, либо подавать им на вход различные случайные подмножества признаков. Отметим,что при формировании начального приближения не требуется особая точность на- стройки, поэтому отдельные нейроны можно обучать простейшими градиентными методами.

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

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

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

    1. Ещё одна эвристика состоит в том, чтобы чаще предъявлять те объекты,на которых была допущена ошибка. Для этого вероятность появления каждого объекта вычисляется в соответствии с величиной ошибки сети на данном объекте. Эту

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

    1. Другой вариант предыдущей эвристики отличается простотой реализации и заключается в том, чтобы после прямого хода (шага 4 в Алгоритме 3) сравнить величину ошибки на i-м объекте с некоторым порогом. Если ошибка окажется меньше

порога, вектор весов не модифицируется. Иначе выполняется обратный ход, вычисляется градиент и изменяются веса (шаги 5 и 6). Логика этой эвристики в точности та же, что у персептрона Розенблатта: если объект уже неплохо классифицируется, то менять веса не нужно. При этом увеличивается и скорость настройки.

Сокращение весов является частным случаем регуляризации некорректно поставленных задач по А. Н. Тихонову. Аналогичный приём применяется в линейном дискриминантном анализе и в линейной регрессии. Идея заключается в том, чтобы ограничить возможный рост абсолютных значений весов, добавив к минимизируемому функционалу $Q(w)$ специальное штрафное слагаемоеб что приводит к постоянному уменьшению весов. Отсюда название метода - сокращение весов (weights decay).

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

Недостаток метода в том, что параметр шрафа приходится подбирать в режиме скользящего контроля, что связано с большими затратами времени

Выбор величины шага.

  1. Известно, что градиентные методы сходятся при определённых условиях,если величину шага $\eta$ уменьшать с числом итераций $t$.Точнее, сходимость гарантируется при $\eta _t \to 0,\sum\limits_{t = 1}^\infty {\eta _t = \infty ,} \sum\limits_{t = 1}^\infty {\eta _t^2 < \infty }$ ,в частности можно положить $\eta _t = 1/t$.При настройке нейронных сетей дополнительные условия сходимости могут не выполняться, поэтому стратегию постепенного уменьшения шага следует воспринимать скорее как эвристическую рекомендацию/

  2. Метод скорейшего градиентного спуска приводит к выбору адаптивного шага $\eta$ исходя из решения одномерной задачи минимизации $Q\left( {w - \eta \frac{{\partial Q}}{{\partial w}}} \right) \to \min$ Во многих случаях эту задачу удаётся решить аналитически. В частности формулы вычисления адаптивного шага получены для метода обратного распространения ошибок.

Выбивание сети из локальных минимумов

Оно обязательно должно быть предусмотрено в любой хоть сколько-нибудь серьёзной реализации back-propagation. Один из простейших способов заключается в том, чтобы при каждой стабилизации функционала ошибки производить случайные модификации вектора весов в довольно большой окрестности текущего значения и запускать процесс градиентного спуска из новых точек. Этот способ называют потряхиванием коэффициентов (jog of weights).По сути дела, он является симбиозом градиентного метода и случайного локального поиска (stochastic local search).

Выбор критерия останова.

В Алгоритме 3 в качестве критерия останова используется условие стабилизации среднеквадратичной ошибки $Q$. Точное вычисле- ние этой величины потребовало бы пропускать через сеть все обучающие объекты после каждой итерации. Разумеется, это недопустимо из соображений эффективности. Вместо этого функционал Q оценивается приближённо, как экспоненциальное скользящее среднее ошибок $Q_i$, допущенных на объектах $x_i$, при этом больший вес получают объекты, предъявленные последними (шаг 7).

Ранний останов.

Слишком глубокая оптимизация также может привести к переобучению. Узкий глобальный минимум функционала $Q$ менее предпочтителен, чем более пологий и устойчивый локальный минимум. Для предотвращения попадания в такие 'расщелины' применяется техника раннего останова (early stopping). По ходу итераций вычисляется какой-нибудь внешний критерий, и если он начинает возрастать, процесс настройки прекращается

Выбор градиентного метода оптимизации.

К сожалению, градиентные методы первого порядка сходятся довольно медленно, и потому редко применяются на прак- тике. Ньютоновские методы второго порядка также непрактичны, но по другой причине - они требуют вычисления матрицы вторых производных функционала $Q(w)$,имеющей слишком большой размер. Метод сопряжённых градиентов этого не требует, однако применять его непосредственно нельзя, так как он существенно опирается на предположение неизменности функционал $Q(w)$, а в методе стохастического градиента функционал меняется при предъявлении каждого нового объекта. Необходимы специальные ухищрения, чтобы приспособить стандартные методы оптимизации для настройки нейронных сетей. Можно дать следующие рекомендации:

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

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

$$\eta _{jh} = \frac{\eta }{{\frac{{\partial ^2 Q}}{{\partial w_{jh}^2 }} + \mu }}$$

где $\eta$ остаётся глобальным параметром темпа обучения,$\mu$ -новый параметр, предотвращающий обнуление знаменателя, и, соответственно, неограниченное увеличение шага. Отношение $\eta /\mu$ есть темп обучения на ровных участках функционала $Q(w)$,где вторая производная обращается в нуль. Диагональный элемент матрицы вторых производных вычисляется с помощью специального варианта back-propagation

  1. Если обучающая выборка имеет небольшой объём, или если решается задача регрессии, то лучше использовать адаптированные варианты метода сопряжённых градиентов. Адаптация заключается в том, что объекты предъявляются не по одному, а пакетами (batch learning). Состав пакета может формироваться случайным образом. Для каждого пакета минимизируемый функционал остаётся фиксированным, что позволяет применить метод сопряжённых градиентов.

Оптимизация структуры сети

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

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

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

Выбор числа нейронов в скрытом слое

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

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

  2. Оптимизация $H$ по внешнему критерию, например, по критерию скользящего контроля или средней ошибки на независимой контрольной выборке $Q(X^k)$.Зависимость внешних критериев от параметра сложности, каким является $H$, обычно имеет характерный оптимум. Недостаток этого способа в том, что приходится много раз заново строить сеть при различных значениях параметра $H$, а в случае скользящего контроля - ещё и при различных разбиениях выборки на обучающую и контрольную части.

Динамическое добавление нейронов.

Сначала сеть обучается при заведомо недостаточной мощности среднего слоя $H ≪ l$. Обучение происходит до тех пор, пока ошибка не перестанет убывать. Тогда добавляется один или несколько новых нейронов. Веса новых связей инициализируются небольшими случайными числами, либо добавленные нейроны обучаются поотдельности как однослойные персептроны. Во втором случае можно рекомендовать обучать новый персептрон на случайной подвыборке, возможно, добавив в неё те объекты, на которых текущая сеть допустила наибольшие ошибки. Веса старых связей не меняются. Затем проводится настройка сети методом обратного распространения. После добавления новых нейронов ошибка, как правило, сначала резко возрастает, затем быстро сходится к меньшему значению. Интересно, что общее время обучения обычно оказывается лишь в 1.5–2 раза больше, чем если бы в сети сразу было нужное количество нейронов. Это означает, что информация, накопленная в сети, является полезной и не теряется при добавлении новых нейронов.При постепенном наращивании сети целесообразно наблюдать за динамикой какого-нибудь внешнего критерия. Прохождение значения $Q(X^k)$ через минимум является надёжным критерием останова, так как свидетельствует о переобученности,вызванной чрезмерным усложнением сети.

Удаление избыточных связей.

Можно использовать метод оптимального усечения сети (optimal brain damage, OBD) он удаляет те связи, к изменению которых функционал $Q$ наименее чувствителен. Уменьшение числа весов снижает склонность сети к переобучению

б. Программная реализация нейросетвых классификаторов.¶

Реализация нейросетевых классификаторов в python¶

Линейный перцептрон.

На python реализовано несколько нейросетевых классификаторов. Рассмотрем две реализации из модуля sklearn.cluster, начнем с простейшего классификатора на основе линейного перцептрона.Для его использования необходимо загрузить пакет from sklearn.linear_model import Perceptron и вызвать его:

Perceptron(penalty=None, alpha=0.0001, l1_ratio=0.15, fit_intercept=True, max_iter=1000, tol=0.001, shuffle=True, verbose=0, eta0=1.0, n_jobs=None, random_state=0, early_stopping=False, validation_fraction=0.1, n_iter_no_change=5, class_weight=None, warm_start=False)

Параметры :

penalty {'l2','l1','elasticnet'}, по умолчанию = нет -Штраф (он же термин регуляризации), который будет использоваться.

alpha с плавающей запятой, по умолчанию = 0.0001 -Константа, умножающая член регуляризации, если используется регуляризация.

l1_ratio с плавающей запятой, по умолчанию = 0.15 -Параметр смешивания Elastic Net с . соответствует штрафу L2, L1. Используется только если 0 <= l1_ratio <= 1l1_ratio=0 l1_ratio=1 penalty='elasticnet'

fit_intercept bool, по умолчанию = True -Следует ли оценивать перехват или нет. Если значение равно False, предполагается, что данные уже центрированы.

max_iter целое число, по умолчанию = 1000 - Максимальное количество проходов по обучающим данным (т. е. эпох). Это влияет только на поведение метода fit, а не на сам partial_fit метод.

tol float или None, по умолчанию=1e-3 - Критерий остановки. Если это не None, итерации остановятся, когда (loss > previous_loss - tol).

shuffle bool, по умолчанию = True - Следует ли перемешивать данные обучения после каждой эпохи.

verbose int, по умолчанию = 0 - Уровень многословности.

eta0 с плавающей запятой, по умолчанию = 1 -Константа, на которую умножаются обновления.

n_jobs int, по умолчанию = Нет - Количество процессоров, используемых для вычисления OVA (один против всех, для задач с несколькими классами). None означает 1, если только в joblib.parallel_backend контексте. -1 означает использование всех процессоров

random_state int, экземпляр RandomState или нет, по умолчанию = 0 -Используется для перемешивания обучающих данных, если shuffle установлено значение True. Передайте int для воспроизводимого вывода при нескольких вызовах функций

early_stopping bool, по умолчанию = False -Следует ли использовать раннюю остановку для прекращения обучения при проверке оценка не улучшается. Если установлено значение True, он автоматически отложит стратифицированную часть данных обучения для проверки и прекратит обучение, когда оценка проверки не улучшится как минимум на tol в течение n_iter_no_change последовательных эпох.

validation_fraction с плавающей запятой, по умолчанию = 0.1 -Доля обучающих данных, которые необходимо отложить в качестве набора проверки для ранней остановки. Должно быть от 0 до 1. Используется только в том случае, если Early_stopping имеет значение True.

n_iter_no_change целое, по умолчанию = 5 - Количество итераций без улучшения, требующих ожидания перед ранней остановкой.

class_weight dict, {class_label: вес} или “balanced”, по умолчанию = нет -Предустановлен для параметра подгонки class_weight. Веса, связанные с классами. Если он не указан, все классы должны иметь вес один.«Сбалансированный» режим использует значения y для автоматической корректировки весов, обратно пропорциональных частотам классов во входных данных как n_samples / (n_classes * np.bincount(y))

warm_start bool, по умолчанию = False - Если установлено значение True, повторно используйте решение предыдущего вызова в качестве инициализации, в противном случае просто сотрите предыдущее решение.

Атрибуты :

classes_ ndarray of shape (n_classes,) - Уникальные метки классов.

coef_ ndarray of shape (1, n_features) if n_classes == 2 else (n_classes, n_features) - Веса, присвоенные объектам.

intercept_ ndarray of shape (1,) if n_classes == 2 else (n_classes,)- Константы в функции решения.

loss_function_ concrete LossFunction - Функция, определяющая потери или разницу между выходными данными алгоритма и целевыми значениями.

n_features_in_ int - Количество функций, наблюдаемых во время подгонки .

feature_names_in_ ndarray of shape (n_features_in_,) - Названия функций, видимых во время подгонки . Определяется только в том случае, если X имена объектов состоят из строк.

n_iter_ int - Фактическое количество итераций для достижения критерия остановки. Для многоклассовой подгонки это максимум для каждой двоичной подгонки.

t_ int -Количество обновлений веса, выполненных во время тренировки. То же, что и .(n_iter_ * n_samples + 1)

Методы:

decision_function(X) Прогнозирование показателей достоверности для выборок.

densify() Преобразуйте матрицу коэффициентов в формат плотного массива.

fit(X, y[, coef_init, intercept_init, ...]) Подберите линейную модель со стохастическим градиентным спуском.

get_metadata_routing() Получите маршрутизацию метаданных этого объекта.

get_params([deep]) Получите параметры для этой оценки.

partial_fit(X, y[, classes, sample_weight]) Выполните одну эпоху стохастического градиентного спуска на данных выборках.

predict(X) Прогнозируйте метки классов для образцов в X.

score(X, y[, sample_weight]) Возвращает среднюю точность данных испытаний и меток.

set_fit_request(*[, coef_init, ...]) Метаданные запроса, передаваемые в fitметод.

set_params(*params) Установите параметры этой оценки.

set_partial_fit_request(*[, classes, ...]) Метаданные запроса, передаваемые в partial_fitметод.

set_score_request(*[, sample_weight]) Метаданные запроса, передаваемые в score метод.

sparsify() Преобразуйте матрицу коэффициентов в разреженный формат.

Используем линейный персептрон для решения задачи классификации регионов РФ по типу экономики. Ариори ясно, что безошибочно линейно расделить регионы на классы с помощью линейного перцептрона не получиться. Ниже приведен скрипт python для решения задачи классификации регионов. При разделения множества регинов на train и tect соотношении 0.9 , 0.1 полученный результат на тесте имеет верность равную 0.78 (две ошибки из 9).Построение кривых обучения показывает что средняя ошибка стремиться к уровню 0.6-0.65 ,что подтверждает теоретические ограниченные возможности линейного персептрона как классификатора.

In [1]:
#Perceptron линейный

import warnings
import numpy as np
import scipy.stats as st
from pandas import Series, DataFrame
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Perceptron
import plotly
import plotly.express as px
import plotly.graph_objs as go

warnings.simplefilter('ignore')

#ввод исходных данных из файла
Regdata =pd.ExcelFile('REG_RU_03.xlsx')
Regtab1 =Regdata.parse('dan04')
#print(Regtab1)
ind=np.arange(0,len(Regtab1), 1)


Reg1df=DataFrame(Regtab1,index=ind,columns=['Name','PI_N','Pcx_N','PP_N','Claster'])
Reg1df = np.round(Reg1df,decimals = 2) 
Reg2df=Reg1df[['PI_N','Pcx_N','PP_N']]
Reg1df

y=Reg1df['Claster']
y=np.array(y)
X=np.array (Reg2df)

#нормирование значений элементов массива X
SUMX=X[:,0] +X[:,1] + X[:,2] 
X[:,0] =(X[:,0] /SUMX)*100
X[:,1] =(X[:,1] /SUMX)*100
X[:,2] =(X[:,2] /SUMX)*100

#описательные статистики P10
print('Описательные статистики предикторов')
for num in range(3) : 
  print('Номер переменной: %.0f' %num)
  print('число элентов массива =',len(X[:,num]))
  print('среднее значение =',np.mean(X[:,num]))
  print('стандартное отклонение =',np.std(X[:,num]))
  print('мин мах =',np.min(X[:,num]), np.max(X[:,num]))


#выделение обучающей и тренировочной последовательностей
X_train, X_test, y_train, y_test = train_test_split  ( X , y , test_size=0.1, random_state=0)

print('Фактические метки классов на тесте')
print(y_test)

#обучение перцептрона
ppn = Perceptron(tol=1e-5,max_iter =1000,random_state=10)
ppn.fit(X_train, y_train)
Perceptron()
ppn.score(X_train, y_train)
#проверка на тестовой последовательности
y_forecast = ppn.predict(X_test)

print('Прогнозные метки классов на тесте')
print(y_forecast)

#Оценка качества классификации
from sklearn.metrics import accuracy_score
eplus = accuracy_score(y_test, y_forecast)
print('Bepнocть: %.2f' %eplus) 

print('Матрица путаницы')
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
cm = confusion_matrix(y_test, y_forecast, labels=ppn.classes_)
disp = ConfusionMatrixDisplay(confusion_matrix=cm,display_labels=ppn.classes_)
disp.plot()
plt.show()

# ПОСТРОЕНИЕ КРИВЫХ ОБУЧЕНИЯ ==============================================


train_ndf=[]
train_meandf=[]
test_meandf=[]

from sklearn.model_selection import learning_curve
#gnb = GaussianNB()
train_size_abs, train_scores, test_scores = learning_curve(
ppn, X, y, train_sizes=np.linspace (0.1, 1, 50) )

for train_size, cv_train_scores, cv_test_scores in zip(train_size_abs, train_scores, test_scores):
    train_ndf.append(train_size)
    train_meandf.append(cv_train_scores.mean())
    test_meandf.append(cv_test_scores.mean())
    #print(f"{train_size} образцы использовались для обучения модели")
    #print(f"Средняя точность обучения {cv_train_scores.mean():.2f}")
    #print(f"Средняя точность теста {cv_test_scores.mean():.2f}")
train_n=DataFrame(train_ndf,columns=['train_size'])
train_mean=DataFrame(train_meandf,columns=['train'])
test_mean=DataFrame(test_meandf,columns=['test'])
tab_LC=pd.concat([train_n,train_mean,test_mean],axis=1)


plt.figure(figsize=(10, 6))                         
plt.plot(tab_LC.train_size,tab_LC.train,color='green', linewidth=2.0,label='train')
plt.plot(tab_LC.train_size,tab_LC.test,color='r', linewidth=2.0,label='test')
plt.xlabel(r'$trainsize$ размер обучающей выборки',fontsize=18)
plt.ylabel('Средняя точность',fontsize=18)
plt.title(r'Кривые обучения Perceptron', fontsize=18)
plt.legend()
plt.grid(True)
plt.show()
Описательные статистики предикторов
Номер переменной: 0
число элентов массива = 81
среднее значение = 14.606522100470073
стандартное отклонение = 21.45226047724495
мин мах = 0.0 88.01123490528579
Номер переменной: 1
число элентов массива = 81
среднее значение = 18.1794075086528
стандартное отклонение = 18.18581909139375
мин мах = 0.0 85.49166666666666
Номер переменной: 2
число элентов массива = 81
среднее значение = 67.21407039087713
стандартное отклонение = 23.035424677590143
мин мах = 10.317543736715482 98.71935180385155
Фактические метки классов на тесте
[2 2 1 5 1 2 0 2 4]
Прогнозные метки классов на тесте
[2 2 1 1 1 2 1 2 4]
Bepнocть: 0.78
Матрица путаницы
In [2]:
#ПРСТРОЕНИЕ КРИВЫХ ОБУЧЕНИЯ С ИСПОЛЬЗОВАНИЕМ LearningCurveDisplay
import numpy as np
import scipy.stats as st
from pandas import Series, DataFrame
import pandas as pd
from sklearn.datasets import load_digits
from sklearn.naive_bayes import GaussianNB
import matplotlib.pyplot as plt
from sklearn.model_selection import LearningCurveDisplay
from sklearn.utils import shuffle

#ввод исходных данных из файла
Regdata =pd.ExcelFile('REG_RU_03.xlsx')
Regtab1 =Regdata.parse('dan04')
#print(Regtab1)
ind=np.arange(0,len(Regtab1), 1)


Reg1df=DataFrame(Regtab1,index=ind,columns=['Name','PI_N','Pcx_N','PP_N','Claster'])
Reg1df = np.round(Reg1df,decimals = 2) 
Reg2df=Reg1df[['PI_N','Pcx_N','PP_N']]
Reg1df

y=Reg1df['Claster']
y=np.array(y)
X=np.array (Reg2df)

#нормирование значений элементов массива X
SUMX=X[:,0] +X[:,1] + X[:,2] 
X[:,0] =(X[:,0] /SUMX)*100
X[:,1] =(X[:,1] /SUMX)*100
X[:,2] =(X[:,2] /SUMX)*100



X, y = shuffle(X, y, random_state=0)
LearningCurveDisplay.from_estimator( Perceptron(tol=1e-5,max_iter =1000,random_state=10), X, y, train_sizes=np.linspace (0.1, 1, 50), cv=5)
plt.show()

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

Рассмотрим классификатор на основе многослойного персептрона.Эта модель оптимизирует функцию логарифмических потерь с помощью LBFGS или стохастического градиентного спуска. Она реализована в модуле sklearn, для ее использования должен быть загружен пакет from sklearn.neural_network import MLPClassifier и вызвать его:

MLPClassifier(hidden_layer_sizes=(100,), activation='relu', *, solver='adam', alpha=0.0001, batch_size='auto', learning_rate='constant', learning_rate_init=0.001, power_t=0.5, max_iter=200, shuffle=True, random_state=None, tol=0.0001, verbose=False, warm_start=False, momentum=0.9, nesterovs_momentum=True, early_stopping=False, validation_fraction=0.1, beta_1=0.9, beta_2=0.999, epsilon=1e-08, n_iter_no_change=10, max_fun=15000)

Параметры :

hidden_layer_sizes скрытый_слой_размеры в виде массива формы (n_layers - 2,), по умолчанию = (100,) - i-й элемент представляет количество нейронов в i-м скрытом слое.

activation {'identity', 'logistic', 'tanh', 'relu'},по умолчанию ='relu'- Функция активации скрытого слоя.

  • 'identity', активация без операций, полезная для реализации линейного узкого места, возвращает f(x) = x

  • 'logistic', логистическая сигмовидная функция, возвращает f(x) = 1/(1 + exp(-x)).

  • 'tanh', гиперболическая функция tan, возвращает f(x) = tanh(x).

  • 'relu', выпрямленная линейная единичная функция, возвращает f(x) = max(0, x)

solver {'lbfgs', 'sgd', 'adam'}, default= 'adam' Решатель для оптимизации веса.

  • «lbfgs» — это оптимизатор семейства квазиньютоновских методов.

  • «sgd» относится к стохастическому градиентному спуску.

  • «adam» относится к оптимизатору на основе стохастического градиента, предложенному Кингмой, Дидериком и Джимми Ба.

alpha float, default=0.0001 Сила члена регуляризации L2. Член регуляризации L2 делится на размер выборки и добавляется к потерям.

batch_size int, default='auto' Размер мини-пакетов для стохастических оптимизаторов. Если решателем является «lbfgs», классификатор не будет использовать мини-пакет. Если установлено значение «авто», batch_size=min(200, n_samples)

learning_rate int, default='auto'{'constant', 'invscaling', 'adaptive'}, default='constant' График обучения для обновлений веса.

  • «constant» — это постоянная скорость обучения, заданная параметром «learning_rate_init».

  • «invscaling» постепенно снижает скорость обучения на каждом временном шаге «t», используя показатель обратного масштабирования «power_t». effect_learning_rate = Learning_rate_init / pow(t, power_t)

  • «adaptive» поддерживает постоянную скорость обучения на уровне «learning_rate_init», пока потери на обучение продолжают уменьшаться. Каждый раз, когда две последовательные эпохи не могут уменьшить потери обучения хотя бы на tol или не могут увеличить оценку валидации хотя бы на tol, если включен параметр «early_stopping», текущая скорость обучения делится на 5 Используется только тогда, когда solver='sgd'.

learning_rate_init float, default=0.001 -Используемая начальная скорость обучения. Он контролирует размер шага при обновлении весов. Используется только в том случае, если Solver='sgd' или 'adam'.

power float, default=0.5 -Показатель степени обратного масштабирования скорости обучения. Он используется для обновления эффективной скорости обучения, когда для параметра Learning_rate установлено значение «invscaling». Используется только тогда, когда Solver='sgd'.

max_iter int, default=200 -Максимальное количество итераций. Решатель выполняет итерации до тех пор, пока не произойдет сходимость (определяемая параметром «tol») или указанное количество итераций. Для стохастических решателей («sgd», «adam») обратите внимание, что это определяет количество эпох (сколько раз будет использоваться каждая точка данных), а не количество шагов градиента.

shuffle bool, default=True -Перетасовывать ли образцы на каждой итерации. Используется только в том случае, если Solver='sgd' или 'adam'.

random_state int, RandomState instance, default=None -Определяет генерацию случайных чисел для инициализации весов и смещения, разделения теста поезда, если используется ранняя остановка, и пакетной выборки, когда Solver='sgd' или 'adam'. Передайте int для воспроизводимых результатов при нескольких вызовах функций.

tol float, default=1e-4b -Допуск к оптимизации. Когда потеря или оценка не улучшаются, по крайней мере, tolв течение n_iter_no_changeпоследовательных итераций, если learning_rate установлено значение не «adaptive», конвергенция считается достигнутой и обучение прекращается.

verbose bool, default=False -Выводить ли сообщения о ходе выполнения на стандартный вывод.

warm_start bool, default=False -Если установлено значение True, повторно используйте решение предыдущего вызова в качестве инициализации, в противном случае просто сотрите предыдущее решение

momentum float, default=0.9 -Импульс для обновления градиентного спуска. Должно быть от 0 до 1. Используется только в том случае, если Solver='sgd'.

nesterovs_momentum bool, default=True -Стоит ли использовать импульс Нестерова. Используется только тогда, когда Solver='sgd' и импульс > 0.

early_stopping bool, default=False -Следует ли использовать раннюю остановку для прекращения обучения, если показатель проверки не улучшается. Если установлено значение true, он автоматически отложит 10 % данных обучения для проверки и прекратит обучение, если оценка проверки не улучшится как минимум на 10 шагов в течение n_iter_no_changeпоследовательных эпох. Разделение является стратифицированным, за исключением настройки с несколькими метками. Если ранняя остановка имеет значение False, то обучение прекращается, когда потери при обучении не уменьшаются более чем на tol за n_iter_no_change последовательных проходов по обучающему набору. Эффективно только в том случае, если Solver='sgd' или 'adam'.

validation_fraction float, default=0.1 -Доля обучающих данных, которые необходимо отложить в качестве набора проверки для ранней остановки. Должно быть от 0 до 1. Используется только в том случае, если Early_stopping имеет значение True.

beta_1 float, default=0.9 -Скорость экспоненциального убывания для оценок вектора первого момента в адаме должна находиться в пределах [0, 1). Используется только тогда, когда Solver='adam'.

beta_2 float, default=0.999 -Скорость экспоненциального убывания для оценок вектора второго момента в адаме должна находиться в пределах [0, 1). Используется только тогда, когда Solver='adam'.

epsilon float, default=1e-8 -Значение числовой стабильности в адаме. Используется только тогда, когда Solver='adam'.

n_iter_no_change int, default=10 -Максимальное количество эпох, в течение которых не будет достигнуто tolулучшение. Эффективно только в том случае, если Solver='sgd' или 'adam'.

max_fun int, default=15000 -Используется только тогда, когда Solver='lbfgs'. Максимальное количество вызовов функции потерь. Решатель выполняет итерации до тех пор, пока не произойдет сходимость (определяемая параметром «tol»), количество итераций не достигнет max_iter или этого количества вызовов функции потерь. Обратите внимание, что количество вызовов функции потерь будет больше или равно количеству итераций для MLPClassifier.

Атрибуты :

classes_ ndarray or list of ndarray of shape (n_classes,) -Метки классов для каждого выхода.

loss_ float -Текущие потери, рассчитанные с помощью функции потерь.

best_loss_ float or None -Минимальные потери, достигнутые решателем во время подгонки. Если early_stopping=True этот атрибут имеет значение None. Вместо этого обратитесь к установленному атрибуту best_validation_score_ .

loss_curve_ list of shape (n_iter_,) -i-й элемент в списке представляет потери на i-й итерации.

validation_scores_ list of shape (n_iter_,) or None -Оценка на каждой итерации в наборе отложенной проверки. Сообщаемая оценка является оценкой точности. Доступно только в том случае, если early_stopping=True, в противном случае атрибуту присвоено значение None.

best_validation_score_ float or None -Наилучшая оценка валидации (т. е. оценка точности), которая привела к досрочной остановке. Доступно только в том случае, если early_stopping=True, в противном случае атрибуту присвоено значение None.

t_ int -Количество обучающих выборок, видимых решателем во время подгонки.

coefs_ list of shape (n_layers - 1,) -i-й элемент в списке представляет весовую матрицу, соответствующую слою i.

intercepts_ list of shape (n_layers - 1,) - i-й элемент в списке представляет вектор смещения, соответствующий слою i + 1.

n_features_in_ int -Количество функций, наблюдаемых во время подгонки .

feature_names_in_ ndarray of shape (n_features_in_,) -Названия функций, видимых во время подгонки . Определяется только в том случае, если X имена объектов состоят из строк.

n_iter_ int -Количество итераций, выполненных решателем.

n_layers_ int -Количество слоев.

n_outputs_ int -Количество выходов

out_activation_ str -Имя функции активации выхода.

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

Методы:

fit(Х, у) Сопоставьте модель с матрицей данных X и целью(ями) y.

get_metadata_routing() Получите маршрутизацию метаданных этого объекта.

get_params([deep]) Получите параметры для этой оценки.

partial_fit(X, y[, classes]) Обновите модель с помощью одной итерации по заданным данным.

predict(X) Прогнозируйте с помощью многослойного классификатора перцептрона.

predict_log_proba(X) Возвратите журнал оценок вероятности.

predict_proba(X) Вероятностные оценки.

score(X, y[, sample_weight]) Возвращает среднюю точность данных испытаний и меток.

set_params(*params) Установите параметры этой оценки.

set_partial_fit_request(*[, classes]) Метаданные запроса, передаваемые в partial_fitметод.

set_score_request(*[, sample_weight]) Мета

Используем MLPClassifier для классификации регионов РФ по типу экономики. Как мы видели у функции MLPClassifier можно задавать очень много параметров, но их выбор для конкретных данных скорее искусство , чем наука. Поэтому будем использовать этот нейроклассификатор с параметрами по умолчанию кроме двух : для воспроизводимости результатов параметр random_state=1,а параметр max_iter=300.Скрипт python и результаты его работы представлены ниже.MLPClassifier безошибочно решил задачу классификации регионов РФ по типу экономики для размера train последовательности равной 0.9 (test=0.1). Кривые обучения также демонстрируют высокое качество работы данной функции на наших данных, практически подтверждая, теоретический вывод о том, что многослойный персептрон может апроксимировать любую функцию со сколько угодной высокой точностью. Кривые обучения при размере train>0.5 (test<0.5) стремятся друг к другу, достигая точности около 100 процентов

In [1]:
#МНОГОСЛОЙНЫЙ ПЕРСЕПТРОН
import warnings
import numpy as np
import scipy.stats as st
from pandas import Series, DataFrame
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
import plotly
import plotly.express as px
import plotly.graph_objs as go

warnings.simplefilter('ignore')

#ввод исходных данных из файла
Regdata =pd.ExcelFile('REG_RU_03.xlsx')
Regtab1 =Regdata.parse('dan04')
#print(Regtab1)
ind=np.arange(0,len(Regtab1), 1)


Reg1df=DataFrame(Regtab1,index=ind,columns=['Name','PI_N','Pcx_N','PP_N','Claster'])
Reg1df = np.round(Reg1df,decimals = 2) 
Reg2df=Reg1df[['PI_N','Pcx_N','PP_N']]
Reg1df

y=Reg1df['Claster']
y=np.array(y)
X=np.array (Reg2df)

#нормирование значений элементов массива X
SUMX=X[:,0] +X[:,1] + X[:,2] 
X[:,0] =(X[:,0] /SUMX)*100
X[:,1] =(X[:,1] /SUMX)*100
X[:,2] =(X[:,2] /SUMX)*100

#выделение обучающей и тренировочной последовательностей
X_train, X_test, y_train, y_test = train_test_split  ( X , y , test_size=0.1, random_state=0)

print('Фактические метки классов на тесте')
print(y_test)

#обучение перцептрона

clf = MLPClassifier(random_state=1, max_iter=300).fit(X_train, y_train)
y_forecast=clf.predict(X_test)
clf.score(X_test, y_test)
print('Прогнозные метки классов на тесте')
print(y_forecast)

#Оценка качества классификации
from sklearn.metrics import accuracy_score
eplus = accuracy_score(y_test, y_forecast)
print('Bepнocть: %.2f' %eplus) 

print('Матрица путаницы')
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
cm = confusion_matrix(y_test, y_forecast, labels=clf.classes_)
disp = ConfusionMatrixDisplay(confusion_matrix=cm,display_labels=clf.classes_)
disp.plot()
plt.show()

# ПОСТРОЕНИЕ КРИВЫХ ОБУЧЕНИЯ ==============================================


train_ndf=[]
train_meandf=[]
test_meandf=[]

from sklearn.model_selection import learning_curve
#gnb = GaussianNB()
train_size_abs, train_scores, test_scores = learning_curve(
clf, X, y, train_sizes=np.linspace (0.1, 1, 50) )

for train_size, cv_train_scores, cv_test_scores in zip(train_size_abs, train_scores, test_scores):
    train_ndf.append(train_size)
    train_meandf.append(cv_train_scores.mean())
    test_meandf.append(cv_test_scores.mean())
    #print(f"{train_size} образцы использовались для обучения модели")
    #print(f"Средняя точность обучения {cv_train_scores.mean():.2f}")
    #print(f"Средняя точность теста {cv_test_scores.mean():.2f}")
train_n=DataFrame(train_ndf,columns=['train_size'])
train_mean=DataFrame(train_meandf,columns=['train'])
test_mean=DataFrame(test_meandf,columns=['test'])
tab_LC=pd.concat([train_n,train_mean,test_mean],axis=1)


plt.figure(figsize=(10, 6))                         
plt.plot(tab_LC.train_size,tab_LC.train,color='green', linewidth=2.0,label='train')
plt.plot(tab_LC.train_size,tab_LC.test,color='r', linewidth=2.0,label='test')
plt.xlabel(r'$trainsize$ размер обучающей выборки',fontsize=18)
plt.ylabel('Средняя точность',fontsize=18)
plt.title(r'Кривые обучения многослойного персептрона.', fontsize=18)
plt.legend()
plt.grid(True)
plt.show()
Фактические метки классов на тесте
[2 2 1 5 1 2 0 2 4]
Прогнозные метки классов на тесте
[2 2 1 5 1 2 0 2 4]
Bepнocть: 1.00
Матрица путаницы
In [3]:
#ПРСТРОЕНИЕ КРИВЫХ ОБУЧЕНИЯ С ИСПОЛЬЗОВАНИЕМ LearningCurveDisplay
import numpy as np
import scipy.stats as st
from pandas import Series, DataFrame
import pandas as pd
from sklearn.datasets import load_digits
from sklearn.naive_bayes import GaussianNB
import matplotlib.pyplot as plt
from sklearn.model_selection import LearningCurveDisplay
from sklearn.utils import shuffle

#ввод исходных данных из файла
Regdata =pd.ExcelFile('REG_RU_03.xlsx')
Regtab1 =Regdata.parse('dan04')
#print(Regtab1)
ind=np.arange(0,len(Regtab1), 1)


Reg1df=DataFrame(Regtab1,index=ind,columns=['Name','PI_N','Pcx_N','PP_N','Claster'])
Reg1df = np.round(Reg1df,decimals = 2) 
Reg2df=Reg1df[['PI_N','Pcx_N','PP_N']]
Reg1df

y=Reg1df['Claster']
y=np.array(y)
X=np.array (Reg2df)

#нормирование значений элементов массива X
SUMX=X[:,0] +X[:,1] + X[:,2] 
X[:,0] =(X[:,0] /SUMX)*100
X[:,1] =(X[:,1] /SUMX)*100
X[:,2] =(X[:,2] /SUMX)*100



X, y = shuffle(X, y, random_state=0)
LearningCurveDisplay.from_estimator( MLPClassifier(random_state=1, max_iter=300), X, y, train_sizes=np.linspace (0.1, 1, 50), cv=5)
plt.show()

Реализация нейросетевых классификаторов в R¶

В R имеется несколько библиотек реализующих нейромодели. Расмотрим две из них library(neuralnet) и library(monmlp).

Нейросеть прямого распространения (neuralnet) как классификатор.

Описание

Можно обучать нейронные сети, используя обратное распространение ошибки, устойчивое обратное распространение ошибки (RPROP) с (Ридмиллер, 1994) или без весового обратного отслеживания (Ридмиллер и Браун, 1993) или модифицированную глобально конвергентную версию (GRPROP) Анастасиадиса и др. (2005). Функция обеспечивает гибкую настройку посредством индивидуального выбора ошибки и функции активации. Кроме того, реализован расчет обобщенных весов (Интратор О. и Интратор Н., 1993)

Применение

neuralnet(formula, data, hidden = 1, threshold = 0.01, stepmax = 1e+05, rep = 1, startweights = NULL, learningrate.limit = NULL, learningrate.factor = list(minus = 0.5, plus = 1.2), learningrate = NULL, lifesign = "none", lifesign.step = 1000, algorithm = "rprop+", err.fct = "sse",act.fct = "logistic", linear.output = TRUE, exclude = NULL, constant.weights = NULL, likelihood = FALSE)

Аргументы:

formula символическое описание устанавливаемой модели.

data кадр данных, содержащий переменные, указанные в formula.

hidden вектор целых чисел, определяющий количество скрытых нейронов (вершин) в каждом слое.

threshold числовое значение, определяющее порог для частных производных функции ошибок в качестве критерия остановки.

stepmax максимальные шаги для обучения нейронной сети. Достижение этого максимума приводит к остановке процесса обучения нейронной сети.

rep количество повторений обучения нейронной сети.

startweights вектор, содержащий начальные значения весов. Установите значение NULL для случайной инициализации.

learningrate.limit вектор или список, содержащий нижний и верхний предел скорости обучения. Используется только для RPROP и GRPROP.

learningrate.factor вектор или список, содержащий коэффициенты умножения для верхней и нижней скорости обучения. Используется только для RPROP и GRPROP.

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

lifesign строка, указывающая, сколько функция будет печатать во время расчета нейронной сети. «нет», «минимальный» или «полный».

lifesign.step целое число, определяющее размер шага для печати минимального порога в режиме полного жизненного знака.

algorithm строка, содержащая тип алгоритма расчета нейронной сети. Возможны следующие типы: «backprop», «rprop+», «rprop-», «sag» или «slr». «backprop» относится к обратному распространению ошибки, «rprop+» и «rprop-» относятся к устойчивому обратному распространению ошибки с обратным отслеживанием веса и без него, а «sag» и «slr» вызывают использование модифицированного глобально конвергентного алгоритма (grprop). См. Подробности для получения дополнительной информации.

err.fct дифференцируемая функция, которая используется для вычисления ошибки. В качестве альтернативы можно использовать строки «sse» и «ce», которые обозначают сумму квадратов ошибок и перекрестную энтропию.

act.fct дифференцируемая функция, которая используется для сглаживания результата векторного произведения ковариаты или нейронов и весов. Кроме того, строки 'logistic' и 'tanh' возможны для логистической функции и тангенса гиперболического.

linear.output logical.. Если act.fct не следует применять к выходным нейронам, установите для линейного выхода значение TRUE, в противном случае — FALSE.

exclude вектор или матрица, задающая веса, исключаемые из расчета. Если задано в виде вектора, необходимо знать точные положения весов. Матрица с n строками и 3 столбцами исключит n весов, где первый столбец соответствует слою, второй столбец — входному нейрону, а третий столбец — выходному нейрону веса.

constant.weights вектор, задающий значения весов, которые исключаются из процесса обучения и рассматриваются как фиксированные.

likelihood logical.. Если функция ошибок равна отрицательной логарифмической функции правдоподобия, будут рассчитаны информационные критерии AIC и BIC. Более того, использование доверительного интервала имеет смысл.

Подробности

Глобально конвергентный алгоритм основан на устойчивом обратном распространении ошибки без обратного отслеживания по весу и дополнительно изменяет одну скорость обучения: либо скорость обучения, связанную с наименьшим абсолютным градиентом (провисание), либо саму наименьшую скорость обучения (SLR). Скорость обучения в алгоритме grprop ограничена границами, определенными в Learningrate.limit.

Оценки:

neuralnet возвращает объект класса nn. Объект класса nn— это список, содержащий не более следующих компонентов:

call совпадающий вызов.

response извлечено из data argument.

covariate переменные, извлеченные из файла data argument.

model.list список, содержащий ковариаты и переменные ответа, извлеченные из файла formula argument.

err.fct функция ошибки.

act.fct функция активации.

data data argument_

net.result список, содержащий общий результат работы нейронной сети для каждого повторения.

weights список, содержащий подобранные веса нейронной сети для каждого повторения.

generalized.weights список, содержащий обобщенные веса нейронной сети для каждого повторения.

result.matrix матрица, содержащая достигнутый порог, необходимые шаги, ошибку, AIC и BIC (если вычислены) и веса для каждого повторения. Каждый столбец представляет собой одно повторение.

startweights список, содержащий начальные веса нейронной сети для каждого повторения.

Используем neuralnet для классификации регионов РФ по типу экономики.Соотвествующий скрипты R и результаты их работы приведены ниже. Для классификации мы использовали нейронную сеть прямого распространения с двумя скрытыми слоями, содержащими 5 и 2 нейрона.Остальные параметры нейросети взяты по умолчанию. При размере обучающей последовательности train=0.8 (test=0.2) верность классификации на тесте равна 0.95 (одна ошибка на 22 значениях). Кроме того построен график зависимости средней точности (neuralnet, N=50) на test от доли train с доверительным интервалом. Из графика видно,что сростом доли train растет средняя точность классификации на тесте стремясь к значению 0.8. При тонкой настройки нейросети на наши данные, по всей видимости, можно улучшить эти результаты.

In [2]:
#классификация neuralnet

options(warn=-1)
library(openxlsx)
library(e1071) # naiveBayes
library(caTools)
library(MASS)
library(class)
library(gmodels)
library(openxlsx)
library(caret)
library(ggplot2) 
library(GGally)
library(psych)
library(neuralnet)

#ЗАГРУЗКА ИЗ EXSEL ПЕРВИЧНЫХ ДАННЫХ
N=6 # номер листа с данными
x <-read.xlsx("REG_RU_03.xlsx", sheet = N)
#x
xreg <-data.frame(X1=x$PI_N,X2=x$Pcx_N,X3=x$PP_N,Class=x$Claster)

xreg_f <-xreg[,'Class']

xregSum =xreg[,'X1']+xreg[,'X2']+xreg[,'X3']
xreg[,'X1']=xreg[,'X1']/xregSum
xreg[,'X2']=xreg[,'X2']/xregSum
xreg[,'X3']=xreg[,'X3']/xregSum

xstr_nor <-xreg[,1:3]
xstr_nor <-cbind(xstr_nor,xreg_f)

# Разделение данных на обучающие и тестовые данные
set.seed(4948493)
split <- sample.split(xstr_nor, SplitRatio = 0.8)
train_cl <- subset(xstr_nor , split == "TRUE")
test_cl <- subset(xstr_nor, split == "FALSE")

classnnet <-neuralnet(xreg_f~X1+X2+X3,data=train_cl, hidden=c(5,2),linear.output = TRUE)                  
#classnnet$net.result
plot(classnnet)

# ПРОГНОЗ КЛАССОВ НА ТЕСТЕ
class_res <-compute(classnnet,test_cl)
tar_pred =class_res$net.result
Test = test_cl$xreg_f
Pred=round(tar_pred, digits = 0)
ResultCl <-cbind(Test,Pred)
CrossTable(x=ResultCl [,1],y=ResultCl [,2], prob.chisq = TRUE)

test_f<-factor(ResultCl[,1])
Resul<-data.frame(ResPred=Pred,ResTest=test_f)
Resul

# Матрица путаницы
m_at <- table(test_f,Pred)
m_at

#оценка точности 
j=0
for(i in 1:length(Resul[,2])){
if (Resul[i,2]==Resul[i,1]){j=j+1} 
}    
accur= j/length(Resul[,2])
accur=round(accur, digits = 2)
print(paste('Установлено, что точность теста=',accur))
 
   Cell Contents
|-------------------------|
|                       N |
| Chi-square contribution |
|           N / Row Total |
|           N / Col Total |
|         N / Table Total |
|-------------------------|

 
Total Observations in Table:  20 

 
              | ResultCl[, 2] 
ResultCl[, 1] |         0 |         1 |         2 |         3 |         4 |         5 | Row Total | 
--------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
            0 |         4 |         0 |         0 |         0 |         0 |         0 |         4 | 
              |    12.800 |     0.600 |     1.200 |     0.200 |     0.800 |     0.400 |           | 
              |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.200 | 
              |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.000 |           | 
              |     0.200 |     0.000 |     0.000 |     0.000 |     0.000 |     0.000 |           | 
--------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
            1 |         0 |         3 |         0 |         0 |         0 |         0 |         3 | 
              |     0.600 |    14.450 |     0.900 |     0.150 |     0.600 |     0.300 |           | 
              |     0.000 |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.150 | 
              |     0.000 |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |           | 
              |     0.000 |     0.150 |     0.000 |     0.000 |     0.000 |     0.000 |           | 
--------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
            2 |         0 |         0 |         6 |         0 |         0 |         0 |         6 | 
              |     1.200 |     0.900 |     9.800 |     0.300 |     1.200 |     0.600 |           | 
              |     0.000 |     0.000 |     1.000 |     0.000 |     0.000 |     0.000 |     0.300 | 
              |     0.000 |     0.000 |     1.000 |     0.000 |     0.000 |     0.000 |           | 
              |     0.000 |     0.000 |     0.300 |     0.000 |     0.000 |     0.000 |           | 
--------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
            4 |         0 |         0 |         0 |         1 |         4 |         0 |         5 | 
              |     1.000 |     0.750 |     1.500 |     2.250 |     9.000 |     0.500 |           | 
              |     0.000 |     0.000 |     0.000 |     0.200 |     0.800 |     0.000 |     0.250 | 
              |     0.000 |     0.000 |     0.000 |     1.000 |     1.000 |     0.000 |           | 
              |     0.000 |     0.000 |     0.000 |     0.050 |     0.200 |     0.000 |           | 
--------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
            5 |         0 |         0 |         0 |         0 |         0 |         2 |         2 | 
              |     0.400 |     0.300 |     0.600 |     0.100 |     0.400 |    16.200 |           | 
              |     0.000 |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.100 | 
              |     0.000 |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |           | 
              |     0.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.100 |           | 
--------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
 Column Total |         4 |         3 |         6 |         1 |         4 |         2 |        20 | 
              |     0.200 |     0.150 |     0.300 |     0.050 |     0.200 |     0.100 |           | 
--------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|

 
A data.frame: 20 × 2
ResPredResTest
<dbl><fct>
322
722
1155
1522
1944
2322
2700
3100
3500
3955
4334
4744
5122
5500
5911
6344
6711
7144
7522
7911
      Pred
test_f 0 1 2 3 4 5
     0 4 0 0 0 0 0
     1 0 3 0 0 0 0
     2 0 0 6 0 0 0
     4 0 0 0 1 4 0
     5 0 0 0 0 0 2
[1] "Установлено, что точность теста= 0.95"

Plot neuralnet

In [4]:
#КРИВАЯ ОБУЧЕНИЯ ДЛЯ neuralnet
require(ggplot2)
library(ggthemes)

N=50 # объем вариаций на каждом уровне train
accurdf <- matrix(0, ncol = 8, nrow = N)## Создать нулевую матрицу 
i=0
for (sr in seq(from=0.2, to=0.9, by=0.1)) 
{
i=i+1 
ik <- 12300   
for (j in 1:N)
{
ik <- ik+15
set.seed(ik)
split <- sample.split(xstr_nor, SplitRatio = sr)
train_cl <- subset(xstr_nor , split == "TRUE")
test_cl <- subset(xstr_nor, split == "FALSE")

# Подгонка nn модели к набору обучающих данных
classnnet <-neuralnet(xreg_f~X1+X2+X3,data=train_cl, hidden=c(5,2),linear.output = TRUE)

# ПРОГНОЗ КЛАССОВ НА ТЕСТЕ
class_res <-predict(classnnet, test_cl, rep = 1)

Test = test_cl$xreg_f
Pred=round(class_res, digits = 0)
Resul <-cbind(Test,Pred)

#оценка точности
k=0
for(l in 1:length(Resul[,2])){
if (Resul[l,2]==Resul[l,1]){k=k+1} 
}    
accuracy= k/length(Resul[,2])
accuracy=round(accuracy, digits = 2)  
accurdf[j,i]=accuracy 
}
} 
ASSdf<-data.frame(accuracy=accurdf)

# ГРАФИК КРИВОЙ ОБУЧЕНИЯ
meandf <-rep(0, times= 8 )
dovint1df <-rep(0, times= 8 )
dovint2df <-rep(0, times= 8 )

for (i in seq(from=1, to=8, by=1))
{    
meandf[i]=mean(ASSdf[,i])
model <- lm(ASSdf[,i] ~ 1 )
dovint=confint(model, level=0.95)
dovint1df[i]=dovint[1]
dovint2df[i]=dovint[2]
}    
ASS_PARdf =data.frame(train_N=seq(from=0.2, to=0.9, by=0.1),accmean=meandf,dovint2_5=dovint1df,dovint97_5=dovint2df)
options(repr.plot.width = 18, repr.plot.height =10)
theme_update(text = element_text(size=20))
g4 <-ggplot(data=ASS_PARdf, aes(x=train_N),
colors = "Accent")
g4 <-g4 +geom_point(aes(y=accmean),size=5)
g4 <-g4 +geom_line( aes(y=accmean,colour='accmean'),linetype=1,size=2)
g4 <-g4 +geom_line(aes(y=dovint2_5,colour='dovint2_5'),linetype=2,size=1)
g4 <-g4 +geom_line(aes(y=dovint97_5,colour='dovint97_5'),linetype=2,size=1,)
g4 <-g4+scale_colour_manual("Среднее и дов.инт.", 
                      breaks = c("accmean", "dovint2_5", "dovint97_5"),
                      values = c("blue", "red", "green"))
g4 <-g4 +labs(title =" График зависимости средней точности (neuralnet, N=50) на test от доли train с доверительным интервалом",
x="Доля train", y="Средняя точность классификации на тесте")
g4  <-g4+theme(axis.text = element_text(size = 16, angle=0,face = "plain")) 
g4  <-g4+theme(plot.title = element_text(size = 22,face = "plain"))
g4  <-g4+theme( axis.title = element_text(size = 18,face = "plain"))
g4

Классификатор на основе многослойного персептрона monmlp

Описание Позволяет подобрать отдельную модель или ансамбль моделей регрессии MLP или MONMLP с помощью optimx процедур оптимизации, чтобы минимизировать функцию стоимости наименьших квадратов. Чтобы избежать переобучения, можно использовать дополнительную остановку обучения и начальную агрегацию (пакетирование). При вызов monotone аргумента обеспечивает усиление поведения между указанными столбцами xи выходными данными модели. В этом случае exp функция применяется к соответствующим весам после инициализации и во время оптимизации; init.weights может потребоваться ручная регулировка.

Применение

monmlp.fit(x, y, hidden1, hidden2 = 0, iter.max = 5000,n.trials = 1, n.ensemble = 1, bag = FALSE, cases.specified = NULL, iter.stopped = NULL,scale.y = TRUE, Th = tansig, To = linear, Th.prime = tansig.prime, To.prime = linear.prime, monotone = NULL, init.weights = NULL, max.exceptions = 10, silent = FALSE, method = "BFGS",control = list(trace = 0))

Аргументы:

x матрица ковариат с количеством строк, равным количеству выборок, и количеством столбцов, равным количеству ковариат.

y матрица ответа с количеством строк, равным количеству выборок, и количеством столбцов, равным количеству переменных ответа.

hidden1 количество нейронов в первом скрытом слое.

hidden2 количество нейронов во втором скрытом слое.

iter.max максимальное количество итераций алгоритма оптимизации.

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

n.ensemble необходимое количество участников ансамбля.

bag логическая переменная, указывающая, следует ли использовать начальную агрегацию (пакетирование).

cases.specified if bag = TRUE— список, в котором указаны загрузочные варианты, которые будут использоваться в каждом члене ансамбля.

iter.stopped if bag = TRUEуказывает количество остановленных итераций обучения между расчетом функции стоимости в случаях выхода за пределы начальной загрузки.

scale.y логическое определение того, следует ли масштабировать столбцы матрицы ответов до нулевого среднего и единичной дисперсии перед подгонкой. Установите это значение, FALSEесли используете передаточную функцию выходного слоя, которая ограничивает диапазон прогнозов.

Th функция передачи скрытого слоя.

To Передаточная функция выходного слоя.

Th.prime производная передаточной функции скрытого слоя.

To.prime производная передаточной функции выходного слоя.

monotone индексы столбцов ковариат, для которых должно выполняться ограничение монотонности.

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

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

silent логическое определение того, следует ли подавлять диагностические сообщения.

method optimx метод оптимизации.

control list of optimx параметры управления.

Оценки

список, содержащий подобранные весовые матрицы с атрибутами, включая вызываемые значения x, y, Th, To, Th.prime, To.prime, monotone, bag, iter.max, и iter.stopped, а также значения средних значений столбца ковариаты/ответа и стандартные отклонения ( x.center, x.scale, y.center, y.scale), случаи вне начальной загрузки oob, прогнозируемые значения y.pred, и, если включено остановленное обучение, итерация iter.bestи значение функции стоимости cost.best, которая минимизировала ошибку проверки вне начальной загрузки.

Используем monmlp.fit для классификации регионов РФ по типу экономики. Установим следующие параметры: hidden1=5,hidden2 =2, n.ensemble=1,iter.max = 500,scale.y=FALSE,method = 'L-BFGS-B',silent = TRUE.Значения остальных параметров примем по умолчанию. Скрипты R классификации регионов при размере train последовательности равной 0.8 (test=0.2) и построения графика зависимости средней точности на test от доли train (monmlp,N=100) с доверительным интервалом представлены ниже. Как мы видим monmlp.fit решил задачу классификации регионов со 100 процентной точностью. Средняя точность классификации статистически стремиться к величине 0.8-0.9. Из теории ясно, что можно подобрать такой набор параметров двухслойного персептрона при котором средняя точность классификации на наших данных будет стремиться к 1.0

In [3]:
# МНОСЛОЙНЫЙ ПЕРЦЕПТРОН monmlp
# Loading package
options(warn=-1)
library(openxlsx)
#library(klaR) # naiveBayes
library(e1071) # naiveBayes
library(caTools)
library(MASS)
library(class)
library(gmodels)
library(openxlsx)
library(caret)
library(ggplot2) 
library(GGally)
library(psych)
library(neuralnet)
library(monmlp) 
library(ROCR)

#ЗАГРУЗКА ИЗ EXSEL ПЕРВИЧНЫХ ДАННЫХ
N=6 # номер листа с данными
x1 <-read.xlsx("REG_RU_03.xlsx", sheet = N)
#x
xreg <-data.frame(X1=x1$PI_N,X2=x1$Pcx_N,X3=x1$PP_N,Class=x1$Claster)

#xreg[,'Class']<-factor(xreg[,'Class'])
xreg_f <-xreg[,'Class']

xregSum =xreg[,'X1']+xreg[,'X2']+xreg[,'X3']
xreg[,'X1']=xreg[,'X1']/xregSum
xreg[,'X2']=xreg[,'X2']/xregSum
xreg[,'X3']=xreg[,'X3']/xregSum

xstr_nor <-xreg[,1:3]
xstr_nor <-cbind(xstr_nor,xreg_f)
xstr_nor <-cbind(x1$Name,xstr_nor)

# Разделение данных на обучающие и тестовые данные
set.seed(123)
split <- sample.split(xstr_nor, SplitRatio = 0.8)
train_cl <- subset(xstr_nor , split == "TRUE")
test_cl <- subset(xstr_nor, split == "FALSE")
x= as.matrix(train_cl[,2:4])
y= as.matrix(train_cl[,5])
Xtest=as.matrix(test_cl[,2:4])
nc=1
# Fit the model and compute the predictions 
# Возможные коды методов : «Nelder-Mead», «BFGS», «CG», «L-BFGS-B», «nlm», «nlminb»,
#«spg», «ucminf», «newuoa». , «bobyqa», «nmkb», «hjkb», «Rcgmin» или «Rvmmin».

r <- monmlp.fit(x, y, hidden1=5,hidden2 =2, n.ensemble=nc,iter.max = 500,scale.y=FALSE,method = 'L-BFGS-B',silent = TRUE) 
z <- monmlp.predict(x = Xtest, weights = r) 
Pred=as.integer(round(z, digits = 0))
Test = as.integer(test_cl$xreg_f)
Resul<-data.frame(Name=test_cl[,1],ResPred=Pred,ResTest=Test)
Resul

CrossTable(x=Resul[,3],y=Resul[,2], prob.chisq = TRUE)

# Матрица путаницы
test_f<-factor(Resul[,3])
m_at <- table(test_f,Resul[,2])
m_at

#оценка точности 1
confusionMatrix(m_at)
accuracy=confusionMatrix(m_at)$overall[1]
print(paste('Установлено, что точность 1 теста=',accuracy))


#оценка точности 2
j=0
for(i in 1:length(Resul[,3])){
if (Resul[i,3]==Resul[i,2]){j=j+1} 
}    
accur= j/length(Resul[,3])
accur=round(accur, digits = 2)
print(paste('Установлено, что точность 2 теста=',accur))
A data.frame: 16 × 3
NameResPredResTest
<chr><int><int>
Ивановская область 22
Московская область 22
Тверская область 22
Республика Коми 11
Мурманская область 44
Республика Калмыкия 33
Ростовская область 00
Республика Северная Осетия 55
Республика Мордовия 00
Кировская область 22
Саратовская область 00
Челябинская область 22
Красноярский край 44
Томская область 44
Приморский край 22
Еврейская автономная область00
 
   Cell Contents
|-------------------------|
|                       N |
| Chi-square contribution |
|           N / Row Total |
|           N / Col Total |
|         N / Table Total |
|-------------------------|

 
Total Observations in Table:  16 

 
             | Resul[, 2] 
  Resul[, 3] |         0 |         1 |         2 |         3 |         4 |         5 | Row Total | 
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
           0 |         4 |         0 |         0 |         0 |         0 |         0 |         4 | 
             |     9.000 |     0.250 |     1.500 |     0.250 |     0.750 |     0.250 |           | 
             |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.250 | 
             |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.000 |           | 
             |     0.250 |     0.000 |     0.000 |     0.000 |     0.000 |     0.000 |           | 
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
           1 |         0 |         1 |         0 |         0 |         0 |         0 |         1 | 
             |     0.250 |    14.062 |     0.375 |     0.062 |     0.188 |     0.062 |           | 
             |     0.000 |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.062 | 
             |     0.000 |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |           | 
             |     0.000 |     0.062 |     0.000 |     0.000 |     0.000 |     0.000 |           | 
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
           2 |         0 |         0 |         6 |         0 |         0 |         0 |         6 | 
             |     1.500 |     0.375 |     6.250 |     0.375 |     1.125 |     0.375 |           | 
             |     0.000 |     0.000 |     1.000 |     0.000 |     0.000 |     0.000 |     0.375 | 
             |     0.000 |     0.000 |     1.000 |     0.000 |     0.000 |     0.000 |           | 
             |     0.000 |     0.000 |     0.375 |     0.000 |     0.000 |     0.000 |           | 
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
           3 |         0 |         0 |         0 |         1 |         0 |         0 |         1 | 
             |     0.250 |     0.062 |     0.375 |    14.062 |     0.188 |     0.062 |           | 
             |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.000 |     0.062 | 
             |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.000 |           | 
             |     0.000 |     0.000 |     0.000 |     0.062 |     0.000 |     0.000 |           | 
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
           4 |         0 |         0 |         0 |         0 |         3 |         0 |         3 | 
             |     0.750 |     0.188 |     1.125 |     0.188 |    10.562 |     0.188 |           | 
             |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.188 | 
             |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |           | 
             |     0.000 |     0.000 |     0.000 |     0.000 |     0.188 |     0.000 |           | 
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
           5 |         0 |         0 |         0 |         0 |         0 |         1 |         1 | 
             |     0.250 |     0.062 |     0.375 |     0.062 |     0.188 |    14.062 |           | 
             |     0.000 |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.062 | 
             |     0.000 |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |           | 
             |     0.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.062 |           | 
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
Column Total |         4 |         1 |         6 |         1 |         3 |         1 |        16 | 
             |     0.250 |     0.062 |     0.375 |     0.062 |     0.188 |     0.062 |           | 
-------------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|

 
      
test_f 0 1 2 3 4 5
     0 4 0 0 0 0 0
     1 0 1 0 0 0 0
     2 0 0 6 0 0 0
     3 0 0 0 1 0 0
     4 0 0 0 0 3 0
     5 0 0 0 0 0 1
Confusion Matrix and Statistics

      
test_f 0 1 2 3 4 5
     0 4 0 0 0 0 0
     1 0 1 0 0 0 0
     2 0 0 6 0 0 0
     3 0 0 0 1 0 0
     4 0 0 0 0 3 0
     5 0 0 0 0 0 1

Overall Statistics
                                     
               Accuracy : 1          
                 95% CI : (0.7941, 1)
    No Information Rate : 0.375      
    P-Value [Acc > NIR] : 1.529e-07  
                                     
                  Kappa : 1          
                                     
 Mcnemar's Test P-Value : NA         

Statistics by Class:

                     Class: 0 Class: 1 Class: 2 Class: 3 Class: 4 Class: 5
Sensitivity              1.00   1.0000    1.000   1.0000   1.0000   1.0000
Specificity              1.00   1.0000    1.000   1.0000   1.0000   1.0000
Pos Pred Value           1.00   1.0000    1.000   1.0000   1.0000   1.0000
Neg Pred Value           1.00   1.0000    1.000   1.0000   1.0000   1.0000
Prevalence               0.25   0.0625    0.375   0.0625   0.1875   0.0625
Detection Rate           0.25   0.0625    0.375   0.0625   0.1875   0.0625
Detection Prevalence     0.25   0.0625    0.375   0.0625   0.1875   0.0625
Balanced Accuracy        1.00   1.0000    1.000   1.0000   1.0000   1.0000
[1] "Установлено, что точность 1 теста= 1"
[1] "Установлено, что точность 2 теста= 1"
In [ ]:
# КРИВАЯ ОБУЧЕНИЯ monmlp
options(warn=-1)
library(openxlsx)
library(e1071) # naiveBayes
library(caTools)
library(MASS)
library(class)
library(gmodels)
library(openxlsx)
library(caret)
library(ggplot2) 
library(GGally)
library(psych)
library(neuralnet)
library(monmlp) 
require(ggplot2)
library(ggthemes)

#ЗАГРУЗКА ИЗ EXSEL ПЕРВИЧНЫХ ДАННЫХ
N1=6 # номер листа с данными
x1 <-read.xlsx("REG_RU_03.xlsx", sheet = N1)
#x
xreg <-data.frame(X1=x1$PI_N,X2=x1$Pcx_N,X3=x1$PP_N,Class=x1$Claster)

xreg_f <-xreg[,'Class']

xregSum =xreg[,'X1']+xreg[,'X2']+xreg[,'X3']
xreg[,'X1']=xreg[,'X1']/xregSum
xreg[,'X2']=xreg[,'X2']/xregSum
xreg[,'X3']=xreg[,'X3']/xregSum

xstr_nor <-xreg[,1:3]
xstr_nor <-cbind(xstr_nor,xreg_f)
xstr_nor <-cbind(x1$Name,xstr_nor)


# ПОСТРОЕНИЕ КРИВОЙ ОБУЧЕНИЯ
N=100 # объем вариаций на каждом уровне train
accurdf <- matrix(0, ncol = 8, nrow = N)## Создать нулевую матрицу 
i=0
for (sr in seq(from=0.2, to=0.9, by=0.1)) 
{
i=i+1 
   
for (j in 1:N)
{
split <- sample.split(xstr_nor, SplitRatio = sr)
train_cl <- subset(xstr_nor , split == "TRUE")
test_cl <- subset(xstr_nor, split == "FALSE")
x= as.matrix(train_cl[,2:4])
y= as.matrix(train_cl[,5])
Xtest=as.matrix(test_cl[,2:4])
nc=1
# Подгонка наивной nn модели к набору обучающих данных
# Fit the model and compute the predictions 
r <- monmlp.fit(x, y, hidden1=5,hidden2 =2, n.ensemble=nc,iter.max = 1000,scale.y=FALSE,max.exceptions = 0,
method = 'L-BFGS-B',silent = TRUE) 

z <- monmlp.predict(x = Xtest, weights = r) 
Pred=as.integer(round(z, digits = 0))
Test = as.integer(test_cl$xreg_f)
Resul<-data.frame(Name=test_cl[,1],ResPred=Pred,ResTest=Test)
#print(Resul)
#оценка точности
k=0
for(l in 1:length(Resul[,3])){
if (Resul[l,2]==Resul[l,3]){k=k+1} 
}    
accuracy= k/length(Resul[,3])
accuracy=round(accuracy, digits = 2)  
accurdf[j,i]=accuracy 
}
} 
ASSdf<-data.frame(accuracy=accurdf)

# График
meandf <-rep(0, times= 8 )
dovint1df <-rep(0, times= 8 )
dovint2df <-rep(0, times= 8 )

for (i in seq(from=1, to=8, by=1))
{    
meandf[i]=mean(ASSdf[,i])
model <- lm(ASSdf[,i] ~ 1 )
dovint=confint(model, level=0.95)
dovint1df[i]=dovint[1]
dovint2df[i]=dovint[2]
}    
ASS_PARdf =data.frame(train_N=seq(from=0.2, to=0.9, by=0.1),accmean=meandf,dovint2_5=dovint1df,dovint97_5=dovint2df)
options(repr.plot.width = 18, repr.plot.height =10)
theme_update(text = element_text(size=20))
g4 <-ggplot(data=ASS_PARdf, aes(x=train_N),
colors = "Accent")
g4 <-g4 +geom_point(aes(y=accmean),size=5)
g4 <-g4 +geom_line( aes(y=accmean,colour='accmean'),linetype=1,size=2)
g4 <-g4 +geom_line(aes(y=dovint2_5,colour='dovint2_5'),linetype=2,size=1)
g4 <-g4 +geom_line(aes(y=dovint97_5,colour='dovint97_5'),linetype=2,size=1,)
g4 <-g4+scale_colour_manual("Среднее и дов.инт.", 
                      breaks = c("accmean", "dovint2_5", "dovint97_5"),
                      values = c("blue", "red", "green"))
g4 <-g4 +labs(title =" График зависимости средней точности на test от доли train (monmlp,N=100) с доверительным интервалом",
x="Доля train", y="Средняя точность классификации на тесте")
g4  <-g4+theme(axis.text = element_text(size = 16, angle=0,face = "plain")) 
g4  <-g4+theme(plot.title = element_text(size = 22,face = "plain"))
g4  <-g4+theme( axis.title = element_text(size = 18,face = "plain"))
g4

LC monmlp