</font>
Классификацию лучше разибрать с вероятностной точки зрения. Мы разберем эту тему на примере бинарной классификации с классами $\{0, 1\}$.
Примеры задач?
Есть случайная величина $y$ - метка класса $\{0, 1\}$; вектор случайных величин - признаков $\textbf{x}$.
$y_i = p(y_i|\textbf{x}_i)$ - вероятность того, что объект $\textbf{x}_i$ принадлежит к "положительному" классу (например, классу покупателей, купивших товар). Если человек действительно купил товар, $p(y_i|\textbf{x}_i) = 1$, иначе $0$.
Нужно прогнозировать вероятность (события). Значит, модель должна возвращать число в диапазоне $[0, 1]$ - речь идет о вероятности. Это первое ограничение, которое будет наложено на модель $f(\textbf{x}, \textbf{w})$
Правдоподобие - функция, которая показывает вероятность какого-то набора исходов при заданных параметрах модели.
Простой пример правдоподобия: есть монета, броски монеты описываются случайной величиной $Y$. При этом неизвестно, "честная" ли монета, или она падает неравномерно. Броски независимы, исходы записываются в последовательность. Наблюдается последовательность бросков:
$HHHHHHHTHHTHH$
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
$\textbf{y} = \{HHHHHHHTHHTHH\}$ - результаты эксперимента
$\mathcal{L}(\theta|\textbf{y}) = \prod_{i=1}^n p(Y=y_i|\theta)$ - вероятность данного набора исходов
Что нужно сделать? Найти максимум функции $\mathcal{L}(\theta|\textbf{y})$ ($= p(\textbf{y}|\theta)$).
Поиск максимума $\rightarrow$ поиск экстремума. У нас есть набор методов для того, чтобы решать подобные задачи - как минимум, аналитические решения и градиентный спуск.
Поиск максимума называется (принципом) максимизацией правдоподобия.
log-likelihood (логарифм правдоподобия)
$\log{\mathcal{L}(\theta|\textbf{y})} = \log \prod_{i=1}^n p(Y=y_i|\theta) = \sum\limits_{i=1}^n \log{p(Y=y_i|\theta)} $
Логарифм применяют, так как функция многие вероятностные распределения логарифмически выпусклые, а выпуклость функции нужна, чтобы найти "правильный" максимум при максимизации правдободобия.
Немного обобщим. Представим, что речь идет не о монете, а о более сложной модели, которая вкючает вектор параметров $\theta$ и вектор переменных $textbf{x}$. Допустим, есть всего два исхода: $\{0, 1\}$ Вероятность исхоов можно записать так:
$p(y_i=0| \textbf{x}_i, \theta)$
$p(y_i=1| \textbf{x}_i, \theta)$
Так как исходы взаимоисключающие, можно записать
$p(y_i=0| \textbf{x}_i, \theta) = 1 - p(y_i=1| \textbf{x}_i, \theta)$
Теперь давайте скажем, что функция $f(\textbf{x}_i, \theta) = p(y_i=1| \textbf{x}_i, \theta)$ - это модель, которая прогнозирует вероятность того, что будет "положительный" случайный исход.
Правдоподобие в таком случае может быть записано как
$\mathcal{L}(\theta | \textbf{y}) = \prod_{i=1, [y_i = 1]}^{n} f(\theta, \textbf{x}_i) \cdot \prod_{i=1, [y_i = 0]}^{n} (1 - f(\theta, \textbf{x}_i))$
здесь $[y_i = 0]$ - условный оператор: если $y_i = 0$ или $1$, то суммируем, иначе пропускаем элемент.
Максимизация правдоподобия - процесс поиска максимума этой функции. Давайте выполним дополнительные действия, прологарифмируем это выражение и добавим знак "-":
$- \log{\mathcal{L}(\theta | \textbf{y})} = -\sum_{i=1, [y_i = 1]}^{n} \log{f(\theta, \textbf{x}_i)} - \sum_{i=1, [y_i = 0]}^{n} \log{(1 - f(\theta, \textbf{x}_i))}$
Теперь мы должны не максимизировать, а минимизировать - из-за замены знака. Наличие одного минимума в общем виде не гарантируется, но может быть получено с определенными ограничениями на функцию $f(\theta, \textbf{x})$.
Немного упростим - избавимся от двух сумм с условиями, оставив одну сумму.
$ -\sum_{i=1, [y_i = 1]}^{n} \log{f(\theta, \textbf{x}_i)} - \sum_{i=1, [y_i = 0]}^{n} \log{(1 - f(\theta, \textbf{x}_i))} = -\sum_{i=1}^{n} y_i \log{f(\theta, \textbf{x}_i)} + (1 - y_i) \log{(1 - f(\theta, \textbf{x}_i))} $
Как воспринимать полученное выражение: $y_i$ - это конкретный исход, например, Орел/Решка. В таком случае, $x_i$ - это набор параметров броска монеты, а $\theta$ - набор параметров модели, которая определяет вероятность, с которой монета упадет на одну из граней.
Максимизируя произведение вероятностей отедльных бросков, т.е. правдоподобие моделей, мы можем подобрать наиболее "правильные" параметры модели, которые более точно описывают закон, по которому падает монета.
Так как речь идет не о $\mathcal{L}$, а о $-log{\mathcal{L}}$, нужно минимизировать (из-за знака минус).
Фактически, максимизация правдоподобия была (уже практически) преобразована в задачу регрессии. Осталась пара деталей.
Если $y_i = f(\theta, \textbf{x}_i) = p(\hat{y}_i | \textbf{x}_i, \theta)$ - прогноз, $\hat{y}_i$ - "настоящее" значение (фактическое наблюдение), то следующая функция
$\mathcal{L}(\hat{y}_i, y_i) = -\sum_{i=1}^{n} \hat{y}_i \log{y_i} + (1 - \hat{y}_i) \log{(1 - y_i)}$
- функция ошибки, называемая бинарной кроссэнтропией.
При оптимизации этой функции в случае, если речь идет о логистической регрессии (определенный вид моделей), после достижения оптимального значения,
$\mathbb{E}(Y|X) = f(X, \theta)$
- здесь $Y, X$ - заглавные, т.к. они обозначают случайные переменные, а не конкретные исходы.
При внимательном рассмотрении формулы
$\mathcal{L}(\hat{y}_i, y_i) = -\sum_{i=1}^{n} \hat{y}_i \log{y_i} + (1 - \hat{y}_i) \log{(1 - y_i)}$
можно понять, что это аналог кросс-энтропии для дискретного распределения -
$H(p, q) = \sum\limits_x p(x) \log{q(x)}$, где $x$ - случайная величина, $p$ - "истинное" распределение, $q$ - заданное распределение, при помощи которого "кодируются" (или восстанавливаются) значения случайной величины из распределения $p$.
В случае модели логистической регрессии и других, более сложных моделей, $p(x)$ - это известные нам исходы, $\hat{y}_i$, $q(x)$ - прогнозы модели, $y_i = f(\textbf{x}_i, \theta)$.
Выражение $(1 - \hat{y}_i) \log{(1 - y_i)}$ - просто трюк для удобства расчета.
Таким образом, когда идет речь о минимизации бинарной кросс-энтропии, минимизируется разница между истинным распределением (зависимой переменной $\hat{y}$) и моделью. Если кросс-энтропия равна нулю - распределения идентичны
т.е. для всех исходов "Решка" модель прогнозирует решку с вероятностью 1, и то же самое для "Орлов".
Функции для регрессии могут быть любой сложности, единственное ограничение - линейная зависимость от параметров $\theta$ (или $w$, как было на занятии по линейной регрессии).
При этом функция
$f(\textbf{x}, \theta) = \sum\limits_{k} \theta_k f_k(x)$
может возвращать значения из можнества $\mathbb{R}$: числа из $(-\inf, \inf)$. Что нужно сделать?
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
отображение со свойством
$\sigma: \mathbb{R} \rightarrow [0, 1]$
Для этого используется логистическая функция с определенными параметрами:
$\sigma(x) = \dfrac{L}{1 + e^{-k(x - x_0)}}$

