Основное понятие нейронных сетей - регрессия.
Линейная регрессия - предсказание количественной зависимости одного показателя от другого
Простейшим представителем нейронных сетей - является перцептрон, который описывает 1 нейрон
![](https://skahin.ru/blog/img/ml/image001.jpg)
Перцептрон можно описать формулой:
![](https://skahin.ru/blog/img/ml/image002.png)
Где
* X - входные активации (факты влияющие на выходное решение)
* W - вектор весов (вес каждого факта в принятии решения)
* b - смещение или порог срабатывания, если перенести его вправо
Исходя из формулы, видно, что перцептрон активируется, если сумма входов * веса > порога срабатывания
Если представить графически, то это будет выглядеть так:
![](https://skahin.ru/blog/img/ml/image003.jpg)
Наша цель заключается в таком подборе весов W, чтобы перцептрон активировался ( > 0 )
* Первоначально веса (W) задаются случайными значениями.
В моем случае это 0
* Чтобы обучить перцептрон, прогоним его по примерам которые мы знаем (tar)
* Если ошиблись в предсказании значения res:
o Получили 1, вместо 0, то уменьшаем вес на значение наблюдения
o Получили 0, вместо 1, то наоборот увеличиваем вес, чтобы следующий раз получить больше
Res тут считается по формуле выше = вес * входная активация + смещение, но для перемножения без циулов используются функции numpy для работы с матрицами: * dot - перемножить матрицы * T - транспонирование матрицы - поворот ее на 90 градусов, т.к. перемножаться могут только матрицы у которых число строк у первой = числу столбцов у второй
import numpy as np w = np.array([0,0,0]) x = np.array([[1,1,0.3],[1,0.4,0.5],[1,0.7,0.8]]) tar = np.array([1,1,0]) def activate(sum): return 1 if sum > 0 else 0 for i in range(3): res = activate(w.T.dot(x[i])) print(str(i) + ". " + str(res)) if res != tar[i]: if res == 1: w = w - x[i] else: w = w + x[i] print(w) #print(w) #1, 1, 0.3 -> (1, 0.4, 0,15) -> 0, 0.6, -0.2 -> (0, 0.42, -0.16) -> 1, 1.3, 0.6 или -1, -0.1, -1
Перцептрон описывает простейший нейрон, нейрон может активироваться различными функциями:
* Линейная (w*x + b)
Просто возвращаем значение этого выражения, без каких либо сравнений
* Перцептрона (f(x,w,b)=1, если w*x+b>0, иначе 0)
Рисунок выше.
Такие функции не всегда удобны, так как от них нельзя найти производную, которая понадобится нам дальше, для вычисления ошибки.
Рассмотрим другие дифференцируемые функции активации:
* сигмоидальная sigma(w*x+b)=1/(1+e**−(w*x+b))
![](https://skahin.ru/blog/img/ml/image004.png)
Наиболее распространенная, часто используется поумолчанию.
* тангенс tanh(w*x+b) = 2*sigma(2*x)-1
![](https://skahin.ru/blog/img/ml/image005.jpg)
* улучшенный линейный нейрон ReLU
= greatest(w*x+b, 0)
* Аналитическое прилижение к ReLU (softplus)
=ln(1+e**w*x+b)
![](https://skahin.ru/blog/img/ml/image006.jpg)
Графически активации можно представить на общем графике :
![](https://skahin.ru/blog/img/ml/image007.png)
Сигмоидальная активационная функция удобна тем, что ее значения лежат в ограниченном диапазоне от 0 (полная ложь) до 1 (полная правда)
Градиентный спуск:
Для оценки ошибки нашего предсказания используется модификаця среднеквадратичного отклонения.
Квадратичная целевая функция показывает нам значение ошибки предсказания от реального:
![](https://skahin.ru/blog/img/ml/image008.png)
Функция используется для оценки ошибки нейрона, где:
* Y^ - предсказанное значение
Предсказаное значение считается по тойже формуле перцептрона, но активационная функция чаще всего = сигмойде
* Y - реальное значение
Чем меньше значение ошибки, тем лучше ведет себя алгоритм.
Пример визуализации функции ошибки от двух входных параметров:
![](https://skahin.ru/blog/img/ml/image009.png)
Где на плоскости веса, а по оси Z - величина ошибки.
В глобальном минимуме функции находится минимальная ошибка алгоритма, чтобы найти этот минимум придется применить производную.
Помним, что производная - это скорость изменения функции.
Нам нужно посчитать производную по каждому аргументу в каждой точке, чтобы найти направление роста или падения функции ошибки по каждому весу.
Совокупность производных по весам дает нам градиент (J)
* градиентный спуск - вектор изменения значения целевой функции по каждой оси (частная производная по каждому аргументу)
![](https://skahin.ru/blog/img/ml/image010.png)
Частная производная показывает нам направление роста по каждой из оси.
Суммарно это дает нам правление роста ошибки.
Но чтобы минимизировать ошибку, умножаем производную на *-1, что даст направление спуска.
Там где изменения функции сменилось с отрицательного на 0, значит мы нашли минимум функции (самую глубокую точку локальной впадины)
Суммируем:
* при градиентном спуске ищем глобальный/локальный минимум (там минимальное отклонение от реального значения)
двигаемся шагами в направлении наибольшего уменьшения функции, пока не найдем минимум (для этого используем частную производную по целевой функции)
* скорость обучения регулируем константой a
Wновое = Wтекущее - a*J (J - значение градиентного спуска)
+/- изменения константы a (размера шага обучения):
** двигаемся большими шагами - можно пропустить минимум
** маленькими - можем остановиться в локальном минимуме, вместо глобального
* критерий останова:
** изменение w -> 0 или достаточно мало
** достигли максимального числа итерации
Градиент для ошибки нейрона
Можно описать как среднее значение приращений (производных) отклоенений ошибок:
![](https://skahin.ru/blog/img/ml/image011.jpg)
Градиент ошибки сигмоидального нейрона:
Посчитанная производная для активации с сигмоидальным нейроном:
![](https://skahin.ru/blog/img/ml/image012.png)
Это вектор производных от целевой функции отклонения. Его значение нам дает понятие в каком направлении в среднем расположен спуск для снижения ошибки.
Пример обучения на Python:
* «J_last» - считаем целевую функцию (отклонения предсказания от реального)
* «J_der» - считаем производную по формуле выше.
Этим определяем направление роста функции.
* «self.w = self.w - J_der * learning_rate» -
Обновляем веса нейрона = вес - производная * скорость обучения.
Минус, т.к. нам нужно двигаться в противоположную сторону от роста функции ошибки.
* «J_new» - пересчитываем целевую функцию еще раз на новых весах
* «(J_last - J_new) < eps»
Если изменение функции ошибки очень мало, значит мы дошли до минимума функции, где изменение очень мало (производная стремится к нулю).
Это значит или что мы дошли до локального минимума или подобрали нужные веса для правильного предсказания:
import numpy as np def update_mini_batch(self, X, y, learning_rate, eps): J_last = J_quadratic(self, X, y) J_der = compute_grad_analytically(self, X, y)
self.w = self.w - J_der * learning_rate J_new = J_quadratic(self, X, y) return int((J_last - J_new) < eps)
Алгоритм обратного распространения ошибки:
До этого мы рассматривали единичный нейрон. В реальности нейронная сеть состоит из множества нейронов и слоев из них, и вычисление ошибки становится значительно сложней, т.к. ошибка на каждом шаге - это совокупность ошибок с предыдущих шагов.
Многослойный перцептрон:
![](https://skahin.ru/blog/img/ml/image013.png)
Здесь Z - сумматорная функция (взвешенная сумма входов)
1 слой - это входы
а - активация
w - веса
x - входные примеры
l - номер слоя
J - градиент ошибки
( Если нужно классифицировать несколько классов, то на выходе может быть более 1 нейрона. )
Одной из сложнейших задач многослойного перцептрона является определение влиятения ошибки предыдущего слоя на текущий.
Алгоритм обратного распространения ошибки:
С помощью градиентного спуска мы уже рассмотрели как найти ошибку в выходном слое.
Чтобы определить влияние других слоев на выходную ошибку применяем алгоритм обратного распространения ошибки:
![](https://skahin.ru/blog/img/ml/image014.png)
1. Вектор ошибок выходного слоя, зная целевую функцию по активациям
2. Ошибки предыдущем слое, зная ошибку в текущем
3. Производная по смещениям
4. Производная по весам
Общий алгоритм теперь такой:
* Сначала мы вычисляем выходные активации, сохраняем промежуточные активации (они понадобятся при обратном проходе расчета ошибок)
* Используем ф.1, чтобы найти ошибки в выходном слое
* Используем ф.2, чтобы найти ошибки во всех предыдущих слоях
* Используем ф.3 и ф.4 получаем остальные параметры
* Обновляем параметры и повторяем
* Останавливаемся при достижении нужных критериев
Сертификат о прохождении
Комментариев нет:
Отправить комментарий