Введение: нейронные сети, биологическая аналогия и ключевые понятия (нейрон, синапс, вес)
Перевод Making a Simple Neural Network
Что мы будем делать? Мы попробуем создать простую и совсем маленькую нейронную сеть, которую мы объясним и научим что-нибудь различать. При этом не будем вдаваться в историю и математические дебри — вместо этого постараемся объяснить задачу рисунками и кодом.

Многие термины в нейронных сетях связаны с биологией, поэтому давайте начнем с самого начала:

Мозг — штука сложная, но его можно разделить на несколько основных частей и операций:

Возбудитель может быть и внутренним (например, образ или идея):

А теперь взглянем на основные и упрощенные части мозга:

Мозг вообще похож на кабельную сеть.
Нейрон — основная единица вычислений в мозге: он получает и обрабатывает химические сигналы других нейронов и, в зависимости от ряда факторов, либо не делает ничего, либо генерирует электрический импульс (потенциал действия), который затем через синапсы подает сигналы связанным нейронам.

Сны, воспоминания, саморегулируемые движения, рефлексы — всё это происходит благодаря миллионам или миллиардам нейронов, работающих на разных уровнях и создающих связи, которые образуют биологическую нейронную сеть.
Упрощая, мы можем описать простую нейронную сеть:

И формализовать её с помощью графа:

Пояснения: кружки — это нейроны, линии — связи между ними. Для простоты взаимодействия мы представляем как прямое движение информации слева направо. Первому нейрону присвоено число (1 — если он активен, 0 — если нет). Числа на связях — это веса.

Графы показывают сеть в определённый момент времени; для точного отображения нужно разделять время на отрезки.
Модель обучения и веса: пример с кроликом (условный рефлекс) — как веса меняют поведение
Чтобы понять, как веса влияют на нейроны и как нейроны обучаются, возьмём модель из классического эксперимента. Представим тестового кролика и поставим его в условия, где на него направляют безопасную струю воздуха — кролики, как и люди, моргают.


Эту модель поведения можно изобразить графами:

В графах дуновение кодируется как логическое значение; срабатывание второго нейрона зависит от веса связи. Если вес ≥ 1, сенсорный нейрон вызывает моргание; если вес < 1, моргания нет — у второго нейрона установлен порог 1.
Добавим безопасный звуковой сигнал:

Если вес звукового входа равен нулю, звук сам по себе ничего не делает: моргание не возникает пока вес небольшой. Теперь научим кролика моргать по команде, сочетая звуковой сигнал и дуновение.

Важно, что события происходят в разные временные эпохи, в графах это выглядит так:

Сам по себе звук ничего не делает, но воздушный поток по-прежнему заставляет кролика моргать; мы показываем это через веса, умноженные на раздражители (красным).
Обучение сложному поведению можно упрощённо выразить как постепенное изменение веса между связанными нейронами с течением времени.
Чтобы обучить кролика, повторим сочетание звука и дуновения несколько раз:

Для первых трёх попыток схемы будут выглядеть так:

Обратите внимание, что вес для звукового раздражителя растёт после каждого повтора (выделено красным). Это значение выбрано произвольно — 0.30 в примере — но может быть любым, даже отрицательным. После нескольких повторов поведение изменится: кролик начнёт моргать по звуку.

Мы убрали воздействие воздухом, но кролик всё ещё моргает, услышав звуковой сигнал — значит, обучение сработало:

В условиях реального эксперимента такого рода может потребоваться более 60 повторений для достижения результата.
От биологии к искусственной нейронной сети: перцептрон и простая задача с четырьмя кнопками (перцептрон, реализация на JavaScript)
Теперь оставим биологический мир и адаптируем принципы для создания искусственной нейросети. Рассмотрим простую задачу: есть машина с четырьмя кнопками, дающая еду при нажатии правильной кнопки. Задача — узнать, какая кнопка выдаёт вознаграждение.

Схематично поведение кнопки при нажатии можно представить так:

Лучше рассмотреть все возможные результаты, включая правильный:

Нажмите на 3-ю кнопку, чтобы получить свой ужин.
Чтобы воспроизвести нейронную сеть в коде, нам нужна модель или граф, сопоставимый с сетью; вот подходящий граф, отображающий биологический аналог:

