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

Обзор:

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

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

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

Программа:

Для этой задачи градиентного спуска подготовлен простой синтетический набор данных. Все блоки кода написаны на языке программирования 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))

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

Но как узнать, является ли наклон крутым или пологим в определенной точке кривой функции стоимости? Вот тут-то и появляются деривативы. Производные дают возможность понять скорость изменения значения по отношению к другому значению в конкретный момент времени. В случае функции стоимости производные позволяют определить величину 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))

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

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

Другая переменная, используемая в градиентном спуске, — это допуск. Поскольку градиентный спуск пытается уменьшить MSE с помощью нескольких итераций, должен быть способ определить, когда MSE является приемлемым, и остановить итерации. Один из способов — использовать толерантность. Может быть несколько способов определить допуск для задачи градиентного спуска. В этой статье определяется разница в 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

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

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

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

3. Еще раз рассчитайте стоимость с новым значением коэффициента 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, снижающий среднеквадратичную ошибку. Количество итераций может быть изменено в зависимости от проблемы, но чем больше итераций, тем дольше выполняется код. Выполнение кода приводит к коэффициенту m, равному 2,29931, что близко к 2,3, которое было установлено в наборе данных при его подготовке. На приведенном ниже графике, также являющемся результатом выполнения приведенного выше кода, показано, как MSE уменьшается с каждым значением коэффициента.

Собираем весь код Python вместе.

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

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

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