Pull to refresh

Разработка «универсальной» библиотеки для создания нейронной сети (Начало)

Reading time5 min
Views4.3K
Предыстория

Я, простой смертный, даже и не думал о ИИ как о универсальном помощнике, спокойно себе кодил под АРМ-ы на сях (С/С++), и все бы- ничего, если не одно НО.
Как-то познакомился я с человеком на форуме посвященному тематике кодинга под АРМ, довольно долгое время он многое мне разъяснял, помогал, +он и сам сделал не мало интересного. Но как то раз речь зашла о ИИ и вот тогда меня и заитересовал его ответ в стиле «Живет вот у меня на компе что то, что тебе интересно, неплохой дебаггер, таск менеджер +бот для аськи, который уже не раз тест Тьюринга прошел ». Я, конечно, как вполне адекватный человек не поверил, т.к. исходники давать он отказался, готовую программу он обещал дать только если взломаю его комп и получу доступ к ФС. Несколько лет с тех пор прошло, и еще не раз поднималась тема на счет его ИИ. Хотя опытный образец мне получить так и не удалось, да и на 100% я не уверен, что он вообще у него есть, но это и не важно, т.к. каждое наше общение зарождало во мне идею напейсать свой ИИ.

Начало

Для начала естественно надо было составить список всего необходимого для разработки, когда я выбрал за основу свой любимый С/С++, друг подсказал мне, что «Ваших интелеГтов на сях обычно не пишут, и выбирать для этого нужно декларированный язык». Мне эта идея сразу не понравилась из за того, то придется заново изучать новый, совершенно другой по принципу язык, и я все-таки решил рискнуть.
Так был выбран язык С/С++.
Далее дело стояло за малым (как я тогда считал) выбор библиотеки на которой начнется разработка и вот тут был встречен второй подводный камень. Пересмотрел я много статей по ИНС, перековырял много библиотек, но так и не нашел нужную из-за того, что либо библиотека была не достаточно гибкой, либо она была сложна для понимания, либо не удовлетворяла по скорости работы. Было конечно еще одно НО, о нем позже.
Так была поставлена задача написать свою библиотеку.
Поехали

Среду я выбрал Rad Studio, чувствуя тонны ненависти постараюсь объясниться:
Мне нужна быстрая «формошлепалка» для проверки, чтобы не затрачивать много времени на интерфейс
Нужна была простота переноса на Delphi т.к. многие знакомые выбрали его как основной язык, а Rad Studio это основная среда для него
Я не собирался сильно прибивать код к VCL для его более простого переноса на gcc,MS VS.
Я постараюсь использовать минимальный набор средств для более простого межплатформного переноса

Итак, основное строение каждой сети это
  • Связи
  • Нейроны
  • Слои

А для поставленной задачи мне нужно было их как то отвязать друг от друга но в то же время заставить их работать вместе. Сразу же на ум пришла идея- Классы но немного подумав, взвесив все +за и –против пришлось от них отказаться. Сеть должна быть рассчитана на количество нейронов/слоев/связей ограниченного только памятью, +скорость работы должна быть довольно высока, что бы эта сеть не стала тормозом, +гибкость сети должна была позволять простую OnLine работу как со слоями, так и с каждым нейроном в этом слое, так и со связями каждого нейрона в отдельности (Это как раз то, чего не хватало ни в одной найденной мной free библиотеке).
Для этого были выбраны связные списки, и решено было использовать указатели. Давайте взглянем на каркас структуры, наполнять ее пока не будем…

typedef struct _link{

}LINK;

typedef struct _neuron{

struct _neuron *prev,*next;
}NEURON;

typedef struct _n_layer{

struct _n_layer *prev,*next;
}NLAYER;

Теперь идея в том, как это все связать?
Немного подумав решил сделать так: 1 блок связи соединяет 2 нейрона-> каждый экземпляр связи должен быть легко доступным и относиться только к 2-ум конкретным нейронам, но у нейрона может быть неограниченное количество связей (я старался делать библиотеку без программных ограничений). Нейроны в свою очередь для более простой работы должны находиться в слое, можно было и не использовать слоев но работа с такими скоплениями нейронов была бы крайне затруднена. Но не только слой должен иметь указатель на принадлежащие ему нейроны, но и каждый нейрон должен иметь указатель на слой, в котором он находиться, но это уже понадобиться для более простой и быстрой технической работе с сетью.

Так структура перекочевала в другое состояние более продуманное, как мне кажется.
typedef struct _link{

void *from,*to;		//указатель на LINKL
}LINK;

typedef struct _link_list{
LINK *link;
void *Neuron;		//указатель на сами_знаете_что
struct _link_list *next,*prev;
}LINKL;

typedef struct _neuron{
LINKL *in,*out;
void *Layer;		//указатель на сами_знаете_что
struct _neuron *prev,*next;
}NEURON;

typedef struct _n_layer{
NEURON *first,*end;
struct _n_layer *prev,*next;
}NLAYER;

На этом этапе я пишу обработчики для удаления/добавления элемента в список.
Но опять же эта структура не заполнена и в ней не хватает одного, очень важного момента…
Давайте прервемся и подумаем, разве когда вы куда то смотрите, вы не можете думать?
Или же когда вы что то слышите вы не можете видеть? Ответ- нет.
Именно поэтому появилась идея сделать потоки!

Этого я не встречал даже в платных библиотеках.
Как же это должно работать? Да очень просто, всего то нужно добавить 1 параметр в каждую ветвь основного строения, это будет параметр state- статус он будет указывать возможна ли дальнейшая работа с тем или иным элементом сети.
И снова наше строение модифицируется.

#define STATE_NOT_READY	0
#define STATE_READY		1

typedef struct _link{
void *from,*to;
}LINK;

typedef struct _link_list{
LINK *link;
char state;
void *Neuron;
struct _link_list *next,*prev;
}LINKL;

typedef struct _neuron{
char state;
LINKL *in,*out;
void *Layer;
struct _neuron *prev,*next;
}NEURON;

typedef struct _n_layer{
NEURON *first,*end;
char state;
struct _n_layer *prev,*next;
}NLAYER;


Вуаля, каркас нейро сети готов.

Теперь перейдем к более вкусным плюшкам, и чтобы не оказаться пустозвуком, подкладываю вам на изучение готовую библиотеку написанную мной не без помощи многоуважаемого Ilya90 респект ему!

NewNeuroLib Tonich

Пасс:XabraZabra

Заключение

В данной статье описан мой подход к созданию «умной» нейронной сети, теперь осталось только придумать, чем заполнить каждую ветвь, скорее всего тип данных я выберу double, но 3 вещи для меня непонятны и пока я их не пойму, опытный образец не увидит свет.
  1. (решено)По какому условию создается новая связь и/или как выбирается от какого нейрона до какого она будет вести.
  2. (решено)По какому условию создается новый нейрон (от чего и зачем он создаеться)
  3. (решено частично)Когда нейрон должен «выстрелить»? Когда все весы связей расставлены или же не обязательно, и если так то как будет выглядеть функция, способная работать при постоянном различном количестве и значениях весов связи?

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

Если будет интерес, могу выложить пример использования, но без библиотеки SaveLoad (за нее я еще нобелевку не получил Ы)


Добро пожаловать в комменты!

Исследованные материалы

Конечно же многие статьи на Хабре.
FANN-библиотека на которой заострял внимание больше всего.
Сайт с которого прочитал большое колличество статей.
Очень интересная статья, которая навела меня на мысль (:
Tags:
Hubs:
-4
Comments19

Articles

Change theme settings