Разбираем нейронную сеть. C#

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

Пару слов, необходимо уделить устройству этой самой "великой" и "ужасной" нейронной сети. Долгое количество времени люди ходили взад и вперед и размышляли над вопросом: (в чем смысл жизни?)
Как можно распознавать образы?

Ответов было огромное множество. Тут и различные эвристики, и сравнения по шаблонам и многое-многое. Одним из ответов была нейронная сеть. [К слову сказать нейронная сеть может не только распознавать образы]

Итак. Структура нейронной сети. Представьте себе такую картину: паук сплел сеть и сеть словила муху. То место на которое попала муха и есть нейрон, который был "максимально" близок к цели. Нейронная сеть состоит из нейронов, которые "описывают"
шансы того или иного события. Описание "вероятности" события (каждого нейрона) может храниться (к примеру) в отдельном файле.



Теперь переходим к главной теме разговора этого вечера.

Как устроена нейронная сеть. Как происходит ее обучение и распознание.

Пример структуры нейронной сети отчеливо виден на этой картинке:




На вход поступает множество входных сигналов X. Которые умножаются на множество весов W (Xi * Wi). В нейроне производится подсчет суммы произведений и на выход отправляется некоторое число.
После подсчета значений у всех нейронов, производится поиск наибольшего значения. Это наибольшее значение и считается корректным ответом на вопрос. Программой выдается образ, который описывается найденным нейроном.
В режиме обучения пользователь имеет возможность подправить результат (основываясь на своем опыте) и тогда программа произведет пересчет весов нейронов.
Формула перерасчета примерно следующая: W[i] = W[i] + Speed*Delta*X[i] - здесь
W[i] - вес i-го элемента,
Speed - скорость обучения,
Delta - знак (-1 или 1),
X[i] - значение i-го входящего сигнала (во многих случаях 0 или 1)

Зачем используется delta?

Разберем такой случай.

На вход программе подается картинка с цифрой 6. Нейронная сеть распознала цифру 8. Пользователь правит цифру на 6. Что происходит далее в программе?

Программа пересчитывает данные для двух нейронов, описывающих число 6 и число 8, причем для нейрона, описывающего число 6 delta будет равна 1, а для 8 = -1


Как задается параметр скорости?

Данный параметр, чем меньше тем, дольше и точнее(качетственнее) будет происходить обучение сети, и чем больше, тем быстрее и "поверхностней" будет происходить обучение сети.

Параметр Speed может задаваться как вручную, пользователем, так и в ходе выполнения программы( к примеру const)

Как видно, весы символов также должны быть определены. А чем они определяются изначально? на самом деле тут также все просто. Определяются они совершенно случайно, это позволяет избежать "предвзятости" нейронной сети. Обычно, интервал случайных значений небольшой -0.4...0.4 или -0.3..0.2 и т.п.



Теперь переходим к самой интересной части. Как это закодировать!


Создадим два класса - класс Нейрон и класс Сеть (Neuron и Net соответственно)

Опишем основные задачи класса Neuron:

- Реакция на входной сигнал

- Суммирование

- Корректировка

(как дополнительно можно добавить чтение из файла, создание начальных значений, сохранение. Оставим это на "совести" читающих)

Переменные внутри класса Neuron:symbol
- Идентификатор "опознания" - LastY

- Описываемый образ - symbolsymbol

- Весы List w;

- Количество элементов PointCount



Реализуем алгоритмы Реакции, корректировки и суммирования:

  1. public double Y(List <byte > x)
  2. {
  3.    double Result;
  4.     Result = S(x);//подсчет
  5.     if (Result >= 0 ) return Result;
  6.     else return 0 ;//реакция
  7. }
  8. double S(List <byte > x)
  9. {//Суммирование
  10. double result = 0 ;//результат
  11. for (int i = 0 ; i < x.Count; i++)
  12.    {//подсчет суммы произведения
  13.     result += w[i] * x[i];
  14.    }
  15.   return result;//собственно выдача
  16. }
  17. public void Correct(List <byte > x, int delta, double speed)
  18. {//Корректировка весов по x, delta и speed
  19.   change = true;
  20. for (int i = 0 ; i < w.Count; i++)
  21.     w[i] = w[i]+ (double)speed * delta * x[i];
  22. }

This code was highlighted with code.xnim.ru


Как можно заметить они доваольно простые.


Теперь основные функции класса Net:

- Добавление нового нейрона

- Распознавание

- Корректировка по всем нейронам

Основной "рабочей" единицей в этом классе - список нейронов - List net = new List();

Опишем функции:

  1. public char Recognize(List <byte > x)
  2. {
  3. char result = ''\
    ''
    ;
  4. lastNeuron = -1;
  5. double max = 0 ;
  6. foreach (Neuron n in net)
  7.   {//подсчет и выбор максимального для каждого нейрона
  8.    double Candidate = n.Y(x);
  9.    if (Candidate > max)
  10.     {
  11.      max = Candidate;
  12.      result = n.Symbol;
  13.      lastNeuron = net.IndexOf(n);
  14.     }
  15.   }
  16. return result;
  17. }
  18. public char Correct(char symbol, List <byte > x, double speed)
  19. {//корректировка группы нейронов
  20. bool check = false;
  21. for (int i = 0 ; i < net.Count; i++)
  22.    {//поиск необходимых и выборочная корректировка
  23.     if (symbol == ''\
    ''
    )
  24.      {
  25.       if (net[i].LastY > 0 )
  26.       net[i].Correct(x, -1, speed);
  27.      }
  28.      else
  29.       {
  30.       if (net[i].Symbol == symbol)
  31.       {
  32.        net[i].Correct(x, 1 , speed);
  33.        check = true;
  34.       }
  35.       else if (net[i].LastY > 0 )
  36.          net[i].Correct(x, -1, speed);
  37.      }
  38.    }
  39. if (!check)
  40.   {
  41.    net.Add(new Neuron(symbol, x.Count-1));
  42.    net[net.Count - 1 ].Correct(x, 1 , speed);
  43.    StreamWriter write = new StreamWriter("chars.txt" , true);
  44.    write.WriteLine(symbol);
  45.    write.Close();
  46.   }
  47. return Recognize(x);
  48. }
  49. public void AddNeuron(char symbol)
  50. {
  51.     net.Add(new Neuron(symbol, resolution));
  52. }

This code was highlighted with code.xnim.ru


Как видно данный код также не является сложным.

Добавление таких функций как сохранение, загрузка, оставим для "слушателей"



Таким образом мы попытались поработать с однослойной нейронной сетью и создать свою сеть для распознавания неких символов. Данную нейронную сеть легко "перевести" на распознавание образов, групп символов и т.д.
2012-04-30