Posts Tagged ‘нейроредактор’

ASSERTоподобные точки останова

Пятница, Ноябрь 27th, 2009

Обычные инструкции типа ASSERT, как и обычные точки останова, останавливают исполнение в отладчике. Нейронные точки останова останавливают работу нейросети в Нейроредакторе без прерывания программы. Но устанавливать однотипные точки останова после каждого запуска – ненужная рутина. Поэтому их можно перед запуском создавать программно. Но программное создание такой же точки останова, как и в интерфейсе Нейроредактора, которая может редактироваться через ГИП, не тривиально, и занимает несколько строк. Для некоторых стандартных случаев типа остановки каждые несколько циклов созданы функции-обертки. Но можно пойти еще одним путем – использовать упрощенные точки останова, которые не отображаются в интерфейсе, и которые невозможно изменить. Условно говоря – вызвать функцию типа maybeStopNeuroNet(bool) с условием проверки точки останова. Еще удобнее использовать макрос: если условие сработает – нейросеть остановится после завершения прохода по всем нейронам, а условие, которое сработало, будет выведено в журнал исполнения. Булевское условие можно писать любое, даже такое, которое не входит в список полей Д3, по которым только и работают обычные точки останова Нейролаборатории. Например, можно объявить локальную переменную, и по ней останавливать ИНС.
Еще один вариант – использовать QtScript, и код точек останова вводить в виде JavaScript в Нейролаборатории. Но этот способ требует существенного усложнения кода, и пока не нужен.

JIT и Нейролаборатория

Четверг, Ноябрь 26th, 2009

В теории, JIT можно применять для компиляции точек останова. Компилировать можно код итераторов вместе с кодом проверок условий. Может совмещаться проверка нескольких точек останова при прохождении одного нейрона или иного объекта.

Пространства моделирования ИНС

Четверг, Октябрь 15th, 2009

В некоторых проектах по моделированию мозга, либо по моделированию нейросетей для ИИ, применяется модель нейронов в трехмерном пространстве. Какие преимущества дает такой подход? (далее…)

Видео Нейролаборатории

Суббота, Июнь 13th, 2009

Что делать в ночь с Пт на Сб, когда голова после рабочей недели уже не работает, а делать что-то хочется? Можно сделать видео :). Треть видео занимает слайд-шоу – экранные снимки эволюции Нейролаборатории. Дальше большую часть занимает видео демонстрации ее работы. Финальные кадры напоминают, что ИИ будет использован в первую очередь для Войны.

Рекомендую в самом начале проигрывания остановить и подождать две секунды для буферизации.
embedded by Embedded Video

Download Video
Музыка – Fear Factory «Self Immolation (Liquid Sky Mix)», видео – Slayer «Final Six».

№93 NL UI: Выбор координат нейронов для карты нейронов

Четверг, Апрель 23rd, 2009

Нейронная карта/поле нейронов полезна для удобства отладки, для придания большей образности процессу разработки, для подготовки пояснительных схем. Как нейроны располагаются на этом поле? Доступно и ручное перетаскивание нейронов, чего достаточно для построения обучающих схем. В этой заметке рассматривается автоматическое расположение.
При создании окна карты, в ИНС уже может присутствовать большое количество нейронов. Например, ИНС может быть загружена из файла, либо это могут быть предварительно созданные сенсорные и эффекторные нейроны. Либо окно с картой нейронов может быть создано после некоторого времени работы ИНС.
По умолчанию, уже существующие нейроны располагаются квадратом, по порядку перечисления, который совпадает с порядком их создания.
Как располагать новые нейроны? Сколько их будет создано в процессе работы ИНС – окну заранее не известно. Желательно располагать нейроны так, чтобы обе координаты задействовались в примерно равной степени. Принята следующая схема: новые нейроны располагаются вправо от последних добавленных; при достижении некоторой внутренней границы происходит «перевод строки». После перевода «курсора» для вставки следующего нейрона, длина строки будет на единицу больше. Поэтому рост ИНС в карте будет напоминать треугольник (или трапецию – в зависимости от начальных условий). Со временем нижнее основание будет расти все больше. При этом, верхняя правая часть окна не используется, она остается пустой. Потери свободного пространства при таком способе расположения – около 50%.
Благодаря использованию Qt, карта поддерживает масштабирование.


