Как стать автором
Обновить

Нано-нейрон — 7 простых JavaScript функций, показывающих, как машина может «учиться»

Время на прочтение11 мин
Количество просмотров9.9K
Всего голосов 15: ↑14 и ↓1+13
Комментарии13

Комментарии 13

Я думаю, что этот подход не очень эффективен, более того, он значительно размывает понятие «нейрон».

Большинство знает, что такое производная, потому что это входит как в школьную, так и в институтскую программу. Даже у гуманитариев. Поэтому проще объяснить в терминах градиентного спуска как метода оптимизации.

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

Это лучшая шутка, которую я когда либо слышал про производную)
Не понятно как образовались производные по параметрам w и b. могли бы вы более наглядно объяснить?
как я понимаю исходная функция y=xw+b,
а значит по параметру w производная будет: y=x
а по параметру b: y=1.
Производная берется не от модели, а от «функции ошибки (погрешности)». В тексте выше это формула avarageCost (производная от: 1/m * SUM[(y — prediction) ^ 2 / 2]). Ведь мы хотим найти минимум не для формулы предсказания модели, а для функции, которая описывает насколько прав/неправ наш нейрон.
то есть получается что сама функция нейрона может быть любой и с любым количеством коэффициентов, и расчет коэффициентов зависит от того как считается ошибка? в данном случае средне квадратичное. я помню вариант с сигмоидом, так там производная бралась от сигмоида. вариант нейрона с сигмоидом и вариант нейрона в этой статье можно как-то сравнить?
Да, все верно, функция нейрона (модель) может быть любой. Насколько я знаю, наиболее распространенный вариант для модели нейрона — линейная функция. В нашем случае нано-нейрон имеет всего один вход, поэтому функция выглядит как y = w * x + b (всего один вход х). В случае нейронной сети, каждый нейрон будет иметь не один, а несколько входов (количество входов m равно количеству нейронов в предыдущем слое) и тогда модель нейрона немного усложнится, но все-равно останется линейной:

Y = W1 * X1 + W2 * X2 + ... + Wm *Xm + b

где, Xn — это n-й вход нейрона, а Wn — это n-й параметр нейрона (отвечает за восприимчивость нейрона к числу на входе Xn).

Далее, модель нейрона имеет непосредственное влияние на функцию ошибки (погрешности). То есть нельзя изменить модель нейрона не изменив итоговую формулу расчета функции погрешности.

Минимизируем мы именно функцию ошибки, поскольку она отвечает за то, насколько наш нейрон прав или неправ и мы хотим, чтобы его ошибка свелась к минимуму.

В нейронной сети выходной сигнал нейрона пропускается еще через дополнительную функцию активации (тот же Sigmoid или ReLu). То есть если бы мы использовали функцию активации (назовем ее Z) для нано-нейрона, то его выход/активация вычислялась бы по формуле a = Z(y), где y = w * x + b, а z = 1 / (1 + e^(-x)). В этом случае, использование функции активации повлияло бы на функцию оценки и повлияло бы в итоге на ее производную.