Сеть получает входную информацию (какая кнопка нажата), затем множит входы на веса и суммирует результат на выходе. В начальном состоянии все веса равны нулю — сеть пуста, но полностью связана:

Обратите внимание, что все веса равны 0, поэтому нейронная сеть, как младенец, совершенно пуста, но полностью взаимосвязана.
Далее мы сопоставляем внешнее событие с входным слоем и вычисляем значение на выходе программным способом. Начнём с ввода весов на JavaScript:
var inputs = [0,1,0,0];
var weights = [0,0,0,0];
// Для удобства эти векторы можно назватьСоздадим функцию, которая собирает входные значения и веса и рассчитывает значение на выходе:
function evaluateNeuralNetwork(inputVector, weightVector){
var result = 0;
inputVector.forEach(function(inputValue, weightIndex) {
layerValue = inputValue*weightVector[weightIndex];
result += layerValue;
});
return (result.toFixed(2));
}
// Функция сопоставляет пары вес/ввод и суммирует результатКак и ожидалось, если запустить код в начальном состоянии, получим результат 0.00:
evaluateNeuralNetwork(inputs, weights); // 0.00Живой пример: Neural Net 001.
Следующим шагом будет проверка выходного значения сети по сравнению с реальностью. Закодируем текущую реальность в переменную и добавим функцию ошибки:

// Функция ошибки
Error = Reality - Neural Net OutputС помощью функции ошибки можно оценивать работу сети:

Но важнее учитывать, что нас интересует расхождение между желаемым результатом и текущим выводом сети:

Переназначим функцию ошибок как:
Error = <b>Desired Output</b> - Neural Net OutputЭто показывает, что мы будем использовать прошлые результаты для сопоставления с будущими действиями и для обучения.
Добавим в пример кода новые переменные и функцию ошибки:
var input = [0,0,1,0];
var weights = [0,0,0,0];
var desiredResult = 1;function evaluateNeuralNetError(desired,actual) {
return (desired — actual);
}
// После вычисления: "Neural Net output: 0.00 Error: 1"Живой пример: Neural Net 002.
Обучение перцептрона: скорость обучения (learning rate), корректировка весов и повторы (trials)
Короткий итог: мы сделали простую модель, получили способ измерять её производительность по сравнению с желаемым результатом. Теперь нужно исправлять несоответствия — процесс обучения.
Как обучать нейронную сеть? Основа обучения как биологической, так и искусственной нейронной сети — повторение и алгоритмы обучения. В природе алгоритмы обучения — это изменения физических или химических характеристик нейронов после опыта.

Добавим переменную для обозначения степени изменения весов — коэффициент обучения:
var learningRate = 0.20;
// Чем больше значение, тем быстрее будет процесс обучения :)Коэффициент обучения будет изменять веса (как у кролика), особенно вес, который формирует желаемый вывод.
function learn(inputVector, weightVector) {
weightVector.forEach(function(weight, index, weights) {
if (inputVector[index] > 0) {
weights[index] = weight + learningRate;
}
});
}Эта функция добавляет learningRate к весу активного нейрона. До и после обучения:
// Original weight vector: [0,0,0,0]
// Neural Net output: 0.00 Error: 1
learn(input, weights);
// New Weight vector: [0,0,0.20,0]
// Neural Net output: 0.20 Error: 0.8
// Вывод сети стал ближе к желаемому (1)Живой пример: Neural Net 003.
Осталась последняя деталь — повторы. В природе мы просто повторяем одно и то же, в коде указываем количество повторов:
var trials = 6;function train(trials) {
for (i = 0; i < trials; i++) {
neuralNetResult = evaluateNeuralNetwork(input, weights);
learn(input, weights);
}
}Итоговый отчёт после 6 повторов:
Neural Net output: 0.00 Error: 1.00 Weight Vector: [0,0,0,0]
Neural Net output: 0.20 Error: 0.80 Weight Vector: [0,0,0.2,0]
Neural Net output: 0.40 Error: 0.60 Weight Vector: [0,0,0.4,0]
Neural Net output: 0.60 Error: 0.40 Weight Vector: [0,0,0.6,0]
Neural Net output: 0.80 Error: 0.20 Weight Vector: [0,0,0.8,0]
Neural Net output: 1.00 Error: 0.00 Weight Vector: [0,0,1,0]
// Chicken Dinner !Теперь у нас есть вектор весов, который даст желаемый результат, если входной вектор соответствует реальности (нажатие на третью кнопку).

Это масштабируемая модель, игрушка и инструмент для обучения: мы узнали основы машинного обучения, нейронных сетей и ИИ.
Предостережения и ограничения модели (порог, переобучение, отрицательные веса)
Механизм хранения изученных весов не предусмотрён, поэтому данная нейронная сеть забудет всё при перезапуске — потребуется не менее шести успешных повторов, чтобы сеть обучилась заново, если входы появляются в случайном порядке.
Биологические сети могут иметь скорость обучения, равную 1, и тогда нужен только один успешный повтор.
Существует алгоритм обучения, напоминающий биологические нейроны — правило Widrow–Hoff (или обучение Widrow–Hoff).
Пороги нейронов (1 в нашем примере) и эффекты переобучения (при большом количестве повторов результат может превысить 1) не учитываются. Это важно в природе и в сложных моделях. Также не рассмотрены отрицательные веса.
Заметки и список литературы для дальнейшего чтения (перцептрон, ресурсы по нейробиологии и ИИ)
Я пытался избежать математики и строгих терминов, но если интересно, то мы построили перцептрон, который определяется как алгоритм контролируемого обучения (обучение с учителем) для бинарной классификации.
Биологическое строение мозга — тема сложная; лучше начинать с учебников Neuroscience (Purves) и Cognitive Neuroscience (Gazzaniga). Пример с кроликом адаптирован из Gateway to Memory (Gluck). Ещё один полезный ресурс: An Introduction to Neural Networks (Gurney).
А теперь версия на Python. Спасибо Илье Андшмидту за предоставленную версию на Python:
inputs = [0, 1, 0, 0]
weights = [0, 0, 0, 0]
desired_result = 1
learning_rate = 0.2
trials = 6Простейшая нейронная сеть на Python — пример кода и обучение (нейронная сеть, обучение)
def evaluate_neural_network(input_array, weight_array):
result = 0
for i in range(len(input_array)):
layer_value = input_array[i] * weight_array[i]
result += layer_value
print("evaluate_neural_network: " + str(result))
print("weights: " + str(weights))
return result
def evaluate_error(desired, actual):
error = desired - actual
print("evaluate_error: " + str(error))
return error
def learn(input_array, weight_array):
print("learning...")
for i in range(len(input_array)):
if input_array[i] > 0:
weight_array[i] += learning_rate
def train(trials):
for i in range(trials):
neural_net_result = evaluate_neural_network(inputs, weights)
learn(inputs, weights)
train(trials)А теперь на GO! За эту версию благодарю Кирана Мэхера.
Реализация на Go (Golang) — пример обучающей нейронной сети, обучение и оценка ошибки
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println("Creating inputs and weights ...")
inputs := []float64{0.00, 0.00, 1.00, 0.00}
weights := []float64{0.00, 0.00, 0.00, 0.00}
desired := 1.00
learningRate := 0.20
trials := 6
train(trials, inputs, weights, desired, learningRate)
}
func train(trials int, inputs []float64, weights []float64, desired float64, learningRate float64) {
for i := 1; i < trials; i++ {
weights = learn(inputs, weights, learningRate)
output := evaluate(inputs, weights)
errorResult := evaluateError(desired, output)
fmt.Print("Output: ")
fmt.Print(math.Round(output*100) / 100)
fmt.Print("
Error: ")
fmt.Print(math.Round(errorResult*100) / 100)
fmt.Print("
")
}
}
func learn(inputVector []float64, weightVector []float64, learningRate float64) []float64 {
for index, inputValue := range inputVector {
if inputValue > 0.00 {
weightVector[index] = weightVector[index] + learningRate
}
}
return weightVector
}
func evaluate(inputVector []float64, weightVector []float64) float64 {
result := 0.00
for index, inputValue := range inputVector {
layerValue := inputValue * weightVector[index]
result = result + layerValue
}
return result
}
func evaluateError(desired float64, actual float64) float64 {
return desired - actual
}

Комментарии (0)
Войдите или зарегистрируйтесь, чтобы оставить комментарий
Загрузка комментариев…