Кросс-энтропийная функция ошибок при логистической регрессии

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

J = \sum_{n} (t_n - y_n)^2.

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

Кросс-энтропийная функция ошибок. Теория

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

Что нам нужно от функции ошибок?

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

Кросс-энтропийная функция ошибок определяется так:

J = -t*log (y)+(1 - t)*log (1 - y).

где t – целевая переменная, y – результат логистической регрессии.

Прежде всего отметим, что существенным является только один член уравнения. Это происходит потому, что целевая переменная t принимает значения лишь 0 и 1. Если t = 1, существенным является первый член, если t = 0, – то второй.

Далее, поскольку y – исходящая переменная логистической регрессии, принимающая значение от нуля до единицы, то логарифм этой величины принимает значения от нуля до минус бесконечности. Но обратите внимание на знак «минус» в формуле. Таким образом, получив минус бесконечность, в конечном результате у нас получится плюс бесконечность.

Рассмотрим теперь несколько примеров. Пусть у нас t = 1, y = 1. В результате получим единицу, умноженную на нуль, то есть нуль. Таким образом, ошибка равна нулю. Замечательно. Обратите внимание, что если t = 0, y = 0, то получится такой же результат.

Пусть теперь t = 1, y = 0,9, то есть модель почти правильная. В результате получим 0,11, – весьма небольшая ошибка, так что тут тоже всё замечательно. Если мы установим t = 1, y = 0,5, то есть модель находится на грани корректности, то в качестве результата функции ошибок получим 0,69 – это куда большая ошибка, свидетельствующая, что модель работает так себе. Пусть теперь t = 0, y = 0,1, то есть мы очень сильно ошибаемся. В результате получим значение функции ошибки 2,3 – это ещё большее значение.

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

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

J = - \sum_{n=1}^{N} t_n \;log (y_n)+(1 - t_n)\; log (1 - y_n).

Кросс-энтропийная функция ошибок. Код

Теперь рассмотрим вычисление кросс-энтропийной функции ошибок в коде.

Сначала мы перенесём часть кода из предыдущего файла.

import numpy as np

N = 100

D = 2

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

Теперь создадим два наших класса, причём первые 50 точек будут концентрироваться в районе с центром (-2; -2), а вторые 50 – в районе с центром (+2; +2).

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

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

Создадим массив целевых переменных, причём первые 50 будут относиться к классу 0, а вторые 50 – классу 1.

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):

если T[i] == 1:

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

еще:

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

return E

print cross_entropy (T, Y)

Запустим программу. Наша кросс-энтропийная ошибка составляет 52,1763501199.

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

w = np.array([0, 4, 4])

z = Xb.dot(w)

Y = sigmoid(z)

print cross_entropy(T, Y)

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

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

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

Скопируем код из предыдущей статьи. Единственное отличие – на этот раз мы импортируем ещё и библиотеку 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: :???: :?: :!:

Share via
Copy link