В алгоритмах выделения обобщений, рассмотренных ранее, механизм выделения признаков, которые входят в обе цепочки памяти, работал следующим образом. С каждой из двух цепочек памяти на свои признаки слался сигнал обычной силы, и те признаки, которые получили двойную порцию, считались входящими в обе цепочки.
Проверка в коде была вида activation>=2*threshold
Но чтобы писать код с использованием объектов «нейронный контур», нужно было ввести отдельную функцию для такой проверки. В дополнение к функции neuron::isActive, с именем типа isActivatedDoubly. Более красивое решение – использовать шаблонную функцию с параметром «кратность активации». Но так как С++ не поддерживает шаблонные параметры из нецелых чисел, то пришлось коэффициент кратности делать целым. И тогда в функцию обработки нейроконтура можно было передать neuron::isActive<2>, надеясь, что компилятор вместо преобразования типов данных догадается подставить только инкремент степенной части числа с плавающей запятой.
Но у этого подхода есть концептуальные недостатки. Как известно, потенциал действия биологических нейронов при разрядке всегда один и тот же. Накопление на мембране «двойного заряда» не подходит. Повышение порога гуморальными механизмами – слишком медленно (а люди просыпаются достаточно быстро). Можно рассмотреть изменение потенциала на мембранах вспомогательной нейросетью. Можно в режиме выделения тормозить ею нейроны, так что активироваться смогут только нейроны с двойной порцией активации. Или можно во время обычной работы дополнительно активировать нейроны, а в режиме выделения – прекращать поставлять помощь. Можно комбинировать активацию и торможение. Но мне более вероятным кажется использование времени активации в качестве варьируемого параметра. Так как посылка активации в природных нейросетях в режиме высокочастотного возбуждения происходит не единовременно, а множеством спайков, то нейрон, получающий двойную порцию активации (от двух цепочек), будет активирован примерно вдвое быстрее, чем в нормальных условиях. Вариантов реализации механизма выделения нейронов с двойной активацией тогда остается два. В одном варианте, нейроны цепочек шлют вдвое меньше спайков, чем обычно, и активируются только нейроны, входящие в обе цепочки. Мне более вероятным представляется случай, при котором отдельная нейросеть детектирует нейроны, активировавшиеся вдвое быстрее, чем обычно. Вдвое быстрее, конечно, после предыдущего такта нейросети «посылка к признакам». Тот же Бужаки говорил, что есть нейроны, очень точно реагирующие на время активации.
После того, как концептуальные вопросы решены, можно было оставить код, как есть, лишь помня о несколько другом смысле «двойной активации». Понятие двойной активации возникает, так как спайки в моих нейросетях моделируются одним целым, и нет возможности обнаружить изменение времени активации. Можно было бы разделить спайки на два – и вместо одного квазиспайка, всегда слать два квазиспайка. В результате, схема обнаружения общих признаков работала бы так, как и гипотетический природный аналог. Но есть более эффективный подход – слать половинную активацию. Вместо умножения порога или деления активации каждого нейрона при сравнении, лучше послать половинную активацию лишь у тех, кто активирован (с нейронов nDn->* ). Этого можно всего добиться, если понизить порог нейронов контура nDn вдвое, и в зависимости от режима вместо VA(nX, nDn) писать что-то типа VA(nX, nDn, 0.5f), или VA(nX, nDn, 1.f)