Оптимизация: поиск весов | Вводный курс ML

Оптимизация: поиск весов

Все курсы > Вводный курс > Занятие 11

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

Больше тянуть нельзя. Продолжим с примером модели регрессии. Напомню, какую модель мы построили на прошлом занятии.

пример линейной регрессии: зависимость обхвата шеи от роста

Алгебраически уравнение, задающее линию, выглядит следующим образом:

$$ y = 26.86x-10.57 $$

Посмотрим, как были найдены веса 26.86 и −10.57.

Вначале откроем ноутбук к этому занятию

Функция потерь

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

MSE

Средняя сумма этих расстояний для всех точек равна:

$$ средняя\spaceсумма\spaceрасстояний = \frac {\sum^{n}_{i=1} (y_i-\hat{y}_i) ^2} {n} $$

Мы возвели расстояния в квадрат для того, чтобы избавиться от отрицательных значений. Например, в случае y2 − ŷ2, мы получим отрицательное значение, так как y2 < ŷ2. Если затем сложить это расстояние с положительным расстоянием y1 − ŷ1, то отрицательное и положительное значения взаимно сократятся, и мы получим некорректную среднюю сумму расстояний.

В целом, такое выражение называется функцией потерь (loss или cost function). Считайте, что оно показывает, сколько мы «теряем» из-за невозможности провести прямую ровно через каждую из точек.

Очевидно, лучше «терять» как можно меньше. Значит, задача сводится к поиску минимума функции потерь или ее оптимизации.

Раздел математики, занимающийся поиском минимума функции, называется теорией оптимизации (Optimization Theory).

Как найти минимум функции

Можно использовать компьютер. Он будет поочередно подставлять разные w и e до тех пор, пока функция потерь не выдаст наименьшее значение.

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

различные положения линии регрессии

то (2) постепенно изменяем потерю (еще говорят ошибку, error).

оптимизация функции: постепенное снижение потери (ошибки)

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

То, что на втором графике ошибка неуклонно уменьшается, не просто случайность, веса изменяются согласно определенной логике.

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

Создание модели на Питоне с помощью библиотеки Scikit-learn

На прошлом занятии мы построили нашу прямую, проходящую через данные, с помощью несложной функции polyfit библиотеки Numpy. Теперь воспользуемся библиотекой Scikit-learn. Она даст нам большую свободу в выборе, обучении и оценке качества моделей.

Для начала вновь возьмем данные роста и обхвата шеи. Только теперь запишем рост в переменную X, а обхват шеи в переменную y (таким образом, сразу становится понятно, что является независимой переменной, а что — зависимой).

Теперь подготовим этим данные. Scikit-learn принимает данные X (т.е. независимые переменные, признаки) в формате, так называемого, двумерного массива. Пока я просто покажу код, без детальных объяснений. На последующих курсах мы внимательно его разберем.

Импортируем необходимые модули и создадим объект класса линейной регрессии.

Обучим нашу модель. Другими словами, построим нашу прямую таким образом, чтобы минимизировать функцию ошибки. Для этого в библиотеке Scikit-learn используется метод .fit().

Выведем веса нашей модели:

Новые веса, а значит и уравнение идентичны найденным на прошлом занятии.

$$ y = 26.86x-10.57 $$

Это логично, мы использовали одни и те же данные, и одну и ту же функцию потерь для построения модели.

Рассчитаем прогнозные значения, соответствующие нашим исходным данным (X), т.е. найдем значения ŷi. Для этого используем метод .predict().

Выведем для примера первые пять значений (в этом случае вместо индекса указывается диапазон индексов [от : до, но не включая], например, [ : 5] выведет элемент с нулевого по четвертый).

В целом похоже на то, что мы делали в прошлый раз.

Однако библиотека Scikit-learn позволяет нам также вывести уровень потери или ошибку, которую метод .fit() стремился минимизировать. Этот уровень правильнее называть среднеквадратической ошибкой (Mean Squared Error, MSE). Выведем ее:

Чтобы избавиться от квадрата в вычислениях, возьмем квадратный корень из нашей метрики (Root Mean Squared Error, RMSE).

Для того чтобы оценить много это или мало, мы можем сравнить RMSE со средним арифметическим наших исходных данных обхвата шеи.

Как мы видим, RMSE чрезвычайно мал по сравнению со средним значением обхвата шеи (0,48 против 33,1). Т.е. расстояние от предсказанных точек до прямой действительно минимально.

Алгоритм линейной регрессии неплохо потрудился.

На всякий случай, еще раз уточним термины: функция потерь или ошибка по-русски, и loss function, cost function, error function или, как еще говорят, objective function по-английски — это одно и то же.

Подведем итог

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

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

Вопросы для закрепления

Как называется функция, с помощью которой мы находим оптимальные веса в уравнении (исходной модели)?

Ответ: функция потерь (loss function).

Какие метрики (критерии) качества модели линейной регрессии мы уже знаем?

Ответ: (1) средняя квадратическая ошибка (Mean Squared Error, MSE), средняя сумма расстояний от прямой до данных и (2) корень средней квадратической ошибки (Root Mean Squared Error, RMSE)

Дополнительные упражнения⧉ вы найдете в конце ноутбука.

Чего не хватает

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

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


Ответы на вопросы

Вопрос. В модели линейной регрессии на видео вы используете два двумерных массива для X и для y, а в коде двумерным становится только массив признаков (Х), как правильно?

Ответ. Можно и так, и так. Код, который я использую на видео правильный, но избыточный. Для целевой переменной y достаточно одномерного массива, признакам (X) всегда нужен двумерный массив.

В целом, забегая немного вперед, скажу, что моделям в sklearn можно передавать:

  • массивы Numpy (Numpy arrays, 1D и 2D)
  • разреженные матрицы (sparse matrices)
  • датафреймы (в формате DataFrame для X и Series для y)

Вопрос. Возник такой вопрос: в 10 занятии для подбора коэффициентов линии регрессии, которая описывает взаимосвязь роста и окружности шеи, в качестве функции потерь использовалась сумма отклонений прогноза от факта. В этом занятии — сумма квадратов отклонений. Но коэффициенты получились одинаковые. Разве не должны они получится разными?

Ответ. На самом деле, как видно из документации, и функция polyfit()⧉ библиотеки Numpy, которую мы использовали на десятом занятии, и класс LinearRegression⧉ библиотеки sklearn из одиннадцатого занятия минимизируют именно сумму квадратов отклонений прогноза от факта. Так как их алгоритм (для линейной модели) идентичен, то и коэффициенты получились одинаковыми.

На десятом занятии я опять же сознательно не упомянул, что речь идет о квадрате отклонений, потому что не хотел слишком усложнять материал. Более того, «под капотом» и функция polyfit(), и класс LinearRegression используют метод наименьших квадратов (МНК, Least Squares), я же подвожу к алгоритму оптимизации, который называется градиентным спуском (Gradient Descent). Это еще одна сознательная неточность.

Метод наименьших квадратов на этом этапе мне кажется довольно сложным и не интуитивным. Функцию polyfit() и класс LinearRegression я пока использовал как черный ящик, который получает данные и выдает коэффициенты/веса.

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

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

P.S. Также замечу, забегая немного вперед, что напрямую использовать сумму отклонений прогноза от факта в качестве функции потерь мы в любом случае не можем. Если для одного наблюдения отклонение составит 4, а для другого −4, их сумма (то есть общая ошибка) будет равна нулю, что по сути неверно, потому что оба наблюдения отклоняются от прогноза. Чтобы этого избежать, мы либо возводим отклонение в квадрат (Mean Squared Error), либо находим абсолютное значение/модуль отклонения (Mean Absolute Error). Графически это будет парабола и функция модуля соответственно.

MSE vs. MAE

Как у MAE, так и у MSE есть достоинства и недостатки, и их можно преодолеть, например, с помощью функции Хьюбера (Huber loss) и других более продвинутых функций потерь.