Я опустил эти детали в статье (много входов у нейрона и его последующая активация) для того, чтобы формулы были как-можно проще, для простоты изложения.
я использовал ваш материал и написал программу в Qt, все получилось. стал играться с количеством эпох, набором данных и скоростью обучения.
1. скорость стоило увеличить с alpha = 0.0005 на alpha = 0.0007, как ошибка стала сразу увеличиваться, вместо ее уменьшения. естественно я попробовал поставить наоборот значение меньше, например alpha = 0.0003, ошибка стала уменьшаться но медленнее(оно и очевидно), но пришлось увеличить количество эпох чтобы достичь той же погрешности что и при alpha = 0.0005(я эту закономерность тоже понимаю). Но возникает вопрос откуда взялось то значение alpha = 0.0005? вот допустим разработали модель нейрона, подобрали тестовые/обучающие данные, а обучение может не пойти только потому что скорость обучения не такая. Как выбрать скорость обучения?
2. Так же игрался с набором тестовых данных. Сократил их до 2 значений(0,1 градус), нейрон так же обучился(судил по искомым коэффициентам). Возникает еще вопрос о наборе данных для тренировки. В каких случаях необходимо делать выборку по всему диапазону изменения (в статье от 0 до 100) а в каком достаточно и парочку(в данном случае я на двух значениях 0 и 1 смог обучить)?
  1. По поводу подбора скорости обучения альфа я, к сожалению, на данный момент не знаю лучших практик. Сейчас делаю это простым подбором, эмпирически. Помогает построение графика зависимости погрешности от эпох. Если график растёт или убывает с последующим возрастанием — это может быть признаком того, что, возможно, нужно уменьшить скорость обучения. Хаотичность графика так-же может говорить об этом (признак пропущенного минимума, возращение назад, пропуская минимум снова, опять вперёд, пропуская минимум и так далее). Уменьшать можно шагами нелинейно, чтобы быстрее найти подходящий размер шага (0.05, 0.005, 0.0005, назад 0.0008, 0.0001 — снова таки, это не правило, а скорее эмпирический опыт). Рост погрешности с каждой последующей итерацией так же может быть признаком того, что входные данные надо нормализировать (усреднить и сдвинуть к нулю). Если нейронов несколько (по глубине), возможно введение функции активации поможет избежать «взрыва» (резкого увеличения) параметров нейронов и в итоге погрешности.


  2. По поводу набора тренировочных данных и их количества. В случае с нано-нейроном мы пытались имитировать очень простую и, что наиболее важно, линейную зависимость. Мы это знали заранее. И, действительно, для того, чтобы провести линию правильно может хватить всего двух точек (двух экземпляров тренировочных данных). Но нано-нейрон — упрощенный пример. В реальной жизни мы бы не знали линейная эта зависимость или гораздо более сложная (полиномиальная? синусоидальная? логарифмическая? комбинация всех вместе взятых? ещё более сложная?). В этом случае, чем больше данных для обучения нам удастся раздобыть, тем лучше. Большее количество данных никогда не помешает точности нашего алгоритма (может правда замедлить скорость обучения). Так же, кроме тренировочных данных, важно иметь набор тестовых данных, по которому мы сможем судить, что наш алгоритм не «переучился» или не «недоучился» (bias vs variance issue) и правильно имитирует закономерности в тренировочных данных. По поводу диапазона данных. Если мы собираемся использовать наш нано-нейрон для конвертирования температуры в диапазоне [-40, +60], то соответсвенно и данные для тренировки и для тестирования должны быть тоже из этого диапазона. В случае с нано-нейроном это был диапазон [0, 100] снова таки для простоты. Нужно понимать, что если мы натренировали нано-нейрон на диапазоне [0, 100], то теоретически, использовать его для предсказания (конвертирования) температуры вне этого диапазона — нежелательно (может быть непредсказуемый результат в случае с нелинейными зависимостями


Если нейронов несколько (по глубине), возможно введение функции активации поможет избежать «взрыва»…
большинство функций активации имеет границы изменения. например у сигмоида диапазон изменения [0;1]. как этот диапазон согласовать с конвертацией температуры? необходимо будет ставить некий нелинейный коэффициент?
то есть, если будет больше одного нейрона то получается что на каждом нейроне входные данные сводятся к этому отрезку значений, и как же тогда быть когда хочется получить что-то больше чем единица?

З.Ы. я придерживаюсь той модели что описана в статье, просто хочу добавить в нее сигмоид(либо другую функцию активации)
Если не ошибаюсь, то после введения функции активации (например Сигмойда) итоговая зада, которую будет решать сеть и каждый нейрон в частности будет скорее задачей классификации (true/false), чем задачей регрессии (предсказания конкретного значения).

Каждый нейрон на выходе будет иметь число от 0 до 1, которое будет «говорить» о его «уверенности» в чем-то.

Если на выходе всей сети будет всего один нейрон, то вся сеть в итоге может служить классификатором true/false. Например, имеем на входе 400 пикселей картинки на которой изображена собака и сеть нам «говорит», что, пускай, с вероятностью в 0.89 на входе была собака. Значение выходного нейрона в 0.34 будет говорить, что скорее всего на входе была не собака.

Если на выходе сети два нейрона, то каждый из них может отвечать за свой класс, например первый нейрон будет говорить об «уверенности» сети, что на входе сети изображена «Собака», второй нейрон определяет, что изображен «Кот». В итоге мы на вход сети мы будем давать фото (пиксели), на выходе иметь две вероятности (пускай 0.3 для собаки и 0.9 для кота), можем выбрать большее значение и сказать, что «сеть думает, что на картинке изображен кот».

Если же нужно все-таки «предсказывать» конкретную не дискретную цифру (например стоимость аренды квартиры через месяц на основании данных о квартире, районе, динамике рынка и пр.) то можно использовать методы регрессии. Кстати очень хорошая обзорная статья — Машинное обучение для людей.
Спасибо за статью! Отличная работа. Человеку владеющим javascript и начинающему изучать ML я бы давал в первую очередь.
как будет считаться ошибка для первого нейрона в случае когда будет например два последовательных нейрона(первый входной второй выходной нейрон)? ведь по сути необходимо знать истинное значение для первого нейрона чтобы посчитать ошибку, а истинное значение мы знаем только на выходе(то есть для второго). или необходимо выразить для второго нейрона входное(входное значение для второго нейрона есть выходное значение для первого) значение через выходное и таким образом посчитать? но тогда не понятно как быть, ведь коэффициенты для второго нейрона еще не подобраны(идет процесс обучения).

З.Ы. статью что посоветовали прочитал, спасибо)

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


Модель первого нейрона: y1 = w1 x1 + b1
Модель второго нейрона: y2 = w2
x2 + b2


Если нейроны без функции активации, то можем считать, что выход первого нейрона подаётся на вход второго: x2 = y1.


В итоге два нейрона суммарно на выходе дадут:


y2 = w2 (w1 x1 + b1) + b2
y2 = w1 w2 x1 + w2 * b1 + b2


y2 — предсказываемое значение модели,
x1 — входное значение модели.


Для большей прозрачности можем переименовать переменные:


yPredicted = w1 w2 x + w2 * b1 + b2


Ошибку одного предсказания будем считать как и раньше:


predictionCost = (yCorrect — yPredicted)^2 / 2


predictionCost = (yCorrect — w1 w2 x — w2 * b1 — b2)^2 / 2


Далее находим среднюю ошибку для всего набора тренировочных данных:


averageCost = 1/m * SUM[predictionCost]


И теперь, чтобы оптимизировать параметр каждого нейрона в отдельности, нужно взять 4 частных производных от averageCost (назовём эту функцию, как C, для простоты дальнейшей записи:


dC/dw1
dC/db1
dC/dw2
dC/dn2


Найдя эти четыре производные можем делать градиентный спуск (корректировку параметров):


w1 := w1 — dC/dw1


и так далее...

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории