- PVSM.RU - https://www.pvsm.ru -
Перевод Making a Simple Neural Network [1]
Что мы будем делать? Мы попробуем создать простую и совсем маленькую нейронную сеть, которую мы объясним и научим что-нибудь различать. При этом не будем вдаваться в историю и математические дебри (такую информацию найти очень легко) — вместо этого постараемся объяснить задачу (не факт, что удастся) вам и самим себе рисунками и кодом.
Многие из терминов в нейронных сетях связаны с биологией, поэтому давайте начнем с самого начала:
Возбудитель может быть и внутренним (например, образ или идея):
А теперь взглянем на основные и упрощенные части
Нейрон — основная единица исчислений в
Сны, воспоминания, саморегулируемые движения, рефлексы да и вообще все, что вы думаете или делаете — все происходит благодаря этому процессу: миллионы, или даже миллиарды нейронов работают на разных уровнях и создают связи, которые создают различные параллельные подсистемы и представляют собой биологическую нейронную сеть.
Разумеется, это всё упрощения и обобщения, но благодаря им мы можем описать простую
нейронную сеть:
И описать её формализовано с помощью графа:
Тут требуются некоторые пояснения. Кружки — это нейроны, а линии — это связи между ними,
и, чтобы не усложнять на этом этапе, взаимосвязи представляют собой прямое передвижение информации слева направо. Первый нейрон в данный момент активен и выделен серым. Также мы присвоили ему число (1 — если он работает, 0 — если нет). Числа между нейронами показывают вес связи.
Графы выше показывают момент времени сети, для более точного отображения, нужно разделить его на временные отрезки:
Для создания своей нейронной сети нужно понимать, как веса влияют на нейроны и как нейроны обучаются. В качестве примера возьмем кролика (тестового кролика) и поставим его в условия классического эксперимента.
Когда на них направляют безопасную струю воздуха, кролики, как и люди, моргают:
Эту модель поведения можно нарисовать графами:
Как и в предыдущей схеме, эти графы показывают только тот момент, когда кролик чувствует дуновение, и мы таким образом кодируем дуновение как логическое значение. Помимо этого мы вычисляем, срабатывает ли второй нейрон, основываясь на значении веса. Если он равен 1, то сенсорный нейрон срабатывает, мы моргаем; если вес меньше 1, мы не моргаем: у второго нейрона предел — 1.
Введем еще один элемент — безопасный звуковой сигнал:
Мы можем смоделировать заинтересованность кролика так:
Основное отличие в том, что сейчас вес равен нулю, поэтому моргающего кролика мы не получили, ну, пока, по крайней мере. Теперь научим кролика моргать по команде, смешивая
раздражители (звуковой сигнал и дуновение):
Важно, что эти события происходят в разные временные эпохи, в графах это будет выглядеть так:
Сам по себе звук ничего не делает, но воздушный поток по-прежнему заставляет кролика моргать, и мы показываем это через веса, умноженные на раздражители (красным).
Обучение сложному поведению можно упрощённо выразить как постепенное изменение веса между связанными нейронами с течением времени.
Чтобы обучить кролика, повторим действия:
Для первых трех попыток схемы будут выглядеть так:
Обратите внимание, что вес для звукового раздражителя растет после каждого повтора (выделено красным), это значение сейчас произвольное — мы выбрали 0.30, но число может быть каким угодно, даже отрицательным. После третьего повтора вы не заметите изменения в поведении кролика, но после четвертого повтора произойдет нечто удивительное — поведение изменится.
Мы убрали воздействие воздухом, но кролик все еще моргает, услышав звуковой сигнал! Объяснить это поведение может наша последняя схемка:
Мы обучили кролика реагировать на звук морганием.
В условиях реального эксперимента такого рода может потребоваться более 60 повторений для достижения результата.
Теперь мы оставим биологический мир
узнали, для создания искусственной нейросети. Для начала попробуем сделать простую задачу.
Допустим, у нас есть машина с четырьмя кнопками, которая выдает еду при нажатии правой
кнопки (ну, или энергию, если вы робот). Задача — узнать, какая кнопка выдает вознаграждение:
Мы можем изобразить (схематично), что делает кнопка при нажатии следующим образом:
Такую задачу лучше решать целиком, поэтому давайте посмотрим на все возможные результаты, включая правильный:
Нажмите на 3-ю кнопку, чтобы получить свой ужин.
Чтобы воспроизвести нейронную сеть в коде, нам для начала нужно сделать модель или график, с которым можно сопоставить сеть. Вот один подходящий под задачу график, к тому же он хорошо отображает свой биологический аналог:
Эта нейронная сеть просто получает входящую информацию — в данном случае это будет восприятие того, какую кнопку нажали. Далее сеть заменяет входящую информацию на веса и делает вывод на основе добавления слоя. Звучит немного запутанно, но давайте посмотрим, как в нашей модели представлена кнопка:
Обратите внимание, что все веса равны 0, поэтому нейронная сеть, как младенец, совершенно пуста, но полностью взаимосвязана.
Таким образом мы сопоставляем внешнее событие с входным слоем нейронной сети и вычисляем значение на ее выходе. Оно может совпадать или не совпадать с реальностью, но это мы пока проигнорируем и начнем описывать задачу понятным компьютеру способом. Начнем с ввода весов (будем использовать JavaScript):
var inputs = [0,1,0,0];
var weights = [0,0,0,0];
// Для удобства эти векторы можно назвать
Следующий шаг — создание функции, которая собирает входные значения и веса и рассчитывает значение на выходе:
function <b>evaluateNeuralNetwork</b>(inputVector, weightVector){
var result = 0;
inputVector.forEach(function(inputValue, weightIndex) {
layerValue = inputValue*weightVector[weightIndex];
result += layerValue;
});
return (result.toFixed(2));
}
// Может казаться комплексной, но все, что она делает — это сопоставляет пары вес/ввод и добавляет результат
Как и ожидалось, если мы запустим этот код, то получим такой же результат, как в нашей модели или графике…
evaluateNeuralNetwork(inputs, weights); // 0.00
Живой пример: Neural Net 001 [3].
Следующим шагом в усовершенствовании нашей нейросети будет способ проверки её собственных выходных или результирующих значений сопоставимо реальной ситуации,
давайте сначала закодируем эту конкретную реальность в переменную:
Чтобы обнаружить несоответствия (и сколько их), мы добавим функцию ошибки:
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 <b>evaluateNeuralNetError</b>(desired,actual) {
return (desired — actual);
}
// After evaluating both the Network and the Error we would get:
// "Neural Net output: 0.00 Error: 1"
Живой пример: Neural Net 002 [4].
Подведем промежуточный итог. Мы начали с задачи, сделали её простую модель в виде биологической нейронной сети и получили способ измерения её производительности по сравнению с реальностью или желаемым результатом. Теперь нам нужно найти способ исправления несоответствия — процесс, который как и для компьютеров, так и для людей можно рассматривать как обучение.
Как обучать нейронную сеть?
Основа обучения как биологической, так и искусственной нейронной сети — это повторение
и алгоритмы обучения, поэтому мы будем работать с ними по отдельности. Начнем с
обучающих алгоритмов.
В природе под алгоритмами обучения понимаются изменения физических или химических
характеристик нейронов после проведения экспериментов:
Драматическая иллюстрация того, как два нейрона меняются по прошествии времени в коде и нашей модели «алгоритм обучения» означает, что мы просто будем что-то менять в течение какого-то времени, чтобы облегчить свою жизнь. Поэтому давайте добавим переменную для обозначения степени облегчения жизни:
var learningRate = 0.20;
// Чем больше значение, тем быстрее будет процесс обучения :)
И что это изменит?
Это изменит веса (прям как у кролика!), особенно вес вывода, который мы хотим получить:
Как кодировать такой алгоритм — ваш выбор, я для простоты добавляю коэффициент обучения к весу, вот он в виде функции:
function <b>learn</b>(inputVector, weightVector) {
weightVector.forEach(function(weight, index, weights) {
if (inputVector[index] > 0) {
<b>weights[index] = weight + learningRate;</b>
}
});
}
При использовании эта обучающая функция просто добавит наш коэффициент обучения к вектору веса активного нейрона, до и после круга обучения (или повтора) результаты будут такими:
// Original weight vector: [0,0,0,0]
// Neural Net output: 0.00 Error: 1
<b>learn(input, weights);</b>
// New Weight vector: [0,0.20,0,0]
// Neural Net output: 0.20 Error: 0.8
// Если это не очевидно, вывод нейронной сети близок к 1 (выдача курицы) — то, чего мы и
хотели, поэтому можно сделать вывод, что мы движемся в правильном направлении
Живой пример: Neural Net 003 [5].
Окей, теперь, когда мы движемся в верном направлении, последней деталью этой головоломки будет внедрение повторов.
Это не так уж и сложно, в природе мы просто делаем одно и то же снова и снова, а в коде мы просто указываем количество повторов:
var trials = 6;
И внедрение в нашу обучающую нейросеть функции количества повторов будет выглядеть так:
function <b>train</b>(trials) {
for (i = 0; i < trials; i++) {
neuralNetResult = evaluateNeuralNetwork(input, weights);
learn(input, weights);
}
}
Ну и наш окончательный отчет:
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 !
Живой пример: Neural Net 004 [6].
Теперь у нас есть вектор веса, который даст только один результат (курицу на ужин), если входной вектор соответствует реальности (нажатие на третью кнопку).
Так что же такое классное мы только что сделали?
В этом конкретном случае наша нейронная сеть (после обучения) может распознавать входные данные и говорить, что приведет к желаемому результату (нам всё равно нужно будет программировать конкретные ситуации):
Кроме того, это масштабируемая модель, игрушка и инструмент для нашего с вами обучения. Мы смогли узнать что-то новое о машинном обучении, нейронных сетях и искусственном интеллекте.
Предостережение пользователям:
Я пытался избежать математики и строгих терминов, но если вам интересно, то мы построили перцептрон [7], который определяется как алгоритм контролируемого обучения (обучение с учителем [8]) двойных классификаторов [9] — тяжелая штука.
Биологическое строение
Еще один шикарный ресурс 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
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! За эту версию благодарю Кирана Мэхера.
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("nError: ")
fmt.Print(math.Round(errorResult*100) / 100)
fmt.Print("nn")
}
}
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
}
Автор: NIX_Solutions
Источник [10]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/algoritmy/293012
Ссылки в тексте:
[1] Making a Simple Neural Network: https://becominghuman.ai/making-a-simple-neural-network-2ea1de81ec20
[2] Мозг: http://www.braintools.ru
[3] Neural Net 001: http://codepen.io/k3no/pen/GWyJgP
[4] Neural Net 002: http://codepen.io/k3no/pen/dvaGpX
[5] Neural Net 003: http://codepen.io/k3no/pen/qrJoXO
[6] Neural Net 004: http://codepen.io/k3no/pen/dvBZLe?editors=0012
[7] перцептрон: https://ru.wikipedia.org/wiki/%D0%9F%D0%B5%D1%80%D1%86%D0%B5%D0%BF%D1%82%D1%80%D0%BE%D0%BD
[8] обучение с учителем: https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D1%81_%D1%83%D1%87%D0%B8%D1%82%D0%B5%D0%BB%D0%B5%D0%BC
[9] двойных классификаторов: https://en.wikipedia.org/wiki/Binary_classification
[10] Источник: https://habr.com/post/423647/?utm_campaign=423647
Нажмите здесь для печати.