Одно из интересных применений - рост биомассы (популяции, ... - ограниченный экспоненциальный рост).

Итак, линейная модель $f(\textbf{x}, \theta)$ встраивается внутрь сигмоиды:
$g(\textbf{x}, \theta) = \dfrac{1}{1 + e^{-f(\textbf{x}, \theta)}}$
Если подставить $y_i = g(\textbf{x}_i, \theta)$ в бинарную кроссэнтропию, получится
$\mathcal{L}(\hat{y}_i, y_i) = -\sum_{i=1}^{n} \hat{y}_i \log{\dfrac{1}{1 + e^{-f(\textbf{x}, \theta)}}} + (1 - \hat{y}_i) \log{\bigg(1 - \dfrac{1}{1 + e^{-f(\textbf{x}, \theta)}}\bigg)}$
Остается решить задачу минимизации этой функции при помощи градиентного спуска. Доказано, что логистическая функция выпуклая, и методом градиентного спуска можно найти глобальный минимум.
Для простоты восприятия я сделаю ряд допущений, например, не буду разбирать задачу в вектороном виде с использованием градиентов.
Чтобы рассчитать градиент, воспользуемся "цепным правилом" (chain rule):
$\dfrac{\delta\mathcal{L}}{\delta\theta} = \dfrac{\delta\mathcal{L}}{\delta\sigma}\dfrac{\delta\sigma}{\delta g}\dfrac{\delta g}{\delta\theta} $
$\dfrac{\delta\mathcal{L}}{\delta\sigma} = -\dfrac{y \log{\sigma} + (1 - y) \log{(1 - \sigma)}}{\delta\sigma} = \dfrac{y - \sigma}{(\sigma - 1)\sigma} $
$\dfrac{\delta\sigma}{\delta g} = \dfrac{\delta \bigg(\dfrac{1}{1 + e^{g}}\bigg)}{\delta g} = {\sigma}{(1 - \sigma)}$
Графие производной сигмоиды
(обратите внимание на левый и правый "края")

