Краткий курс машинного обучения или как создать нейронную сеть для решения скоринг задачи
Мы часто слышим такие словесные конструкции, как «машинное обучение», «нейронные сети». Эти выражения уже плотно вошли в общественное сознание и чаще всего ассоциируются с распознаванием образов и речи, с генерацией человекоподобного текста. На самом деле алгоритмы машинного обучения могут решать множество различных типов задач, в том числе помогать малому бизнесу, интернет-изданию, да чему угодно. В этой статье я расскажу как создать нейросеть, которая способна решить реальную бизнес-задачу по созданию скоринговой модели. Мы рассмотрим все этапы: от подготовки данных до создания модели и оценки ее качества.
Вопросы, которые разобраны в статье:
• Как собрать и подготовить данные для построения модели? • Что такое нейронная сеть и как она устроена? • Как написать свою нейронную сеть с нуля? • Как правильно обучить нейронную сеть на имеющихся данных? • Как интерпретировать модель и ее результаты? • Как корректно оценить качество модели?
Во многих компаниях, менеджеры по продажам общаются с потенциальными клиентами, проводят им демонстрации, рассказывают о продукте. Отдают, так сказать, свою душу по сотому разу на растерзание тем, кто, возможно, попал в их руки совершенно случайно. Часто клиенты недостаточно понимают, что им нужно, или то, что продукт может им дать. Общение с такими клиентами не приносит ни удовольствия, ни прибыли. А самое неприятное то, что из-за ограничения по времени, можно не уделить достаточно внимания действительно важному клиенту и упустить сделку.
Я математик-программист в сервисе seo-аналитики Serpstat. Недавно я получил интересную задачу по улучшению уже существующей и работающей у нас скоринговой модели, по-новому оценив факторы, которые влияют на успех продажи. Скоринг считался на основе анкетирования наших клиентов, и каждый пункт, в зависимости от ответа на вопрос, вносил определенное количество очков в суммарный балл. Все эти баллы за разные вопросы расставлялись на основе статистических гипотез. Скоринговая модель использовалась, время шло, данные собирались и в один прекрасный день попали ко мне. Теперь, когда у меня появилась достаточная выборка, можно было смело строить гипотезы, используя алгоритмы машинного обучения.
Я расскажу вам, как мы построили свою скоринг модель. Это реальный кейс с реальными данными, со всеми трудностями и ограничениями, с которыми мы столкнулись в реальном бизнесе. Итак, обо всем по порядку.
Мы подробно остановимся на всех этапах работы:
▸ Сбор данных ▸ Препроцессинг ▸ Построение модели ▸ Анализ качества и интерпретация модели
Рассмотрим устройство, создание и обучение нейросети. Все это я описываю, решая реальную скоринговую задачу, и постоянно подкрепляю новую теорию примером.
Сбор данных
Вначале нужно понять, какие вопросы будут представлять клиента (или просто объект) в будущей модели. К задаче подходим серьезно, так как на ее основании строится дальнейший процесс. Во-первых, нужно не упустить важные признаки, описывающие объект, во-вторых, создать жесткие критерии для принятия решения о признаке. Основываясь на опыте, я могу выделить три категории вопросов:
- Булевы (бикатегориальные), ответом на которые является: Да или Нет (1 или 0). Например, ответ на вопрос: есть ли у клиента аккаунт?
- Категориальные, ответом на которые является конкретный класс. Обычно классов больше двух (мультикатегориальные), иначе вопрос можно свести к булевому. Например, цвет: красный, зеленый или синий.
- Количественные, ответами на которые являются числа, характеризующее конкретную меру. Например, количество обращений в месяц: пятнадцать.
Данные должны иметь следующую классическую структуру: вектор признаков для каждого i-го клиента X (i) = и класс Y (i) — категория, показывающая купил он или нет. Например: клиент (3) = — купил.
Основываясь на вышесказанном, попробуем представить формат данных с типами вопросов, для дальнейшей подготовки:
класс: (категория) цвет: (категория) вкус: (категория) вес: (число) твердый: (bool) - красный кислый 4.23 да - зеленый горький 3.15 нет + зеленый горький 4.14 да + синий сладкий 4.38 нет - зеленый соленый 3.62 нетТаблица 1 — Пример данных обучающей выборки до препроцессинга
Препроцессинг
После того как данные собраны, их необходимо подготовить. Этот этап называется препроцессинг. Основная задача препроцессинга — отображение данных в формат пригодный для обучения модели. Можно выделить три основных манипуляции над данными на этапе препроцессинга:
-
Создание векторного пространства признаков, где будут жить примеры обучающей выборки. По сути, это процесс приведения всех данных в числовую форму. Это избавляет нас от категорийных, булевых и прочих не числовых типов. Процесс, при котором мы добиваемся, например того, чтобы среднее значение каждого признака по всем данным было нулевым, а дисперсия — единичной. Вот самый классический пример нормализации данных: X = (X — μ)/σ
- Для повышения размерности можно использовать часть обучающей выборки как опорные точки, добавив в вектор признаков расстояние до этих точек. Этот метод часто приводит к тому, что в пространствах более высокой размерности множества становятся линейно разделимыми, и это упрощает задачу классификации.
- Для понижения размерности чаще всего используют PCA. Основная задача метода главных компонент — поиск новых линейных комбинаций признаков, вдоль которых максимизируется дисперсия значений проекций элементов обучающей выборки.
Например, элемент выборки может быть или горьким, или сладким, или соленым, или кислым, или умами (мясным). Тогда One-Hot кодировка будет следующей: горький = (1, 0, 0, 0 ,0), сладкий = (0, 1, 0, 0 ,0), соленый = (0, 0, 1, 0 ,0), кислый = (0, 0, 0, 1 ,0), умами = (0, 0, 0, 0, 1). Если у вас возник вопрос почему вкусов пять, а не четыре, то ознакомьтесь с этой статьей о вкусовой сенсорной системе, ну а к скорингу это никакого отношения не имеет, и мы будем использовать четыре, ограничившись старой классификацией.
Теперь мы научились превращать категориальные признаки в обычные числовые вектора, а это очень полезно. Проведя все манипуляции над данными, мы получим обучающую выборку, подходящую любой модели. В нашем случае, после применения унитарной кодировки и нормализации данные выглядят так:
class: red: green: blue: bitter: sweet: salti: sour: weight: solid: 0 1 0 0 0 0 0 1 0.23 1 0 0 1 0 1 0 0 0 -0.85 0 1 0 1 0 1 0 0 0 0.14 1 1 0 0 1 0 1 0 0 0.38 0 0 0 1 0 0 0 1 0 -0.48 0Таблица 2 — Пример данных обучающей выборки после препроцессинга
Можно сказать, что препроцессинг — это процесс отображения понятных нам данных в менее удобную для человека, но зато в излюбленную машинами форму.
Формула скоринга чаще всего представляет из себя следующую линейную модель:
Где, k — это номер вопроса в анкете, wk — коэффициент вклада ответа на этот k-ый вопрос в суммарный скоринг, |w| — количество вопросов (или коэффициентов), xk — ответ на этот вопрос. При этом вопросы могут быть любыми, как мы и обсуждали: булевыми(да или нет, 1 или 0), числовыми (например, рост = 175) или категориальными, но представленными в виде унитарной кодировки (зеленый из перечня: красный, зеленый или синий = [0, 1, 0]). При этом можно считать, что категориальные вопросы распадаются на столько булевых, сколько категорий присутствует в вариантах ответа (например: клиент красный? клиент зеленый? клиент синий?).
Выбор модели
Теперь самое важное: выбор модели. На сегодняшний день существует множество алгоритмов машинного обучения, на основе которых можно построить скоринг модель: Decision Tree (дерево принятия решений), KNN (метод k-ближайших соседей), SVM (метод опорных векторов), NN (нейросеть). И выбор модели стоит основывать на том, чего мы от нее хотим. Во-первых, насколько решения, повлиявшие на результаты модели, должны быть понятными. Другими словами, насколько нам важно иметь возможность интерпретировать структуру модели.
Рис. 1 — Зависимость гибкости алгоритма машинного обучения и интерпретируемости полученной модели
Кроме того, не все модели легко построить, для некоторых требуются весьма специфические навыки и очень-очень мощное железо. Но самое важное — это внедрение построенной модели. Бывает так, что бизнес-процесс уже налажен, и внедрение какой-то сложной модели попросту невозможно. Или требуется именно линейная модель, в которой клиенты, отвечая на вопросы, получают положительные или отрицательные баллы в зависимости от варианта ответа. Иногда, напротив, есть возможность внедрения, и даже требуется сложная модель, учитывающая очень неочевидные сочетания входных параметров, находящая взаимосвязи между ними. Итак, что же выбрать?
В выборе алгоритма машинного обучения мы остановились на нейронной сети. Почему? Во-первых, сейчас существует много крутых фреймворков, таких как TensorFlow, Theano. Они дают возможность очень глубоко и серьезно настраивать архитектуру и параметры обучения. Во-вторых, возможность менять устройство модели от однослойной нейронной сети, которая, кстати, неплохо интерпретируема, до многослойной, обладающей отличной способностью находить нелинейные зависимости, меняя при этом всего пару строчек кода. К тому же, обученную однослойную нейросеть можно превратить в классическую аддитивную скоринг модель, складывающую баллы за ответы на разные вопросы анкетирования, но об этом чуть позже.
Теперь немного теории. Если для вас такие вещи, как нейрон, функция активации, функция потери, градиентный спуск и метод обратного распространения ошибки — родные слова, то можете смело это все пропускать. Если нет, добро пожаловать в краткий курс искусственных нейросетей.
Краткий курс искусственных нейронных сетей
Начнем с того, что искусственные нейронные сети (ИНС) — это математические модели организации реальных биологических нейронных сетей (БНС). Но в отличие от математических моделей БНС, ИНС не требует точное описание всех химических и физических процессов, таких как описание «поджигания» потенциала действия (ПД), работы нейромедиаторов, ионных каналов, вторичных посредников, белков транспортеров и пр. От ИНС требуется схожесть с работой реальных БНС только на функциональном, а не на физическом уровне.
Базовый элемент нейросети — нейрон. Попробуем составить самую простую функциональную математическую модель нейрона. Для этого опишем в общих чертах функционирование биологического нейрона.
Рис. 2 — Типичная структура биологического нейрона
Как мы видим, структуру биологического нейрона можно упростить до следующей: дендриты, тело нейрона и аксон. Дендриты — ветвящиеся отростки, собирающие информацию со входа в нейрон (это может быть внешняя информация с рецепторов, например с колбочки в случае цвета или внутренняя информация от другого нейрона). В том случае, если входящая информация активировала нейрон (в биологическом случае — потенциал стал выше какого-то порога), рождается волна возбуждения (ПД), которая распространяется по мембране тела нейрона, а затем через аксон, посредством выброса нейромедиатора, передает сигнал другим нервным клетками или тканям.
Основываясь на этом, Уоррен Мак-Каллок и Уолтер Питтс в 1943 году предложили модель математического нейрона. А в 1958 году Френк Розенблатт на основе нейрона Мак-Каллока-Питтса создал компьютерную программу, а затем и физическое устройство — перцептрон. С этого и началась история искусственных нейронных сетей. Теперь рассмотрим структурную модель нейрона, с которым мы будем иметь дело дальше.
Рис. 3 — Модель математического нейрона Мак-Каллока-Питтса
- X — входной вектор параметров. Вектор (столбец) чисел (биол. степень активации разных рецепторов), пришедших на вход нейрону. W — вектор весов (в общем случае — матрица весов), числовые значение, которые меняются в процессе обучения (биол. обучение на основе синаптической пластичности, нейрон учится правильно реагировать на сигналы с его рецепторов).
- Сумматор — функциональный блок нейрона, который складывает все входные параметры умноженные на соответствующие им веса.
- Функция активации нейрона — есть зависимость значения выхода нейрона от значения пришедшего от сумматора.
- Следующие нейроны, куда на один из множества их собственных входов подается значение с выхода данного нейрона (этот слой может отсутствовать, если этот нейрон последний, терминальный).
Затем из этих минимальных структурных единиц собирают классические искусственные нейронные сети. Принята следующая терминология:
- Входной (рецепторный) слой — это вектор параметров (признаков). Этот слой не состоит из нейронов. Можно сказать, что это цифровая информация, снятая рецепторами из «внешнего» мира. В нашем случае это информация о клиенте. Слой содержит столько элементов, сколько входных параметров (плюс bias-term нужный для сдвига порога активации).
- Ассоциативный (скрытый) слой — глубинная структура, способная к запоминанию примеров, нахождению сложных корреляций и нелинейных зависимостей, к построению абстракций и обобщений. В общем случае это даже не слой, а множество слоев между входными и выходными. Можно сказать, что каждый слой подготавливает новый (более высокоуровневый) вектор признаков для следующего слоя. Именно этот слой отвечает за появление в процессе обучения высокоуровневых абстракций. Структура содержит столько нейронов и слоев, сколько душе угодно, а может и вообще отсутствовать (в случае классификации линейно разделимых множеств).
- Выходной слой — это слой, каждый нейрон которого отвечает за конкретный класс. Выход этого слоя можно интерпретировать как функцию распределения вероятности принадлежности объекта разным классам. Слой содержит столько нейронов, сколько классов представлено в обучающей выборке. Если класса два, то можно использовать два выходных нейрона или ограничиться всего одним. В таком случае один нейрон по-прежнему отвечает только за один класс, но если он выдает значения близкие к нулю, то элемент выборки по его логике должен принадлежать другому классу.
Рис. 4 — Классическая топология нейросети, со входным (рецепторным), выходным, принимающим решение о классе, и ассоциативным (скрытым) слоем
Именно благодаря наличию скрытых ассоциативных слоев, искусственная нейронная сеть способна строить гипотезы, основанные на нахождении сложных зависимостей. Например, для сверточных нейросетей, распознающих изображения, на входной слой будут подаваться значения яркости пикселей изображения, а выходной слой будет содержать нейроны, отвечающие за конкретные классы (человек, машина, дерево, дом и т. д.) В процессе обучения в близких к «рецепторам» скрытых слоях начнут «сами собой» появляться (специализироваться) нейроны, возбуждающиеся от прямых линий, разного угла наклона, затем реагирующие на углы, квадраты, окружности, примитивные паттерны: чередующиеся полоски, геометрические сетчатые орнаменты. Ближе к выходным слоям — нейроны, реагирующие, например, на глаз, колесо, нос, крыло, лист, лицо и т. д.
Рис. 5 — Образование иерархических ассоциаций в процессе обучения сверточной нейронной сети
Проводя биологическую аналогию, хочется сослаться на слова замечательного нейрофизиолога Вячеслава Альбертовича Дубынина, касающиеся речевой модели:
Много теории?! Но есть и хорошие новости: в самом простом случае вся нейросеть может быть представлена одним единственным нейроном! При этом даже один нейрон часто хорошо справляется с задачей, особенно, когда дело касается распознавания класса объекта в пространстве, в котором объекты этих классов являются линейно сепарабельными. Часто добиться линейно сепарабельности можно повысив размерность пространства, о чем было написано выше, и ограничиться всего одним нейроном. Но иногда проще добавить в нейросеть пару скрытых слоев и не требовать от выборки линейной сепарабельности.
Рис. 6 — Линейно разделимые множества и линейно неразделимые множества
Ну а теперь давайте опишем все это формально. На входе нейрона мы имеем вектор параметров. В нашем случае это результаты анкетирования клиента, представленные в числовой форме X (i) = . При этом каждому клиенту сопоставлен Y (i) — класс, характеризующий успешность лида (1 или 0). Нейросеть, по сути, должна найти оптимальную разделяющую гиперповерхность в векторном пространстве, размерность которого соответствует количеству признаков. Обучение нейронной сети в таком случае — нахождение таких значений (коэффициентов) матрицы весов W, при которых нейрон, отвечающий за класс, будет выдавать значения близкие к единице в тех случаях, если клиент купит, и значения близкие к нулю, если нет.
Как видно из формулы, результат работы нейрона — это функция активации (часто обозначаемая через ) от суммы произведения входных параметров на искомые в процессе обучения коэффициенты. Разберемся что же такое функция активации.
Так как на вход нейросети могут поступать любые действительные значения, и коэффициенты матрицы весов тоже могут быть какими угодно, то и результатом суммы их произведений может быть любое вещественное число от минус до плюс бесконечности. У каждого элемента обучающей выборки есть значение класса относительно этого нейрона (ноль или один). Желательно получить от нейрона значение в этом же диапазоне от нуля до единицы, и принять решение о классе, в зависимости от того, к чему это значение ближе. Еще лучше интерпретировать это значение как вероятность того, что элемент относится к этому классу. Значит, нам нужна такая монотонная гладкая функция, которая будет отображать элементы из множества вещественных чисел в область от нуля до единицы. На эту должность отлично подходит так называемая сигмоида.
Рис. 7 — График логистической кривой, одной из самых классических представительниц класса сигмоид
Кстати, в реальных биологических нейронах такая непрерывная функция активации не реализовалась. В наших с вами клетках существует потенциал покоя, который составляет в среднем -70mV. Если на нейрон подается информация, то активированный рецептор, открывает сопряженные с ним ионные каналы, что приводит к повышению или понижению потенциала в клетке. Можно провести аналогию между силой реакции на активацию рецептора и полученным в процессе обучения одним коэффициентом матрицы весов. Как только потенциал достигает значения в -50mV, возникает ПД, и волна возбуждения доходит по аксону до пресинаптического окончания, выбрасывая нейромедиатор в межсинаптическую среду. То есть реальная биологическая активация — ступенчатая, а не гладкая: нейрон либо активировался, либо нет. Это показывает, насколько мы математически свободны в построении наших моделей. Взяв у природы основной принцип распределенного вычисления и обучения, мы способны построить вычислительный граф, состоящий из элементов, обладающих любыми желаемыми свойствами. В нашем примере мы желаем получать от нейрона континуальные, а не дискретные значения. Хотя в общем случае функция активации может быть и другой.
Вот самое важное, что стоит извлечь из написанного выше: «Обучение нейросети (синаптическое обучение) должно свестись к оптимальному подбору коэффициентов матрицы весов с целью минимизации допускаемой ошибки.» В случае однослойной нейросети эти коэффициенты можно интерпретировать как вклад параметров элемента в вероятность принадлежности к конкретному классу.
Результат работы нейросети принято называть гипотезой (англ. hypothesis). Обозначают через h(X), показывая зависимость гипотезы от входных признаков (параметров) объекта. Почему гипотезой? Так уж исторически сложилось. Лично мне этот термин нравится. В итоге мы хотим, чтобы гипотезы нейросети как можно больше соответствовали действительности (реальным классам объектов). Собственно здесь и рождается основная идея обучения на опыте. Теперь нам потребуется мера, описывающая качество нейросети. Этот функционал обычно называют «функцией потерь» (англ. loss function). Функционал обычно обозначают через J(W), показывая его зависимость от коэффициентов матрицы весов. Чем функционал меньше, тем реже наша нейросеть ошибается и тем это лучше. Именно к минимизации этого функционала и сводится обучение. В зависимости от коэффициентов матрицы весов нейросеть может иметь разную точность. Процесс обучения — это движение по гиперповерхности функционала потери, целью которого является минимизация этого функционала.
Рис. 8 — Процесс обучения, как градиентный спуск к локальному минимуму функционала потери
Обычно коэффициенты матрицы весов инициализируются случайным образом. В процессе обучения коэффициенты меняются. На графике показаны два разных итерационных пути обучения как изменение коэффициентов w1 и w2 матрицы весов нейросети, проинициализированных в соседстве.
Теперь собственно о том, как обучить нейросеть. Для этого существует множество вариантов, но я расскажу о двух: эволюционный (генетический) алгоритм и метод градиентного спуска. Эволюционные алгоритмы — это направление в искусственном интеллекте, которое основывается на моделировании естественного отбора. Раньше такой подход использовался для тренировки глубинных слоев нейросети. Эволюционные алгоритмы полностью уступили свое место оптимизаторам на основе градиентного спуска для задачи обучения глубох нейронных сетей, но они по-прежнему могут использоваться для образовательных целей: эволюционные алгоритмы очень просты в понимании, и с них лучше начинать новичкам, их стоит знать для дальнейшего сравнения вычислительной сложности и сходимости с другими (популярными ныне) методами. Метод градиентного спуска и обратного распространения ошибки более сложный, но зато один из самых эффективных и популярных методов обучения, наследниками которого являются популярные сейчас NAG, Adagrad, Adadelta, RMSprop, Adam, Nadam и т.д.
Эволюционное обучениеВ рамках этого метода оперируем следующей терминологией: коэффициенты матрицы весов — геном, один коэффициент — ген, «перевернутая вниз головой» функция потерь — ландшафт приспособленности (тут мы уже ищем локальный максимум, но это всего лишь условность). Этот метод и вправду очень простой. После того как мы выбрали топологию (устройство) нейросети, необходимо сделать следующее:
-
Проинициализировать геном (матрицу весов) случайным образом в диапазоне от -1 до 1. Повторить это несколько раз, тем самым создав начальную популяцию разных, но случайных нейросетей. Размер популяции обозначим через P — population or parents.