Нейросеть с нуля

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

Структура

Рассмотрим нейросеть из одного нейрона.

нейросеть из одного нейрона
Схема сети из одного нейрона

На входе сети два значения: 1 и x. b и w — это веса соответствующих связей. Как правило, нейрон обрабатывает суммарный сигнал, обозначаемый переменной net. net — это сумма произведений сигналов и соответствующих весов. В нашем случае

net = wx + 1 \cdot b

Выходной сигнал нейрона определяется функцией активности y(net). Пусть функцией активности будет тождественная функция:

y(net) = net

Тогда такая нейросеть будет эквивалентна выражению

y = wx + b

Расчет ошибки

Предположим, что на выходе, при данном значении x, нейрон должен выдавать результат t. В таком случае мы можем определить функцию расчета ошибки следующим образом:

E = \frac{1}{2}(y - t)^{2}

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

Обучение

На данном этапе становится ясно, что «мозгом» сети являются переменные w и b. Возникает вопрос: как следует изменить значения этих переменных, чтобы уровень ошибки для определенной пары (x,y) уменьшился? Ответить на этот вопрос поможет градиент функции ошибки. Найдем частные производные функции E по переменным w и b.

\frac{\partial E}{\partial w} = \frac{\partial E}{\partial y}\frac{\partial y}{\partial net}\frac{\partial net}{\partial w} \newline { } \newline \frac{\partial E}{\partial w} = (y - t) x \newline { } \newline \frac{\partial E}{\partial b} = \frac{\partial E}{\partial y}\frac{\partial y}{\partial net}\frac{\partial net}{\partial b} \newline { } \newline \frac{\partial E}{\partial b} = (y - t) \cdot 1

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

Таким образом, процесс обучения сети можно описать с помощью следующего алгоритма:

  1. Сформировать набор пар «аргумент — значение».
  2. Инициализировать w и b случайными ненулевыми значениями в интервале (-1, 1).
  3. Для всех пар «аргумент — значение»:
    • Задать аргумент.
    • Попустить сигнал через нейросеть.
    • Рассчитать градиент, соответствующий функции E.
    • Уменьшить w и b на соответствующие значения градиента.
  4. Если уровень ошибки для набора пар выше необходимого, вернуться к пункту 3.

Практика

Следующий этап — реализация данного алгоритма на языке C++. Все необходимые данные и методы будут описаны в рамках отдельной структуры.

#include <iostream> 
#include <math.h>
using namespace std;

struct Neuron {

double b, w, y, t, x, d;
Neuron(double w, double b) { // Инициализация весов нейрона
this->b = b;
this->w = w;
};

void forwrd() { // Прямой проход сигнала x
y = w*x + b;
};

void backwrd() { // Расчет производных и коррекция весов
d = y - t;
w -= d*x;
b -= d;
};

double calcEps() { // Ошибка - модуль разности результата и требуемого значения
return abs(y-t);
};
};

int main(int argc, char* argv[]) {
double x[] = {0.0, 1.0}; // аргументы и
double y[] = {0.0, 0.5}; // требуемые значения соответственно
double eps;
int size = sizeof(x)/sizeof(double); // количество аргументов

cout << "(x,y):";
for(int i=0; i<size; i++) // вывод точек, на которых обучается нейрон
cout << " (" << x[i] << "," << y[i] << ")";
cout << endl;

Neuron p(0.007, 0.005); // Инициализация нейрона p.
do {
eps = 0.0;
for(int i=0; i<size; i++) { // цикл по всем аргументам
p.x = x[i]; // установка аргумента
p.t = y[i]; // установка требуемого значения
p.forwrd(); // распространение сигнала в прямом направлении
eps += p.calcEps(); // суммирование ошибок
p.backwrd(); // расчет производных и коррекция весов
};
cout << "Sum eps = " << eps << endl; // вывод суммарной ошибки
} while(eps > 0.05);

// тест нейрона для произвольного аргумента
cout << "Test" << endl;
cout << "x = ";
cin >> p.x;
p.forwrd();
cout << "y = " << p.y << endl;
return 0;
};

Вывод программы:

(x,y): (0,0) (1,0.5)
Sum eps = 0.498
Sum eps = 0.493
Sum eps = 0
Test
x = 10
y = 5

В рассмотренном примере выбраны две точки для обучения. Так как через них можно провести единственную прямую, установка сколь угодно малого ограничения на eps не приведет к «зацикливанию». Ситуация поменяется, если таких точек будет больше и они не будут расположены на одной прямой. Тем не менее, смысл обучения от этого не теряется. В таком случае, обучая нейрон, мы найдем прямую, максимально близко расположенную к точкам обучения. Если, например, точки — это люди в очереди, то обученный нейрон — это прямая, вдоль которой все выстроились. Причем данная прямая будет обнаружена, несмотря на неточности в расположении людей.

Более сложный пример.

Добавить комментарий

Ваш e-mail не будет опубликован.