$\dfrac{\delta g}{\delta\theta} = \begin{bmatrix} \theta_{1} \\ \theta_{2} \\ \vdots \\ \theta_{m} \end{bmatrix} $
Сводя все вместе, получим после сокращений
$ \nabla_{\theta}\mathcal{L}(\textbf{y}, \sigma(\textbf{x}, \theta)) =\ ...$ упрощаем, убирая градиент и суммы
$= \dfrac{\delta\mathcal{L}}{\delta\sigma}\dfrac{\delta\sigma}{\delta g}\dfrac{\delta g}{\delta\theta}=\ ...$ возвращаем суммы и векторную форму
$= \dfrac{1}{n}\sum\limits_{i=1}^{n}(\textbf{y} - \sigma(\textbf{x}, \theta))\begin{bmatrix}
\theta_{1} \\
\theta_{2} \\
\vdots \\
\theta_{m}
\end{bmatrix}
$
Иногда в литературе встречается выражение "логит". Что это такое?
$logit(p) = \log{\dfrac{p}{1-p}}$
Логит - это логарифм от шансов (формата "наши шансы выжить 1 к 129824", или odds по-английски). Можно сказать, что логистическая регрессия работает с логитами.
Дело в том, что $logit^{-1} = sigmoid$

Все методы, которые мы разбирали на занятии про линейную регрессию, остаются в силе.
Придумали Уоррен Мак-Каллок и Уолтер Питтс, в 40-х годах. Кажется, первая статься вышла в 1943.
Нейронные сети можно использовать как для задач прогноза количественных характеристик, так и для классификации. Второй вид задач встречается, насколько я знаю, гораздо чаще.
Простейшая нейросеть.

Что важного на иллюстрации?
Каждой связи в перцептроне (и в более сложных нейросетсях) присваивается вес.
Номер веса $w_{jk}^{l}$ - это вес нейрона от $l-1$-го слоя к $l$-му слою, $k$ - номер нейрона в $l-1$-м слое, $j$-номер нейрона в $l$-м слое.
Можно сказать, что между двумя слоями формируется матрица весов размера $j \times k$: $W^l \in R^{k \times j}$

