Азбука ИИ: «Машинное обучение»

Как вычислить вес человека и зачем для этого спускаться с гор

В рамках совместного с МФТИ проекта «Азбука ИИ» мы уже писали о так называемых эволюционных алгоритмах, которые позволяют «выращивать» программы по принципам и законам дарвиновской эволюции. Однако пока такой подход к искусственному интеллекту это, безусловно, «гость из будущего». Но как системы искусственного интеллекта создают сегодня? Как их обучают? В этом нам помог разобраться Виктор Кантор, старший преподаватель кафедры алгоритмов и технологий программирования МФТИ, руководитель группы анализа пользовательского поведения Yandex Data Factory.

Согласно недавнему отчету исследовательской компании Gartner, которая регулярно обновляет свой «цикл зрелости технологий», на сегодняшний день из всего IT на пике ожиданий находится именно машинное обучение. Это неудивительно: за последние несколько лет машинное обучение вышло из сферы интересов узкого круга математиков и специалистов по теории алгоритмов и проникло сначала в словарь IT-бизнесменов, а затем и в мир обывателей. Сейчас о том, что существует такая вещь, как нейросети с их особой «магией», знает любой, кто пользовался приложением Prisma, искал песни с помощью Shazam или видел изображения, прошедшие через DeepDream.

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

Как учатся машины

Для начала, чтобы разобраться с тем, как именно происходит машинное обучение, определимся с понятиями. По определению одного из пионеров этой области Артура Самуэля, к машинному обучению относятся методы, которые «позволяют компьютерам учиться без их непосредственного программирования». Существуют два обширных класса методов машинного обучения: обучение с учителем и обучение без учителя. Первое применяется тогда, когда нам, например, нужно научить компьютер искать фотографии с изображением котиков, второе — когда нам надо, чтобы машина, например, смогла самостоятельно группировать новости в сюжеты, как это происходит в сервисах вроде Яндекс.Новостей или Google News. То есть в первом случае мы имеем дело с задачей, которая подразумевает существование правильного ответа (кот на фото или есть, или нет), во втором — единственного правильного ответа нет, а есть разные способы решения задачи. Мы сосредоточимся именно на первом классе задач как на наиболее интересном.

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

Первое, что нам необходимо, чтобы сделать систему предсказания, это собрать так называемую обучающую выборку, то есть данные о весе людей в популяции. Второе — определиться с набором признаков, на основании которых мы можем делать выводы о весе. Понятно, что одним из самых «сильных» таких признаков будет рост человека, поэтому в первом приближении достаточно взять только его. Если вес зависит от роста линейно, то наше предсказание будет очень простым: вес человека будет равен его росту, умноженному на какой-то коэффициент, плюс какая-то постоянная величина, что записывается простейшей формулой y=kx+b. Все, что нам нужно сделать, чтобы обучить машину предсказывать вес человека, это как-то найти правильные величины k и b.

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

Допустим, на вес человека его рост влияет не линейно, а в третьей степени (что вообще-то говоря ожидаемо, ведь вес зависит от объема тела). Чтобы учесть эту зависимость, мы просто вносим в наше уравнение еще один член, а именно третью степень роста с собственным коэффициентом, получая при этом y=k1x+k2x3+b. Теперь, чтобы обучить машину, нам нужно будет найти не две, а три величины (k1, k2 и b). Допустим, мы хотим в нашем предсказании учитывать еще и размер обуви человека, его возраст, время, проведенное им у телевизора, и расстояние от его квартиры до ближайшей точки фаст-фуда. Никаких проблем: мы просто вносим эти признаки как отдельные члены в то же самое уравнение.

Самое главное — создать универсальный способ находить нужные коэффициенты (k1, k2, … kn ). Если он есть, нам будет почти безразлично, какие использовать признаки для предсказания, ведь машина сама обучится придавать большой вес важным, и маленький — неважным признакам. К счастью, такой метод уже придуман и на нем успешно работает почти все машинное обучение: от простейших линейных моделей до систем распознавания лиц и анализаторов речи. Называется этот метод градиентным спуском. Но прежде чем объяснить, как он работает, надо сделать небольшое отступление и рассказать про нейросети.

Нейросети

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

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