Рис. 93-1 Автоматическое трапециевидное расширение ИНС при добавлении новых нейронов

На рис. 93-1 показана тестовая ИНС, у которой квадратом были расположены нейроны, существовавшие на момент инициализации карты. Остальные нейроны были добавлены позже.
За один такт работы ИНС может быть создано несколько нейронов. Особенно, если ИНС работает на основе кластеров. Неплохо было бы расположить их не по прямой линии, а как-то более компактно. Так и сделано: если в ИНС появляются новые нейроны, то карта группирует нейроны по циклу создания, и каждую такую группу размещает отдельно, в виде прямоугольника. Размещение начинается с той же позиции, где должен был расположиться один новый нейрон. Величина сторон прямоугольника выбирается на основе квадратного корня от числа нейронов в размещаемой группе. После размещения группы, текущий курсор смещается примерно так, как обрабатывается курсор в случае одного нейрона. Пример этого типа размещения показан на рис. 93-2. Для примера использую старые снимки экрана, так как сейчас этот режим нигде не задействован.


Рис. 93-2 Автоматическое размещение нейронов, сгруппированных по циклу создания, прямоугольниками

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


Рис. 93-3 Нечетное количество нейронов при прямоугольном размещении помогает визуально определять кластеры

Но хочется получить более точный контроль над размещением нейронов в кластере. Например, хочется, чтобы нейроны, работающие с признаками, размещались внизу кластера, а нейроны выхода – вверху. Решение-заплатка – подбирать очередность создания нейронов разных типов в кластере так, чтобы получить необходимое расположение.
При росте количества нейронов в кластере это решение становится совсем некрасивым. Кластеров может быть несколько типов – например, кластеры памяти, а также отдельные нейроны цепочек нечеткого распознавания. Поэтому сейчас в НЛ используется следующее решение. ИНС может переопределить метод для возврата объекта-«расположителя»:

  1. //У объекта-«расположителя» длинное название. Ранее, карты нейронов
  2. //располагали нейроны на основе целочисленных индексов стандартной сетки. Потом было
  3. //принято решение перейти к расположению на основе индексов с числами с плавающей точкой.
  4. //Поэтому и название содержит FloatIndexPlacer.
  5. //(NeuroItem – имя класса нейрона в двухмерной карте)
  6. virtual NeuroItemsFloatIndexPlacerAbstract* getNeuroItemsFloatIndexPlacer()=0;

Определение этого класса содержит единственную функцию:

  1. virtual void placeByNeuron(IN bioId id, OUT QList<QPair<bioId, QPointF> > & listPlacedNeurons)=0;

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

  1. //QNLBrain – родительский класс для любой ИНС в Нейролаборатории
  2. //в нем есть следующая функция, которая применяется только для краткости кода:
  3. void QNLBrain::placeNeuron(CommonNeuron* pn, qreal x, qreal y, OUT QList<QPair<bioId, QPointF> > & listPlacedNeurons)
  4. {
  5.         listPlacedNeurons.push_back( QPair<bioId, QPointF>(pn->id(), QPointF(x, y)));
  6. }
  7.  
  8. //пример расположения нейронов кластера на карте:
  9. void BrainB1::placeByNeuron(IN bioId id, OUT QList<QPair<bioId, QPointF> > & listPlacedNeurons)
  10. {
  11.         neuron* pn = GetNeuronById(id);
  12.         ASSERT(pn);
  13.         //получить кластер по нейрону. В ИНС Б1 все нейроны принадлежат кластерам
  14.         TCC* tcc = getTcc(pn);
  15.         ASSERT(tcc);
  16.         placeNeuron(tcc->down   , 0.0, 0.0, listPlacedNeurons);
  17.         placeNeuron(tcc->ninPrev, 0.0, 1.0, listPlacedNeurons);
  18.         placeNeuron(tcc->help   , 0.5, 1.7, listPlacedNeurons);
  19.         placeNeuron(tcc->nout   , 1.0, 0.0, listPlacedNeurons);
  20.         placeNeuron(tcc->nin    , 1.0, 1.0, listPlacedNeurons);
  21. }