Допустим, "на вход" нейронам $l-1$-го слоя подается вектор-строка размерности $j$: $\textbf{x} \in R^j$.
Как записать "выход" $l-1$-го слоя до применения функции активации?
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
$z^l = W^l \cdot \textbf{x}$
Каждый слой нейросети комбинирует выходы предыдущего слоя. Но если бы не нелинейность, в слоях не было смысла:
$x^2 = W^2 \cdot \textbf{x}^1$
$x^3 = W^3 \cdot \textbf{x}^2 = W^3 \cdot W^2 \cdot \textbf{x}^1 = W \cdot \textbf{x}^1$
- можно обойтись одним слоем. Получается, мы все еще ограничены линейной моделью.
Но если добавить после каждого слоя функцию активации, например, $\sigma$? Они привнесут нелинейность, и уже нельзя будет просто перемножить матрицы весов. В то же время, возможности нейросети расширятся очень значительно.
Итак, после каждого слоя добавляется функция активации:
$a^l = \sigma(W^l \cdot \textbf{a}^{l-1})$
Единственное отличие - для весов между перым и вторым слоями на вход подаются не активации предыдущего слоя, а сами данные.
$a^2 = \sigma(W^2 \cdot \textbf{x})$
Часто к входным данным применяют свои функции активации/нормализации, поэтому запись
$a^2 = \sigma(W^2 \cdot \textbf{a}^1)$
можно считать корректной.
Кроме сигмоиды, применяют и другие функции активации:
ReLU, Leaky ReLU, Softplus, tanh и другие.

Важная часть нейросети, которая позволяет нейросети работать со "сдвинутыми" данными, вектор размерности, равной количеству нейронов в слое $l$.
Выполняет ту же роль, что и $b$ в линейной регрессии:
$f(x, w) = b + wx$
$a^l = \sigma(W^l \cdot \textbf{a}^{l-1} + b^l)$
Как применить градиентный спуск к нейросети?
Вычислить градиенты для всех весов. Но как это сделать?
Как модифицировать веса на промежуточных слоях во время градиентного спуска?
Алгоритм:
Backpropagation($X$, $y$):
-- $X$ - матрица с примерами, $n \times k$
-- $y$ - вектор целевых переменных, $n$ (или $n \times j$)
Пока не будет достигнуто условие остановки:
Я оставлю вывод уравнений за кадром, но есть отличный разбор с выводом всех выражений по ссылке.




Адаптивные медоты градиентного спуска: Momentum, AdaM, NAdaM, AdaGrad
Momentum:
$\nu_t = \gamma \nu_{t-1} - \eta \nabla_w \mathcal{L(w)}$
$w = w - \nu_t$
Обзорная статья про многое из перечисленного выше
</font>
import keras
import matplotlib.pyplot as plt
import numpy as np
from keras.datasets import mnist
(x_tr, y_tr), (x_te, y_te) = mnist.load_data()
y_tr
plt.matshow(x_tr[0])
def to_bin(x):
return np.array([1 if i == 1 else 0 for i in x])
y_tr, y_te = to_bin(y_tr), to_bin(y_te)
np.mean(y_tr)
x_tr = x_tr / 255.
x_te = x_te / 255.
x_tr = x_tr.reshape((len(x_tr), 28*28))
x_te = x_te.reshape((len(x_te), 28*28))
x_tr.shape
x_te.shape
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, f1_score
logreg = LogisticRegression()
logreg.fit(x_tr, y_tr)
y_te_pr = logreg.predict_proba(x_te)[:,1]
y_te_pr = logreg.predict(x_te)
y_te_pr
y_te
accuracy_score(y_te, y_te_pr)
f1_score(y_te, y_te_pr, average='macro')
accuracy_score(y_te, [0] * len(y_te))
f1_score(y_te, [0] * len(y_te), average='macro')
f1_score(y_te, [1] * len(y_te), average='macro')
from keras.layers import Dense, Input
from keras.models import Sequential
model = Sequential()
model.add(Dense(784, activation='sigmoid', input_shape=(784, )))
model.add(Dense(1, activation='sigmoid'))
model.summary()
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(x_tr, y_tr, validation_data=(x_te, y_te),
epochs=5,
batch_size=64
)
y_te_pr = model.predict(x_te)
y_te_pr = [1 if i > 0.5 else 0 for i in y_te_pr]
accuracy_score(y_te, y_te_pr)
f1_score(y_te, y_te_pr)
0.9844005962