Поясним на примере. Мы остановились на предсказании, в котором вес человека зависит от его роста и роста в кубе, что выражается формулой y=k1x+k2x3+b. С некоторой натяжкой, но фактически даже такую формулу можно назвать нейросетью. В ней, как и в обычной нейросети, есть первый слой «нейронов», он же слой признаков: это x и x3 ( ну и «единичный нейрон», который мы держим в уме и за который отвечает коэффициент b). Верхний, или результирующий, слой представлен одним «нейроном» y, то есть предсказанным весом человека. А между первым и последним слоем «нейронов» есть связи, сила или вес которых определяется коэффициентами k1, k2 и b. Обучить эту «нейросеть» означает просто найти эти самые коэффициенты. 

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

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

Итак, мы имеем обучающую выборку примеров с известными данными, то есть таблицу с точно измеренным весом человека, и некоторую гипотезу зависимости, в данном случае линейную регрессию y=kx+b. Наша задача заключается в том, чтобы найти правильные величины k и b, причем не вручную, а автоматически. И желательно, универсальным методом, который не зависит от количества параметров, включаемых в формулу.

Сделать это, в общем, несложно. Главная идея заключается в том, чтобы создать некую функцию, которая будет измерять текущий суммарный уровень ошибки и «подкручивать» коэффициенты таким образом, чтобы суммарный уровень ошибки постепенно падал. Как сделать, чтобы уровень ошибки падал? Нужно подкручивать наши параметры в нужную сторону.

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

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

Как можно найти эту точку? Самый правильный способ — двигаться все время вниз из той точки, где мы исходно оказались. Так рано или поздно мы придем в локальный минимум — точку, ниже которой в ближайшей окрестности ничего нет. Причем желательно делать шаги разного размера: когда уклон крутой, можно шагать шире, когда уклон небольшой, то лучше подкрадываться к локальному минимуму «на цыпочках», иначе можно и проскочить. 

Именно так работает метод градиентного спуска: мы меняем веса признаков в направлении наибольшего падения функции ошибки. Меняем их итерационно, то есть с неким шагом, величина которого пропорциональна крутизне уклона. Что интересно, при увеличении числа признаков (добавлении куба роста человека, его возраста, размера обуви и так далее) по сути ничего не меняется, просто наш ландшафт становится не двумерным, а многомерным.

Функцию ошибки можно определить как сумму квадратов всех отклонений, которые текущая формула допускает по отношению к людям, чей вес нам уже точно известен. Возьмем какие-то случайные величины k и b, например 0 и 50. Тогда система будет нам предсказывать, что вес каждого человека в выборке всегда равен 50 килограммам y=0×x+50 На графике такая зависимость будет выглядеть как прямая, параллельная горизонтали. Понятно, что это не очень хорошее предсказание. Теперь возьмем отклонение в весе от этого предсказанного значения, возведем ее в квадрат (чтобы отрицательные значения тоже учитывались) и просуммируем — это и будет ошибка в данной точке. Если вам знакомы начала анализа, то можно даже уточнить, что направление наибольшего падения задается частной производной функции ошибки по k и b, а шаг — это величина, которая выбирается из практических соображений: мелкие шаги занимают много времени на вычисления, а большие могут привести к тому, что мы проскочим мимо минимума.

Хорошо, а если у нас не просто сложная регрессия с множеством признаков, а настоящая нейросеть? Как нам применить градиентный спуск в таком случае? Оказывается, что и с нейросетью градиентный спуск работает точно так же, только обучение происходит 1) поэтапно, от слоя к слою и 2) постепенно, от одного примера в выборке к другому. Метод, который здесь применяется, называется алгоритмом обратного распространения ошибки, он был независимо описан в 1974 году советским математиком Александром Галушкиным и математиком из Гарвардского университета Полом Джоном Вебросом (Paul John Webros).

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

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

Трудности градиентного спуска

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

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

Неправильный выбор шага. Метод градиентного спуска — итерационный метод. То есть нам самим нужно выбрать величину шага — скорость, с которой мы спускаемся. Выбрав слишком большой шаг, мы можем пролететь мимо нужного нам экстремума и не найти минимума. Это может произойти, если вы окажетесь перед очень резким спуском. А выбор слишком маленького шага грозит крайне медленной работой алгоритма, если мы окажемся на относительно ровной поверхности. Если снова представить, что мы находимся на вершине отвесной горы, то может получиться ситуация, когда из-за очень крутого спуска вблизи минимума мы его просто пролетим.

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

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

Подготовил Александр Ершов

Нашли опечатку? Выделите фрагмент и нажмите Ctrl+Enter.