Модификация весовых коэффициентов с помощью градиентного спуска

В этой лекции мы обсудим, как модифицировать весовые коэффициенты нашей модели логистической регрессии для уменьшения ошибки.

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

Модификация весовых коэффициентов с помощью градиентного спуска. Теория

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

Что же в таком случае мы можем сделать? Пусть у нас есть кривая функции ошибок.:

Модификация весовых коэффициентов с помощью градиентного спуска

 

Установим случайные значения для весового коэффициента в некоторой точке. Предположим, например, что значение производной в этой точке равно -1, а значение весового коэффициента равно -2. Суть в том, чтобы небольшими шагами двигаться в сторону производной.

Размер шага – это то, что мы называем коэффициентом обучения. В нашем примере установим его равным единице. Тогда модифицированное значение весового коэффициента будет равно

w=-2-1*(-1)=-1.

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

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

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

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

Итак, как мы можем использовать градиентный спуск применительно к логистической регрессии? Начнём с целевой функции:

Модификация весовых коэффициентов с помощью градиентного спуска

Нам нужно найти производную. В дифференциальном счислении есть так называемое цепное правило, поэтому нам необязательно делать всё сразу. Сначала мы можем найти производную по J относительно y, потом найти производную по y относительно сигмоиды (обозначим её через a), затем – производную по a относительно w, после чего их перемножить, чтобы получить окончательный ответ:

Модификация весовых коэффициентов с помощью градиентного спуска

Это потому, что производная логарифма равна единице, делённой на аргумент логарифма.

Далее найдём производную по сигмоиде. Получим:

Модификация весовых коэффициентов с помощью градиентного спуска

Модификация весовых коэффициентов с помощью градиентного спуска

Поскольку все элементы с индексом i из левой части зависят только от элементов с индексом i из правой части, мы можем переписать уравнение в векторной форме:

Модификация весовых коэффициентов с помощью градиентного спуска

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

Используя векторную форму, помните, что скалярное произведение является суммой элементов с соответствующими индексами:

Модификация весовых коэффициентов с помощью градиентного спуска

Получается произведение матриц с размерностями DxN и Nx1, в результате чего получается матрица размерности Dx1, поскольку N является внутренней размерностью, которая сокращается, а внешние размерности равны D и 1.

А что же с членом смещения? В логистической регрессии он легко вводится в уравнение простым добавлением столбца, состоящего из единиц:

Модификация весовых коэффициентов с помощью градиентного спуска

Модификация весовых коэффициентов с помощью градиентного спуска. Код

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

Большую часть кода мы возьмём из предыдущей программы.

import numpy as np

N = 100

D = 2

X = np.random.randn(N,D)

X[:50, :] = X[:50, :] – 2*np.ones((50, D))

X[:50, :] = X[:50, :] + 2*np.ones((50, D))

T = np.array([0]*50 + [1]*50)

ones = np.array([[1]*N]).T

Xb = np.concatenate((ones, X), axis=1)

w = np.random.randn(D + 1)

z = Xb.dot(w)

def sigmoid(z):

return 1/(1 + np.exp(-z))

Y = sigmoid(z)

def cross_entropy(T, Y):

E = 0

for i in xrange(N):

if T[i] == 1:

E -= np.log(Y[i])

else:

E -= np.log(1 – Y[i])

return E

print cross_entropy (T, Y)

Итак, у нас есть два нормально распределённых класса, один из которых центрируется к точке с координатами (-2; -2), а второй – к точке с координатами (+2; +2). Уберём частное решение для байесовского классификатора. Установим коэффициент обучения равным 0,1, сделаем 100 итераций и будем выводить на экран результат.

 

learning_rate = 0.1

for i in xrange(100):

if i % 10 == 0:

print cross_entropy(T, Y)

 

w += learning_rate * np.dot((T-Y).T, Xb)

Y = sigmoid(Xb.dot(w))

 

print ‘’Final w:’’, w

 

Запустив программу, увидим, что ошибка резко уменьшается примерно после 30 итераций. Весовые коэффициенты находятся: один – в районе нуля и два значения – в районе 14. Обратите внимание, что хотя это расширение частного случая решения, но полученные значения кажутся чересчур большими.

Мы обсудим это в следующей нашей статье

 

Визуализация линейного разделителя

В этом разделе статьи мы графически изобразим решение для байесовского классификатора, найденное нами выше.

Скопируем код из предыдущей статьи. Единственное отличие – на этот раз мы импортируем ещё и библиотеку Matplotlib.

 

import numpy as np

import matplotlib.pyplot as plt

 

N = 100

D = 2

 

X = np.random.randn(N,D)

 

У нас уже есть код для создания данных, которые составляют два гауссовых облака, одно из которых имеет центром точку (-2; -2), а второе – точку (+2; +2).

 

X[:50, :] = X[:50, :] – 2*np.ones((50, D))

 

X[:50, :] = X[:50, :] + 2*np.ones((50, D))

 

T = np.array([0]*50 + [1]*50)

 

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

 

ones = np.array([[1]*N]).T

Xb = np.concatenate((ones, X), axis=1)

 

def sigmoid(z):

return 1/(1 + np.exp(-z))

 

Мы уже знаем, что решением для байесовского классификатора являются 0, 4, 4, где 0 – это точка пересечения с осью y. Следовательно, искомая прямая имеет вид y = -x. Установим цвета для диаграммы рассеяния наших целевых переменных, установим количество точек, равное 100, и α = 0,5.

 

plt.scatter(X[:,0], X[:,1] c=T, s=100, alpha=0.5)

 

Прорисовав точки, изобразим теперь прямую. Установим для x начальную точку (-6; -6) и прорисуем ещё 100 точек прямой.

 

x_axis = np.linspace(-6, 6, 100)

y_axis = -x_axis

plt.plot(x_axis, y_axis)

plt.show

 

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

 

Понравилась статья? Поделить с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: