Градиентный спуск с помощью простого набора данных

Градиентный спуск с помощью простого набора данных

Вступление

В этой статье я собираюсь продемонстрировать градиентный спуск в машинном обучении с помощью простого набора данных. Слово “Градиент” имеет несколько значений в зависимости от контекста, в котором оно используется. Однако в общем смысле это означает нечто, что постепенно меняется. На языке математики и машинного обучения градиент называется “наклоном”, который указывает, насколько крутой или неглубокой является линия (или функция) в определённой точке на n-мерной плоскости. "Крутой склон" указывает на высокую скорость изменения одного фактора по сравнению с другим фактором, в то время как обратное верно для "пологого склона".

На уроках математики в школах учат, что уравнение прямой имеет вид y = mx + c (обозначения могут отличаться в зависимости от книг), где y - точка на оси y, x - точка на оси x, m - наклон, а c - пересечение на оси y. Если пересечение по оси y равно 0, значение c можно игнорировать. В машинном обучении это уравнение является базовой задачей линейной регрессии. Если в двумерной плоскости есть только одна линия, наклон и пересечение можно найти с помощью формул, подставив их вместо m и c и решив уравнение. Следовательно, у него есть единственное решение.

На самом деле каждая задача машинного обучения включает в себя сотни или тысячи уравнений, которые чаще всего не согласуются ни с одним решением. Каждое уравнение - это “Наблюдение”, а каждая ось - “Особенность”. Когда система уравнений содержит больше наблюдений, чем признаков, она называется переопределённой системой. Следовательно, большинство проблем машинного обучения связаны с чрезмерно детерминированной системой. Градиентный спуск используется для нахождения решения (коэффициента) для каждого признака, с которым могут согласиться все наблюдения, что сведёт к минимуму разницу между наблюдаемыми и прогнозируемыми результатами. Разница рассчитывается с использованием множества "Функций затрат”. Одним из них является среднеквадратичная ошибка (MSE), которая используется в задаче ML этой статьи.

Программа

Для этой задачи градиентного спуска подготовлен простой синтетический набор данных. Все блоки кода написаны на языке программирования Python. Программа начинается с импорта необходимых пакетов Python:

import numpy as np import pandas as pd from matplotlib import pyplot as plt

Генерируется синтетический набор данных, который следует уравнению y = 2.3x. Цель предварительной фиксации коэффициента и соответствующей генерации набора данных состоит в том, чтобы увидеть, как выполняется градиентный спуск, и в результате определить коэффициент. Излишне говорить, что реальная задача машинного обучения заранее не будет иметь коэффициентов.

Определение уравнения в Python и генерация набора данных:

def f(x): return 2.3*x x = np.arange(-20, 20, 2) #Generate feature x Y = [] for x_i in x: Y.append(np.round(f(x_i),2)) #Generate Observed value Y fulldata = pd.Series(zip(x,Y)) n=len(fulldata)

Как упоминалось ранее, MSE - это функция затрат, которая математически представлена в виде,

Градиентный спуск с помощью простого набора данных

Заменяющий y_bar,

Градиентный спуск с помощью простого набора данных

Функция Python создана для облегчения расчёта стоимости путём предоставления необходимых входных параметров:

def costfunc(Y_i, x_i, m, n): return (1/n)*sum(pow(Y_i-(m*x_i),2))

Как упоминалось ранее, градиентный спуск - это методология, позволяющая минимизировать крутизну склона. Функцией здесь является Cost Function, и градиентный спуск используется для минимизации её ошибки. В более общих чертах, градиентный спуск используется для нахождения значения m, которое приводит к наименьшему MSE.

Но как мы узнаем, является ли наклон "крутым" или "пологим" в определённой точке кривой функции затрат? Вот тут-то и появляются деривативы. Производные предоставляют возможность понять скорость изменения значения по сравнению с другим значением в определённый момент. В случае функции Cost производные предоставляют возможность определить величину MSE для экземпляра m. Следовательно, производные используются для настройки значения m до такой степени, чтобы это приводило к наименьшей ошибке. Применяя производные правила к нашей функции затрат (MSE), производное уравнение становится,

