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

Нейроны в действии

Время на прочтение7 мин
Количество просмотров4.9K
Начиная знакомство с нейронными сетями и нейронами в частности, зачастую трудно представить как «оно» работает прочитав сухую теорию. Поэтому я предлагаю вам рассмотреть нейрон решающей простую, но очень наглядную задачу.

Задача: Определить четность или нечетность числа по его двоичному представлению.

Собственно говоря это задача классификации объектов с которой нейронные сети справляются достаточно хорошо (нейронные сети могут решать ограниченный спектр задач). Приступим.


Немного теории


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

Синтез сети


Синтез сети является в общем случае сложной задачей. В нашем случае для решения этой задачи нам хватит сети из одного нейрона. На входы нейрона будем подавать соответствующие разряды числа в двоичном виде (для простоты ограничимся диапазоном от 0 до 255). Т.е. наш нейрон будет иметь восемь входов и один выход.

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

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

Реализация


Класс на C# реализующий наш нейрон.

  1. public class Neuron
  2.   {
  3.     int[] input = new int[8];      //входы
  4.     double[] weight = new double[8];  //веса входов
  5.  
  6.     double mx = 0;           //средний вес
  7.     double sum = 0;           //сумма входов умноженных на вес
  8.     int k = 1;             //коэфициент обучения
  9.  
  10.     public Neuron()
  11.     {
  12.       for (int i = 0; i < 8; i++)
  13.       {
  14.         weight[i] = 1;       //начальные веса можно задать любые
  15.                       //согласно с принятыми ограничениями
  16.       }
  17.     }
  18.     public byte Analyze(byte b)
  19.     {
  20.       for (int i = 0; i < 8; i++)
  21.       {
  22.         input[i] = 0;
  23.       }
  24.       for (int i = 0; i < 8; i++)   //кривенькое преобразование в двоичный вид
  25.       {
  26.         if ((b / 2) != 0)
  27.         {
  28.           input[i] = b % 2;
  29.           b = Convert.ToByte(b / 2);
  30.         }
  31.         else
  32.         {
  33.           input[i] = b % 2;
  34.           break;
  35.         }
  36.       }
  37.  
  38.       sum = 0;
  39.       mx = weight.Sum() / 8;     //считаем средний вес
  40.  
  41.       for (int i = 0; i < 8; i++)
  42.       {
  43.         if (weight[i] > 0)     //считаем сумму
  44.           sum += weight[i] * input[i];
  45.       }
  46.  
  47.       if (sum > mx)          //определяем выход нейрона
  48.         return 1;
  49.       else
  50.         return 0;
  51.     }
  52.     public void Yes()          //обучение при верном ответе
  53.     {
  54.       double s = weight.Sum();
  55.       for (int i = 0; i < 8; i++)
  56.       {
  57.         weight[i] += input[i] * (weight[i] / s) * k;
  58.       }
  59.       this.Normalize();
  60.     }
  61.     public void No()          //обучение при неверном ответе
  62.     {
  63.       double s = weight.Sum();
  64.       for (int i = 0; i < 8; i++)
  65.       {
  66.         weight[i] -= input[i] * (weight[i] / s) * k;
  67.       }
  68.       this.Normalize();
  69.     }
  70.     private void Normalize()      //чтобы коэфициенты не зашкаливали и для наглядности
  71.     {                  //оставляем в них не более двух разрядов до запятой
  72.       double min = weight.Min();
  73.       double max = weight.Max();
  74.       int pow = 0;
  75.       double b = max / 10;
  76.       while (b > 1)
  77.       {
  78.         b = b / 10;
  79.         pow++;
  80.       }
  81.  
  82.       for (int i = 0; i < 8; i++)
  83.       {
  84.         weight[i] = weight[i] / Math.Pow(10, pow - 1);
  85.       }
  86.     }
  87.     public void Reset()         //сброс весов
  88.     {
  89.       for (int i = 0; i < 8; i++)
  90.       {
  91.         weight[i] = 1;
  92.       }
  93.     }
  94.                       //свойства по вкусу
  95.     public string Bytes
  96.     {
  97.       get
  98.       {
  99.         string str = "";
  100.         for (int i = 0; i < 8; i++)
  101.         {
  102.           str += input[i].ToString();
  103.         }
  104.         return str;
  105.       }
  106.     }
  107.     public string Weights
  108.     {
  109.       get
  110.       {
  111.         string str = "";
  112.         for (int i = 0; i < 8; i++)
  113.         {
  114.           str += weight[i].ToString();
  115.           str += " ";
  116.         }
  117.         return str;
  118.       }
  119.     }
  120.     public string Mx
  121.     {
  122.       get
  123.       {
  124.         return mx.ToString();
  125.       }
  126.     }
  127.     public string Sum
  128.     {
  129.       get
  130.       {
  131.         return sum.ToString();
  132.       }
  133.     }
  134.   }
* This source code was highlighted with Source Code Highlighter.

Замечания


Обучение нейрона организовать очень просто, нужно альтернативным способом проверить четность (нечетность) числа и сказать ему верный или нет был его ответ. В итоге у правильного обученного нейрона все веса кроме веса при первом разряде (собственно если он равен 1 число нечетное, если 0 то четное) станут крайне малыми, что говорит о том что они не как не влияют на четность (нечетность), а этот единственный вес будет расти, что говорит о его значимости. Наш нейрон безошибочно будет работать в выбранном диапазоне чисел уже после пары тысяч обучающих прогонов, а вот если, например, веса поменять на 1 и 0, и изменять соответственно на единицу то нейрон обучить можно за десяток прогонов и у обученного нейрона все веса кроме веса при первом разряде будут равны 0, а он будет равен 1.
Теги:
Хабы:
Всего голосов 28: ↑25 и ↓3+22
Комментарии21

Публикации