В статье Нейросети для чайников. Начало автор Paul_Smith доступно показал насколько просто создать нейронную сеть для распознования картинок. Но есть одно но — то что он описал нейронной сетью не является. Перед его следующей статьей хочу рассказать вам как решить ту же задачу, но с использованием нейронной сети Кохонена.
Итак, распознавать мы будем цифры, написанные белым по черному, такие как эти:
Картинки 45 на 45 пикселей, а значит входов в нашу нейронную сеть будет 45 * 45.
Для простоты, распознаем только цифры от 0 до 5, поэтому нейронов у нас будет 6 — по одному на каждый ответ.
Cтруктура нашей нейросети:
Каждая связь входа сети с нейроном имеет свой вес. Импульс, проходя через связь, меняется: импульс = импульс * вес_связи.
Нейрон получает импульсы от всех входов и просто суммирует их. Нейрон набравший больший суммарный импульс побеждает. Все просто, реализуем!
Классы для представления элементов сети (C#):
// Вход
public class Input
{
// Связи с нейронами
public Link[] OutgoingLinks;
}
// Связь входа с нейроном
public class Link
{
// Нейрон
public Neuron Neuron;
// Вес связи
public double Weight;
}
public class Neuron
{
//Все входы нейрона
public Link[] IncomingLinks;
// Накопленный нейроном заряд
public double Power { get; set; }
}
Создание и инициализация сети дело скучное, кому интересно — смотрите приложенный исходник. Остановлюсь лишь на том, что цвет пикселя это число от 0 до 255, причем 0 — это черный, 255 — белый, цвета между ними — градации серого.
Состояние класса KohonenNetwork это массив Input[] и массив Neuron[]:
public class KohonenNetwork
{
private readonly Input[] _inputs;
private readonly Neuron[] _neurons;
...
}
Предположим, что наша сеть уже обучена. Тогда, чтобы узнать что изображено на картинке мы вызовем метод Handle, там все перемножится, сложится и найдется максимум:
// Пропустить вектор через нейронную сеть
public int Handle(int[] input)
{
for (var i = 0; i < _inputs.Length; i++)
{
var inputNeuron = _inputs[i];
foreach (var outgoingLink in inputNeuron.OutgoingLinks)
{
outgoingLink.Neuron.Power += outgoingLink.Weight * input[i];
}
}
var maxIndex = 0;
for (var i = 1; i < _neurons.Length; i++)
{
if (_neurons[i].Power > _neurons[maxIndex].Power)
maxIndex = i;
}
//снять импульс со всех нейронов:
foreach (var outputNeuron in _neurons)
{
outputNeuron.Power = 0;
}
return maxIndex;
}
Но перед тем как спрашивать у сети что-либо, её надо обучить. Для обучения предъявляем картинки и указываем что на них нарисовано:
Обучение — это изменение весов связей:
public void Study(int[] input, int correctAnswer)
{
var neuron = _neurons[correctAnswer];
for (var i = 0; i < neuron.IncomingLinks.Length; i++)
{
var incomingLink = neuron.IncomingLinks[i];
incomingLink.Weight = incomingLink.Weight + 0.5 * (input[i] - incomingLink.Weight);
}
}
После обучения на двух шрифтах, нейронная сеть различает цифры и из других шрифтов. В том числе будет пройден контрольный тест на таких вот цифрах:
Конечно, для расспознавания капчей такая поделка не годится — все перестает работать, стоит только сдвинуть, растянуть или повернуть изображение.
Однако всем становится понятно, что использовать нейронные сети не так уж и сложно, если начинать с простых примеров.
Исходник поделки
Автор: Kn4av
Возобновите пожалуйста доступ к исходникам. Как не пытаюсь понять и реализовать описанное в статье – не получается. Исходники бы очень помогли. Заранее СПАСИБО!
Ссылка на исходник не работает, а посмотреть на эту сеть очень бы хотелось
:( Присоединяюсь с просьбой исходника…
Скажите, а можно и мне исходник посмотреть?
Ссылка на исходник не работает, исправьте пожалуйста, очень нужно.