Градиентный спуск с помощью простого набора данных

Вот как это будет выглядеть в виде функции на Python:

def der_costfunc(Y_i, x_i, m, n): return (2/n)*sum(x_i*((m*x_i)-Y_i))

Установлена важная переменная, называемая Step (она же Скорость обучения), которая определяет, насколько сильно изменяется значение m на каждой итерации спуска. Значение этой переменной может отличаться в зависимости от задачи машинного обучения. Оно обычно задаётся в долях, таких как 0,01, 0,0001 и т.д.

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

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

Наконец, начальное значение коэффициента m устанавливается таким образом, чтобы его можно было корректировать на каждой итерации для уменьшения MSE. Помещаем всё это в код Python, как показано ниже:

ms = [] #Hold the coefficients for each iteration for plotting purpose errors = [] #Hold the MSE for each iteration for plotting purpose m = 0 #Initial value of the coefficient step = 0.001 #Ensure step is appropriate else costfunc will wildly swing. tol=0.0001 #Acceptable difference in MSE between consecutive iterations to stop the Descent

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

1. Рассчитайте Cost, используя начальное значение коэффициента.

2. Вычислите значение производной для начального значения m, используя уравнение первой производной функции Cost. Умножьте это значение на значен��е Step, чтобы определить следующее значение коэффициента m.

3. Рассчитайте Cost ещё раз с новым значением коэффициента m. Найдите разницу между MSE, полученным на шаге 1, и шаге 3.

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

Применение этих шагов в виде кода на python:

prevcost = costfunc(Y, x, m, n) for i in range(200): der_m = der_costfunc(Y, x, m, n) m = m - (der_m*step) currcost = costfunc(Y, x, m, n) ms.append(m) errors.append(currcost) if((prevcost-currcost) < tol): print(f'm: {np.round(m,5)}, currcost: {currcost}, prevcost: {prevcost}') plt.plot(ms, errors) plt.xlabel("coefficient") plt.ylabel("MSE") plt.show() break prevcost = currcost

Приведённый выше код настроен на выполнение максимум 200 итераций, чтобы найти оптимальный коэффициент m, который уменьшает MSE. Количество итераций может быть изменено в зависимости от проблемы, но чем больше итераций, тем дольше выполняется код. Выполнение кода приводит к коэффициенту m, равному 2,29931, что близко к 2,3, который был установлен в наборе данных при его подготовке. Приведённый ниже график, также являющийся результатом выполнения приведённого выше кода, показывает, как MSE уменьшается с каждым значением коэффициента.

Градиентный спуск с помощью простого набора данных

Ниже представлен полный код программы:

import numpy as np import pandas as pd from matplotlib import pyplot as plt def f(x): return 2.3*x x = np.arange(-20, 20, 2) Y = [] for x_i in x: Y.append(np.round(f(x_i),2)) fulldata = pd.Series(zip(x,Y)) n=len(fulldata) def costfunc(Y_i, x_i, m, n): return (1/n)*sum(pow(Y_i-(m*x_i),2)) def der_costfunc(Y_i, x_i, m, n): return (2/n)*sum(x_i*((m*x_i)-Y_i)) ms = [] #Hold the coefficients for each iteration for plotting purpose errors = [] #Hold the MSE for each iteration for plotting purpose m = 0 #Initial value of the coefficient step = 0.001 #Ensure step is appropriate else costfunc will wildly swing. tol=0.0001 #Acceptable difference in MSE between consecutive iterations to stop the Descent prevcost = costfunc(Y, x, m, n) for i in range(200): der_m = der_costfunc(Y, x, m, n) m = m - (der_m*step) currcost = costfunc(Y, x, m, n) ms.append(m) errors.append(currcost) if((prevcost-currcost) < tol): print(f'm: {np.round(m,5)}, currcost: {currcost}, prevcost: {prevcost}') plt.plot(ms, errors) plt.xlabel("coefficient") plt.ylabel("MSE") plt.show() break prevcost = currcost

Заключение

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

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

Статья была взята из этого источника:

Начать дискуссию