Когда вы решаетесь заняться машинным обучением, одним из фундаментальных аспектов вашего обучения будет понимание «градиентного спуска». Градиентный спуск - это основа алгоритма машинного обучения. В этой статье я попытаюсь объяснить основы градиентного спуска с использованием кода Python. Как только вы овладеете градиентным спуском, все станет более ясным и станет легче понять различные алгоритмы. По этой теме уже написано много, поэтому он не будет новаторским. Чтобы продолжить и построить свой собственный градиентный спуск, вам понадобятся несколько базовых пакетов Python, а именно. numpy и matplotlib для визуализации.

Давайте начнем с некоторых данных, а лучше давайте создадим некоторые данные. Мы создадим линейные данные с некоторым случайным гауссовским шумом.

X = 2 * np.random.rand (100,1)
y = 4 +3 * X + np.random.randn (100,1)

Теперь давайте визуализируем данные

Очевидно, что Y имеет хорошую линейную связь с X. Эти данные очень простые и имеют только одну независимую переменную X.

Вы можете учиться на уровне колледжа, что линия может быть выражена как

Затем вы можете решить уравнение для b и m следующим образом:

Это называется аналитическим методом решения уравнения. В этом нет ничего плохого, однако помните, что машинное обучение - это программирование в матрицах. Ради машинного обучения я могу выразить уравнение линии в терминах машинного обучения по-другому. Я бы назвал y своей гипотезой и представил бы ее как J (theta) и назвал бы b как theta0 и m как theta1. Я могу написать такое же уравнение, как:

Чтобы решить аналитическими методами Theta0 и Theta1, мне пришлось бы написать следующую программу:

theta_best = np.linalg.inv (X.T.dot (X)). точка (X.T) .dot (y)

Помните, что я добавил к X единицу смещения, равную 1 для каждого вектора в X. Это делается для простоты умножения матриц для решения для Theta.

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

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

Вот теперь аналогия с терминами машинного обучения:

Размер шагов в любом направлении = скорость обучения

Гаджет сообщает, что высота = функция затрат

Направление ваших шагов = Градиенты

Выглядит просто, но математически как мы можем это представить. Вот математика:

Где m = количество наблюдений

Я беру пример линейной регрессии. Вы начинаете со случайного вектора Theta и прогнозируете h (Theta), затем вычисляете стоимость, используя приведенное выше уравнение, которое означает среднеквадратичную ошибку (MSE). Помните, что вы пытаетесь свести к минимуму затраты, которые вам нужно знать, ваш следующий шаг (или Theta). Частная производная - это то, что может помочь найти Theta для следующей итерации.

Но подождите, сейчас нам нужно вычислить Theta0 и Theta1, как это сделать и что, если бы у нас было несколько функций, у нас было бы несколько Theta. Не волнуйтесь, вот обобщенная форма для вычисления Theta:

где альфа = скорость обучения

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

Что нам нужно: функция стоимости, которая вычисляет стоимость, функция градиентного спуска, которая вычисляет новый тета-вектор, вот и все.

Начнем с функции стоимости, а вот код:

Я бы поделился своей сутью GitHub в конце этой статьи, чтобы вы могли загрузить и запустить код, но пока позвольте нам понять функцию стоимости. Он принимает theta, X и y, где theta - вектор, X - вектор-строка, а y - вектор. Вот как обычно ваши данные X - это матрица векторов-строк, а y - вектор.

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

Требуется три обязательных входа X, y и theta. Вы можете настроить скорость обучения и количество итераций. Как я сказал ранее, мы вызываем cal_cost из функции gradient_descent.

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

Нам нужно найти theta0 и theta1, но нам нужно передать некоторый вектор theta в градиентном спуске. Мы можем начать со случайных значений тета из распределения Гаусса, и это может быть 1000 итераций и скорость обучения 0,01. Фрагмент кода не требует пояснений.

Мы получаем theta0 = 4,11 и theta1 = 2,899, что очень близко к нашим фактическим значениям 4 и 3 для theta0 и theta1 соответственно. Но нужно ли нам повторять 1000 раз и использовать скорость обучения 0,01? Чтобы ответить на этот вопрос, нам нужно посмотреть, как стоимость изменяется в зависимости от итераций, поэтому давайте построим график cost_history в зависимости от итераций.

Глядя на этот график, становится очевидным, что стоимость примерно после 180 итераций не уменьшается, что означает, что мы можем использовать только 200 итераций. Если мы увеличим масштаб графика, то сможем это заметить.

Также мы можем заметить, что стоимость сначала снижается быстрее, а затем замедляется.

Вы можете попробовать и поиграть с разными комбинациями скорости обучения и итераций.

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

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

it_lr =[(2000,0.001),(500,0.01),(200,0.05),(100,0.1)]

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

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

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

Стохастический градиентный спуск (SGD)

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

Мини-пакетный градиентный спуск

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

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

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

Вот ссылка на суть GITHUB

Если вы хотите увидеть работающий пример, посмотрите его в Google Colab здесь