Результат будет выглядеть так:


Рис. 93-4 Результат выполнения приведенного кода

Забегая вперед, вот как выглядит схема кластера ИНС Б2:


Рис. 93-5 Схема кластера ИНС Б2 в двухмерной карте нейронов

В ИНС Б2, нейроны цепочки нечеткого распознавания располагаются отдельно от основных кластеров: нейроны SL0 чуть ниже, посередине кластера, а SL1 – на одну позицию выше:


Рис. 93-6 Пример расположения нескольких видов нейронных цепочек на карте

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

Обновление: код уже переписан. В первой версии статьи, до переписывания, было следующее:
Подытоживая, можно добавить, что на текущий момент, код по выбору координат и смещений в самой карте – один из самых некрасивых во всей Нейролаборатории. В нем остались пережитки нескольких старых архитектурных решений, принятых в мою бытность начинающим разработчиком: работа с целочисленными индексами (можно оставить только плавающие), возможность устанавливать ограничения на рост (что было нужно при упаковке нейронов в другие контейнеры, но более правильное решение – разрешить рост контейнеров), возможность обмена осей x и y (правильно делать на основе прокси-объекта с тем же интерфейсом, а не на основе вездесущих проверок с перестановками, которые могут невзначай поменять оси лишний раз). Если выпадут пару свободных месяцев – может, исправлю. А сейчас, с учетом приоритетности, устраивает и текущий результат.

№92 Мозгокод на С++ в Нейролаборатории

Понедельник, Апрель 20th, 2009
«№40 О реализации нейронов в НЛ 3.0» ( http://neurocod.net/blog/tag/2008/08/№40-о-реализации-нейронов-в-нл-30 )
«№82 Сокращенная запись алгоритмов ИНС с применением контуров и виртуальных связей. “Мозгокод”.» ( http://neurocod.net/blog/tag/2009/02/№82-сокращенная-запись-алгоритмов-инс )

При моих ресурсах, создавать транслятор с Мозгокода на какой-нибудь другой язык нецелесообразно. Особенно, когда С++ позволяет настолько легко приближаться к Мозгокоду в форме записи.
В шаблонный класс NLBrain добавлен шаблонный класс «_НейронныйКонтур» (_NeuroCircuit). Этот шаблонный класс принимает шаблонный параметр – тип списка нейронов, с которыми он будет работать. Напомню, что каждый нейрон содержится в двух списках – списка всех нейронов ИНС и списка нейронов того же числового типа. От этого класса наследуются класс NeuroCircuit (без знака подчеркивания), который работает с нейронами некоторого типа («настоящий» контур), а также класс AllNeuronsCircuit, который работает со всеми нейронами ИНС. Несмотря на то, что он не является «настоящим» контуром, при помощи него удобно записывать команды для исполнения всей ИНС, да еще в том же коротком стиле, что и для обычных контуров.

Чтобы код был понятнее, (несмотря на небольшое увеличение набираемого текста) используются не операторы С++, а обычные функции. Например, функции по простому обмену полей, без вычисления угасания сигналов:

  1. template<typename NeuroLinkedListType>
  2. class _NeuroCircuit: public INeuroCircuit
  3. {
  4. public:
  5.     //SwapC == Swap Cycles
  6.     void SwapC()
  7.     {
  8.             UINT64 ret = 0;
  9.             NeuroLinkedListType::iterator iter(m_listByType);
  10.             for(;iter;iter++)
  11.             {
  12.                     neuron* pn = iter;
  13.                     pn->setCurActivation(pn->nextActivation());
  14.             }
  15.             logSwapC(count());
  16.     }
  17.     void SwapC(signal_t nextAct)
  18.     {
  19.             NeuroLinkedListType::iterator iter(m_listByType);
  20.             for(;iter;iter++)
  21.             {
  22.                     neuron* pn = iter;
  23.                     pn->setCurActivation(pn->nextActivation());
  24.                     pn->setNextActivation(nextAct);
  25.             }
  26.             logSwapC(count(), nextAct);
  27.     }

Каждый контур типа NeuroCircuit ассоциируется с некоторым числовым типом нейрона, и принимает строковое описание этого типа. Именно по этой информации происходит поиск символьного описания типа нейрона в большинстве случаев. Логично, что для создания нейрона этого типа можно также использовать объект «нейронный контур» – так не нужно заботиться о числовых типах.
имяКонтура.CreateNeuronMinimal()
«Минимальное» создание нейрона означает и напоминает, что не производится наполнение полей, специфических для данной ИНС.
Самые важные функции – это шаблонные функции, позволяющие выполнять операции над нейронами контура одной строкой:

  1. typedef bool (_neuron::*NeuronCondition)()const;
  2. typedef void (_neuron::*NeuronAction)();
  3. typedef void (*StaticNeuronAction)(neuron*);
  4. //для каждого нейрона данного контура, если выполняется условие allowCondition,
  5. //выполнить действие action
  6. template<NeuronCondition allowCondition, NeuronAction action>
  7.                 UINT64 forallNN(NeuroThread *thread);
  8. template<NeuronCondition allowCondition, StaticNeuronAction action>
  9.                 UINT64 forallNS(NeuroThread *thread);//S == Static action
  10. //для всех нейронов данного контура, если выполняется условие allowConditionForA,
  11. //получить по внутрикластерной виртуальной связи соответствующий нейрон контура other,
  12. //и для него вполнить действие actionForB
  13. template<NeuronCondition allowConditionForA, StaticNeuronAction actionForB, typename NeuroCircuit2>
  14.                 UINT64 VLinkNS(NeuroCircuit2 & other, NeuroThread *thread);
  15. // И еще несколько функций, в том числе – перегруженых
  16.  

У функций применяются суффиксы, описывающие типы шаблонных параметров. Например, S означает статическую функцию действия с нейроном (обычно – статическая функция соответствующей ИНС), а N – метод самого нейрона. Суффиксы введены, так как перегрузка шаблонных функций мне не удалась (а может, она и невозможна по стандарту С++ – не стал разбираться). Когда стоял выбор, передавать адреса функций для исполнения в качестве обычных или шаблонных параметров, я выбрал последнее, в надежде на то, что компилятору будет легче оптимизировать код. Правда, надежда не подтвердилась – в релиз-версии, вместо подстановки тел функций действий, компилятор, как показывал дизассемблер, создавал вызовы тех функций, которые были шаблонными параметрами. Но это пока не страшно. При необходимости, всегда можно будет перейти на макросы.
Также, почти каждая функция в классе _NeuroCircuit создает текстовое описание производимого действия, которое параметризируется именем контура. После создания описания, функция вызывает другую стандартную функцию, для облегчения отадки ИНС. Эта функция проверяет, не сделать ли паузу в исполнении. Так можно производить пошаговое исполнение ИНС без применения обычного отладчика среды разработки (типа Visual Studio). Небольшой шаг на пути к цели – сделать Нейронную Лабораторию интегрированной средой разработки ИНС. Во время паузы, текстовое описание шага выводится в строку состояния. Также, каждое такое описание заносится в список истории исполнения нейронных контуров, дополнительно параметризируясь количеством нейронов, которые приняли участие в исполнении. Для функций, принимающих условие разрешения для выполнения действия, число будет равно числу нейронов, для которых условие выполнилось. Вся эта информация доступна в окне «История нейроконтуров». Для хранения одинаковых строк история нейроконтуров использует пул строк.


Рис. 92-1 Окно истории срабатывания нейронных контуров. Видно переход от запоминания ко сну - не только по описаниям состояния, но и по смене последовательности срабатывания контуров.

«История нейроконтуров» напоминает электроэнцефалограмму. Если добавить визуализацию количества нейронов, которые были активны за каждый вызов функции нейроконтура, это была бы почти электроэнцефалограмма.
Пример того, как легко программировать с объектами нейроконтуров – функция стандартного ассоциативного спуска на признаки, и приведения сигналов назад «наверх», чтобы получить все похожие кластеры (эта функция используется во время различных фаз сна):

  1. void BrainB2::DownAndUp(NeuroThread*thread)
  2. {
  3.         nDown.SwapC(0);
  4.         nDown.forallNS< &neuron::isActive, &SendSignalsStandard>(thread);
  5.  
  6.         nIn.SwapC(0);
  7.         nIn.VLinkNN< &neuron::isActive, &neuron::activateNext>(nOut, thread);
  8.  
  9.         nOut.SwapC(0);
  10.         nOut.forallNS< &neuron::isActive, &SendSignalsStandard>(thread);
  11. }

Через объект «нейронный поток исполения» сейчас производится остановка исполнения ИНС для отладки в НЛ, а в будущем также будет происходить синхронизация различных потоков.

№77 NL UI: списки нейронов и связей

Воскресенье, Февраль 15th, 2009

В таблице, отображающей данные нейронов, для удобства полезно к каждому нейрону выводить иконку, цветами показывающую состояние активен/неактивен. Желательно, «двухэтажную» – с информацией за текущий и следующий циклы в верхней и нижней частях. Эта информация берется из чисто виртуальных функций, которые должны быть переопределены в любом классе нейрона, используемом в Нейролаборатории:

  1. virtual __forceinline signal_t curActivation()const=0;
  2. virtual __forceinline signal_t nextActivation()const=0;
  3. virtual __forceinline signal_t threshold()const=0;

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


Рис. 77.1 Таблица нейронов – иконки активации + подсказка

Для удобства работы с таблицей всех связей некоторого нейрона можно использовать такие ухищрения.
1) Применение «outer join»: после столбцов с данными связи, идут столбцы с данными нейрона. Если связь по отношению к нейрону, связи которого отображаются в таблице, исходящая, то показываются параметры нейрона назначения, иначе – связи нейрона отправки. Разделение столбцов, относящихся к связям, от столбцов, относящихся к нейронам, можно показывать той же иконкой активации, что и у отображаемого нейрона в таблице нейронов. Совмещение таблиц происходит с использованием ранее описанных таблиц метаданных.
2) Чтобы быстро определять, исходящая или входящая связь показана на данной строке, можно не выводить идентификатор нейрона, связи которого отображаются в данной таблице.
3) Двойной щелчок по ячейке с идентификатором нейрона (отправки или назначения связи) должен приводить к переключению таблицы на отображение связей этого нейрона – своеобразная «гиперссылка».
4) Часто встречается задача просмотреть связи нейрона с ненамного отличающимся идентификатором. Это может быть нейрон того же кластера, но с другими функциями, или нейрон другого кластера. В случае с нейроном другого кластера, удобно переходы делать равными количеству нейронов в кластере. Для этой цели на панели инструментов таблицы связей выводятся соответствующие кнопки
5) Отображение подсказок для уменьшения количества горизонтальных прокруток
6) Таблица связей должна уметь следить за нейронами, которые выбираются в других окнах, сразу отображать их связи. Редактирование отдельных полей можно запретить через таблицу метаданных, удаление связи (как и удаление нейрона) – запретить/разрешить через флаги типа нейрона/связи, либо, если нужна большая специализация – через переопределение виртуальных функций пользовательской ИНС


Рис. 77.2 Таблица связей

№76 Выделение совпадений в цепочках ИНС – 4. Прямое управление нейронами, изменение группировки нейронов

Воскресенье, Февраль 15th, 2009

Продолжим разработку первой стадии алгоритма выделения совпадений – поиск цепочек с общими элементами для передачи их второй стадии – создания новой нейронной цепочки. (далее…)

№74 Выделение совпадений в цепочках ИНС – 1

Среда, Февраль 11th, 2009

Предыдущие заметки на эту тему:
«№54 Автоматическое выделение закономерностей быстрой памятью» ( http://neurocod.net/blog/tag/2008/12/№54-автоматическое-выделение-закономе )
«№62 ИНС и ДНК» ( http://neurocod.net/blog/tag/2008/12/№62-инс-и-днк )

Начнем с упрощенной задачи.
(далее…)

№60 Использование поля типа нейрона

Пятница, Декабрь 19th, 2008

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