preview
Нейросети в трейдинге: От трансформеров к спайковым нейронам (Основные компоненты)

Нейросети в трейдинге: От трансформеров к спайковым нейронам (Основные компоненты)

MetaTrader 5Торговые системы |
112 0
Dmitriy Gizlyk
Dmitriy Gizlyk

Введение

Финансовые рынки напоминают бурное море, где капитан судна обязан принимать решения молниеносно, опираясь не только на карты и компасы, но и на интуицию, выработанную годами практики. В современном мире эту роль всё чаще берут на себя вычислительные модели, а задачей исследователя становится создание алгоритма, способного соперничать с человеческой гибкостью и дальновидностью. На фоне традиционных методов машинного обучения и уже хорошо освоенных архитектур нейросетей фреймворк SpikingBrainпоявился как свежий ветер, способный наполнить паруса исследователя и привести его к новым берегам анализа данных.

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

Не менее важно и то, что спайковые модели проявляют энергоэффективность. Для финансовых рынков, где работа алгоритмов часто должна быть непрерывной, возможность снижать нагрузку на оборудование без потери качества анализа становится весомым аргументом. В эпоху, когда вычислительные ресурсы распределяются между тысячами стратегий и десятками серверов, умение извлекать максимум пользы из минимума затраченной энергии приобретает не только техническую, но и стратегическую значимость. Можно сказать, что SpikingBrain открывает дорогу к умным вычислениям. Акцент делается не на грубой силе машин, а на изящной архитектуре и оптимизации процессов.

Особая сила фреймворка проявляется в его способности к эффективному переносу знаний и адаптации. В отличие от громоздких моделей, которые требуют гигантских выборок для стабильной работы, спайковая архитектура легче использует предварительно накопленный опыт и быстрее подстраивается под новые данные. Это позволяет применять уже обученные структуры к задачам финансового анализа, дообучая их даже на относительно ограниченных выборках. Данный подход значительно ускоряет внедрение модели в практику и делает её гибким инструментом, способным учитывать специфику конкретного рынка. Следовательно, SpikingBrain становится связующим звеном между универсальностью предварительно обученных решений и уникальными особенностями локальных данных.

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

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

Здесь стоит подробнее рассмотреть важный элемент архитектуры — механизм кодирования сигналов в спайки. Для финансовых временных рядов эта задача особенно нетривиальна: необходимо не просто зафиксировать значения цен или объёмов, но и преобразовать их в форму, где каждая импульсная вспышка отражает значимое изменение в данных. Авторы предлагают несколько стратегий кодирования. От простого порогового подхода, где спайк возникает при превышении критического значения, до более сложных схем, учитывающих скорость изменения и контекст предыдущих событий. Такое многообразие методов делает модель универсальной. Она может одинаково хорошо работать как с высокочастотными данными, где важна каждая миллисекунда, так и с более спокойными дневными графиками, где решающее значение имеет глобальная тенденция.

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

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

Важным элементом архитектуры являются модули, ответственные за нормализацию и устойчивость работы сети. В отличие от традиционных нейросетей, где баланс достигается через массивные процедуры регуляризации, SpikingBrain использует более тонкие механизмы, встроенные в саму природу спайковых сигналов. Благодаря этому сеть демонстрирует стабильность даже в условиях хаотичных данных, сохраняя способность к точному прогнозированию. Для финансового рынка это качество нельзя переоценить: ведь хаос — его постоянный спутник, и умение находить в нём скрытые закономерности определяет успех любой модели.

Здесь же стоит отметить и модульность предложенной архитектуры. Авторы заложили принципы, которые позволяют развивать модель вширь и вглубь, комбинировать спайковые элементы с традиционными блоками глубокого обучения и получать гибридные решения. Такой синтез даёт ещё больше возможностей для применения в финансах. Можно, например, строить модели, где спайковые механизмы отвечают за обработку событийных сигналов, а классические блоки — за долгосрочные прогнозы или анализ текстовой информации. Получается многогранный инструмент, где каждая часть системы выполняет свою функцию, а в совокупности они образуют целостный механизм для анализа сложной рыночной картины.

Авторская визуализация фреймворка SpikingBrain представлена ниже.

В практической части предыдущей статьи мы сосредоточились на подготовке фундаментальной базы, необходимой для переноса идей SpikingBrain в среду MQL5. Было важно показать, как теоретические принципы могут обрести форму в конкретных алгоритмах, готовых к работе с реальными торговыми данными. Мы начали с реализации базового компонента, позволяющего преобразовывать непрерывный сигнал в дискретный спайковый импульс. Тем самым был проложен мост от абстрактной идеи к инструменту, который способен работать в рамках популярной платформы для трейдинга. Эта работа стала первым шагом в построении полноценной системы, где инновации авторов фреймворка получают практическое воплощение в условиях живого рынка.

Мы задали направление и подготовили почву, а теперь переходим к более глубокому анализу архитектуры и принципов работы модели.



Обсуждение реализации

Прежде чем переходить к непосредственной реализации предложенных подходов, стоит обозначить ключевые принципы нашей работы. Авторы фреймворка используют предварительно обученные модели на основе классических Transformer, и это важная деталь. Такой подход позволяет не тратить ресурсы на обучение с нуля, а сразу опираться на накопленный опыт архитектур, доказавших свою эффективность. Следовательно, и в нашей реализации мы можем задействовать уже готовые алгоритмы и модули, что делает процесс более надёжным и гибким.

Особый интерес вызывает идея гибридных модулей внимания. Авторы предлагают сочетать разные архитектурные решения в рамках единой системы — например, параллельно использовать линейное внимание, оконное или же полное. Отчасти это напоминает принципы, реализованные во фреймворке Extralonger, где глобально-локальное внимание стало основой для более глубокого анализа временных и пространственных связей.

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

Поэтому при разработке моделей для финансовых рынков предпочтительнее использовать более адаптивные механизмы внимания. Их задача — уметь отсеивать лишнее и выхватывать редкие, но по-настоящему ценные сигналы. Именно такие сигналы часто становятся определяющими для смены рыночных трендов и позволяют модели формировать прогнозы, обладающие практической значимостью.

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

Более того, использование графонов органично сочетается с идеей авторов фреймворка о внедрении алгоритмов типа Mixture of Experts (MoE). Разреженная структура внимания и модульная архитектура MoE усиливают друг друга. Графоны задают маршруты взаимодействия, а MoE позволяет избирательно активировать наиболее подходящие экспертные блоки. В результате формируется система, которая потенциально лучше справляется с шумными финансовыми рядами и гибко подстраивается под характер текущего рынка.

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

Кроме того, особый интерес вызывает предложенная авторами интерпретация модуля линейного внимания. В одной из наших предыдущих работ мы уже реализовывали объект линейного внимания и хорошо знакомы с его возможностями. Однако авторы фреймворка предложили более гибкий вариант. Линейное внимание реализуется как рекуррентный блок с добавлением гейтов, что позволяет значительно расширить область внимания без существенного увеличения вычислительных затрат.

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

где St — матрица накопленного состояния, gt — вектор гейтов, kt и vt — ключи и значения на текущем шаге, а qt — запрос. Такая структура позволяет сохранять информацию о дальних зависимостях и одновременно контролировать её актуальность через гейты.

С точки зрения финансового анализа это решение особенно ценно. Оно даёт возможность учитывать события, распределённые во времени, не перегружая модель обработкой лишних сигналов и шума. В сочетании с разреженным вниманием на основе графонов и архитектурой MoE рекуррентное линейное внимание становится мощным инструментом для построения адаптивных прогнозов, способных выделять ключевые тенденции и реагировать на быстро меняющиеся рыночные условия.

Авторы фреймворка SpikingBrain предлагают два основных подхода к использованию гибридного внимания: последовательный и параллельный. В рамках последовательного варианта предполагается использование стека слоёв внимания с различной архитектурой, между которыми внедряются блоки типа MoE, выполняющие роль модулей FeedForward. Такой подход позволяет модели поочерёдно обрабатывать сигналы разной природы, сохраняя при этом структурную гибкость и возможность избирательно активировать экспертов.

Параллельное смешивание, напротив, предполагает одновременное использование различных блоков внимания в пределах одного слоя. Их объединённый результат затем передаётся на обработку единым блоком MoE, что обеспечивает интеграцию информации с разных перспектив. Более того, даже в параллельной схеме допускается комбинирование разных модулей внимания между слоями модели. Модель получает максимальную гибкость, позволяя адаптировать структуру внимания к конкретным особенностям данных.

С точки зрения финансовых рынков такой подход выглядит особенно привлекательным. Разные источники информации, временные горизонты и типы сигналов могут обрабатываться одновременно, а система при этом остаётся управляемой и экономной. В сочетании с разреженным вниманием на основе графонов и рекуррентными блоками линейного внимания, гибридные режимы дают возможность выстраивать сложные модели, которые способны улавливать как локальные шумные колебания, так и глобальные тенденции рынка.


Модуль линейного внимания с гейтами

Свою практическую работу сегодня мы начнём с реализации рекуррентного блока линейного внимания с гейтами, который воплотим в виде нового объекта CNeuronGateLineAttention. Этот объект создаётся как специализированный модуль внутри архитектуры SpikingBrain и наследует базовый функционал от CNeuronSpikeConv. Такое наследование позволяет легко интегрировать его в существующую инфраструктуру спайковых нейронных объектов, использовать преимущества импульсной динамики и рекуррентного накопления информации, а также задействовать параллельные вычисления через OpenCL для ускорения обработки данных.

Решение позволяет объединить лучшее из двух миров. Внутри объекта применяются привычные непрерывные значения многоголового линейного внимания, обеспечивая точное выделение ключевых сигналов и дальних зависимостей. В то же время алгоритмы родительского класса снижают размерность многоголового внимания до исходной размерности данных и преобразуют полученные значения в дискретные спайковые импульсы. Таким образом, модель сохраняет точность непрерывного анализа и одновременно получает способность работать в рамках событийной импульсной динамики, что особенно важно для обработки шумных и разреженных финансовых временных рядов.

Структура нового объекта представлена ниже.

class CNeuronGateLineAttention  :  public CNeuronSpikeConv
  {
protected:
   uint              iDimensionK;
   uint              iVariables;
   uint              iHeads;
   //---
   CNeuronConvOCL    cQKV;
   CNeuronBaseOCL    cQ;
   CNeuronBaseOCL    cK;
   CNeuronBaseOCL    cV;
   CNeuronBaseOCL    cKV;
   CNeuronConvOCL    cGate;
   CNeuronBaseOCL    cState;
   CNeuronBaseOCL    cMHAttention;
   //---
   virtual bool      feedForward(CNeuronBaseOCL *NeuronOCL) override;
   virtual bool      updateInputWeights(CNeuronBaseOCL *NeuronOCL) override;
   virtual bool      calcInputGradients(CNeuronBaseOCL *NeuronOCL) override;

public:
                     CNeuronGateLineAttention(void) {};
                    ~CNeuronGateLineAttention(void) {};
   //---
   virtual bool      Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                          uint variables, uint dimension, uint dimension_k, uint heads,
                          ENUM_OPTIMIZATION optimization_type, uint batch);
   //---
   virtual int       Type(void) override const  {  return defNeuroneGateLineAttention;   }
   //--- methods for working with files
   virtual bool      Save(int const file_handle) override;
   virtual bool      Load(int const file_handle) override;
   virtual void      SetOpenCL(COpenCLMy *obj)   override;
   virtual bool      Clear(void) override;
   virtual void      SetActivationFunction(ENUM_ACTIVATION value) override { };
   //---
   virtual bool      WeightsUpdate(CNeuronBaseOCL *source, float tau) override;
   virtual uint      GetVariables(void) const { return iVariables; }
  };

Внутри объекта выделены переменные для сохранения ключевых параметров архитектуры объекта:

  • iDimensionK задаёт размерность ключей, что определяет объём информации, аккумулируемой в каждой голове внимания;
  • iVariables хранит число анализируемых переменных для обработки сигналов;
  • iHeads задаёт количество параллельных голов внимания, что обеспечивает многоканальный анализ временного ряда.

Обработка запросов, ключей и значений реализована через комбинацию объектов CNeuronBaseOCL и CNeuronConvOCL. Особое место здесь занимает объект cQKV, который одновременно генерирует все сущности многоголового внимания. После этого единый результат делится на три тензора (q, k и v) для выполнения математических операций внимания. Такой подход позволяет одновременно формировать все необходимые компоненты, ускоряет вычисления на GPU и снижает нагрузку на центральный процессор, сохраняя при этом точность многоголового анализа.

Все внутренние компоненты нашего объекта CNeuronGateLineAttention объявлены статично, поэтому конструктор и деструктор класса остаются пустыми. Полная инициализация блока выполняется в методе Init, который задаёт параметры работы объекта, подключает вычислительное ядро OpenCL и настраивает внутренние компоненты.

bool CNeuronGateLineAttention::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                                    uint variables, uint dimension, uint dimension_k, uint heads,
                                    ENUM_OPTIMIZATION optimization_type, uint batch)
  {
   if(!CNeuronSpikeConv::Init(numOutputs, myIndex, open_cl, heads * dimension_k, heads * dimension_k,
                                                  dimension, 1, variables, optimization_type, batch))
      return false;

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

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

После успешного завершения родительской инициализации сохраняем специфические параметры объекта: размерность ключей iDimensionK, количество голов внимания iHeads и число анализируемых переменных iVariables.

   iDimensionK = dimension_k;
   iHeads = heads;
   iVariables = variables;

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

Далее переходим к инициализации внутренних компонентов. Первым здесь инициализируем объект cQKV. Он одновременно генерирует все три сущности многоголового внимания — запросы q, ключи k и значения v.

   int index = 0;
   if(!cQKV.Init(0, index, OpenCL, dimension, dimension, 3*iHeads*iDimensionK, 1, iVariables, optimization, iBatch))
      return false;
   cQKV.SetActivationFunction(SIGMOID);

Такой подход ускоряет вычисления, рационально распределяет ресурсы GPU и обеспечивает точное формирование всех компонентов многоголового внимания. Для cQKV задаётся сигмоидальная функция активации, которая плавно регулирует входной сигнал и подготавливает его к рекуррентной обработке.

Далее инициализируются объекты cQ, cK и cV.

   index++;
   if(!cQ.Init(0, index, OpenCL, iHeads * iDimensionK * iVariables, optimization, iBatch))
      return false;
   cQ.SetActivationFunction(None);
   index++;
   if(!cK.Init(0, index, OpenCL, cQ.Neurons(), optimization, iBatch))
      return false;
   cK.SetActivationFunction(None);
   index++;
   if(!cV.Init(0, index, OpenCL, cQ.Neurons(), optimization, iBatch))
      return false;
   cV.SetActivationFunction(None);

Они предназначены для хранения соответствующих тензоров и участвуют в операциях матричного умножения. Функции активации здесь не применяются.

Следующий ключевой компонент — cKV. Он предназначен для хранения результатов матричного умножения тензоров ключей и значений.

   index++;
   if(!cKV.Init(0, index, OpenCL, cQ.Neurons()*iDimensionK, optimization, iBatch))
      return false;
   cKV.SetActivationFunction(None);

Благодаря этому объект аккумулирует информацию, необходимую для вычисления внимания, и передаёт её в последующие этапы обработки.

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

   index++;
   if(!cGate.Init(0, index, OpenCL, dimension, dimension, iDimensionK * iHeads, 1, iVariables, optimization, iBatch))
      return false;
   cGate.SetActivationFunction(SIGMOID);

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

Объект cState аккумулирует предыдущее состояние внимания, обеспечивая рекуррентную обработку. Он хранит накопленные данные о ключевых зависимостях во времени, которые затем участвуют в формировании итогового выхода блока.

   index++;
   if(!cState.Init(0, index, OpenCL, cKV.Neurons(), optimization, iBatch))
      return false;
   cState.SetActivationFunction(None);

В комбинации с cKV и cGate это позволяет реализовать рекуррентное линейное внимание с гейтами, которое способно учитывать как локальные краткосрочные колебания рынка, так и глобальные тенденции, обеспечивая точное выделение значимых сигналов.

Завершает внутреннюю конфигурацию cMHAttention. Он объединяя различные каналы внимания и формирует итоговый сигнал для последующих вычислений.

   index++;
   if(!cMHAttention.Init(0, index, OpenCL, cQ.Neurons(), optimization, iBatch))
      return false;
   cMHAttention.SetActivationFunction(None);
//---
   return true;
  }

Метод Init тщательно проверяет успешность инициализации каждого компонента и возвращает false, если какой-либо шаг завершился неудачей. Таким образом, создаётся полностью готовый к работе объект, способный эффективно обрабатывать финансовые временные ряды, объединяя точность непрерывного многоголового внимания с преимуществами дискретной спайковой динамики и рекуррентного накопления информации.

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

bool CNeuronGateLineAttention::feedForward(CNeuronBaseOCL *NeuronOCL)
  {
   if(!cQKV.FeedForward(NeuronOCL))
      return false;

На первом шаге вызывается одноименный метод объекта cQKV. Здесь создаются объединённые тензоры запросов q, ключей k и значений v для многоголового внимания. Такой подход ускоряет вычисления, поскольку генерация всех трёх сущностей происходит одновременно, а последующее разделение на отдельные тензоры позволяет выполнить стандартные операции внимания.

Далее вызывается FeedForward объекта cGate, который формирует сигналы гейтов.

   if(!cGate.FeedForward(NeuronOCL))
      return false;

Гейтовый механизм регулирует, какая часть предыдущего состояния сохраняется, а какая — обновляется текущими исходными данными. Это особенно важно для финансовых временных рядов, где сигналы разрежены и подвержены шуму: гейты помогают фильтровать шумные колебания и удерживать значимые паттерны.

Следующий шаг — разбиение объединённого выхода cQKV на три отдельных тензора с помощью функции DeConcat.

   if(!DeConcat(cQ.getOutput(), cK.getOutput(), cV.getOutput(), cQKV.getOutput(),
                     iDimensionK, iDimensionK, iDimensionK, iHeads * iVariables))
      return false;

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

   if(!MatMul(cK.getOutput(), cV.getOutput(), cKV.getOutput(), iDimensionK, 1,
                                      iDimensionK, iHeads * iVariables, true))
      return false;

Рекуррентное обновление состояния выполняется в объекте cState. Сначала вызывается SwapOutputs, чтобы сохранить значения предыдущего прямого прохода.

   if(!cState.SwapOutputs())
      return false;
   if(!DiagMatMul(cGate.getOutput(), cState.getPrevOutput(), cState.getOutput(),
              iDimensionK, iDimensionK, iHeads * iVariables, cState.Activation()))
      return false;
   if(!SumAndNormilize(cState.getOutput(), cKV.getOutput(), cState.getOutput(),
                                                  iDimensionK, false, 0, 0, 0, 1))
      return false;

Затем применяется DiagMatMul с выходом гейтов и предыдущим состоянием. На этом шаге формируется новое текущее состояние блока. После этого выполняется суммирование с результатами cKV. Эти операции выделяют значимые сигналы и подавляют шум, обеспечивая точное представление информации для следующего шага.

Завершающий этап — матричное умножение запроса cQ на обновлённое состояние cState, что формирует окончательный выход многоголового внимания в объекте cMHAttention.

   if(!MatMul(cQ.getOutput(), cState.getOutput(), cMHAttention.getOutput(), 1,
                          iDimensionK, iDimensionK, iVariables * iHeads, true))
      return false;

Этот результат передаётся в родительский класс CNeuronSpikeConv для генерации дискретных спайковых импульсов.

   if(!CNeuronSpikeConv::FeedForward(cMHAttention.AsObject()))
      return false;
//---
   return true;
  }

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

В совокупности метод feedForward создаёт связанный поток данных: генерация тензоров, гейтовая регуляция, рекуррентное накопление состояния и объединение многоголового внимания. Такой подход обеспечивает модели способность эффективно работать с финансовыми временными рядами, учитывая краткосрочные колебания и дальние зависимости, и формировать точные сигналы для прогнозирования тенденций рынка.

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

Однако прямой проход — это лишь половина дела. Для обучения модели необходимо правильно распределить ошибку прогнозирования между всеми участниками процесса в соответствии с их влиянием на итоговый результат. В объекте CNeuronGateLineAttention этот механизм реализован в методе calcInputGradients, который выполняет обратное распространение ошибки и формирует градиенты для всех внутренних компонентов.

bool CNeuronGateLineAttention::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
  {
   if(!NeuronOCL)
      return false;
//---
   if(!CNeuronSpikeConv::calcInputGradients(cMHAttention.AsObject()))
      return false;

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

Следующий шаг — вычисление градиентов для запроса cQ и накопленного состояния cState. Метод MatMulGrad распределяет ошибку пропорционально влиянию каждого входного сигнала на итоговый результат многоголового внимания.

   if(!MatMulGrad(cQ.getOutput(), cQ.getGradient(),
                  cState.getOutput(), cState.getGradient(),
                  cMHAttention.getGradient(), 1, iDimensionK,
                  iDimensionK, iVariables * iHeads, true))
      return false;

Далее выполняется передача градиентов на объект cKV, корректируя значения с учётом функции активации.

   if(!DeActivation(cKV.getOutput(), cKV.getGradient(), cState.getGradient(), cKV.Activation()))
      return false;

Особое внимание уделяется гейтовой части. Метод DiagMatMulGrad распределяет ошибку между выходом гейтов cGate и предыдущим состоянием cState.

   if(!DiagMatMulGrad(cGate.getOutput(), cGate.getGradient(),
                      cState.getPrevOutput(), cKV.getPrevOutput(),
                      cState.getGradient(), iDimensionK, iDimensionK,
                      iHeads * iVariables))
      return false;
   Deactivation(cGate)

После этого вызывается деактивация гейтового блока, чтобы учесть сигналы функции активации и корректно скорректировать градиенты.

Градиенты для ключей cK и значений cV вычисляются через MatMulGrad.

   if(!MatMulGrad(cK.getOutput(), cK.getGradient(),
                  cV.getOutput(), cV.getGradient(),
                  cKV.getGradient(), iDimensionK, 1,
                  iDimensionK, iHeads * iVariables, true))
      return false;

А затем все градиенты (cQ, cK, cV) объединяются обратно в единый тензор cQKV с помощью функции Concat.

   if(!Concat(cQ.getGradient(), cK.getGradient(), cV.getGradient(), cQKV.getGradient(),
              iDimensionK, iDimensionK, iDimensionK, iHeads * iVariables))
      return false;
   Deactivation(cQKV)

Это позволяет сохранить согласованность градиентов и корректно распределить ошибку между компонентами многоголового внимания.

Далее нам предстоит передать градиенты ошибки на уровень исходных данных. Здесь мы передаем значения по двум информационным потокам. Сначала передаем значения от объекта cQKV.

   if(!NeuronOCL.CalcHiddenGradients(cQKV.AsObject()))
      return false;

После чего временно подменяется указатель на буфер градиентов, чтобы сохранить ранее полученные значения.

   CBufferFloat* temp = NeuronOCL.getGradient();
   if(!NeuronOCL.SetGradient(PrevOutput, false))
      return false;

И выполняется передача данных от гейтового объекта cGate с последующим суммированием значений от двух информационных потоков.

   if(!NeuronOCL.CalcHiddenGradients(cGate.AsObject()))
      return false;
   if(!SumAndNormilize(PrevOutput, temp, temp, GetFilters(), false, 0, 0, 0, 1))
      return false;
   if(!NeuronOCL.SetGradient(temp, false))
      return false;
//---
   return true;
  }

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

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

Последний этап работы с объектом CNeuronGateLineAttention — оптимизация параметров модели, которая реализована в методе updateInputWeights. Здесь происходит обновление весов всех внутренних компонентов, содержащих обучаемые параметры.

bool CNeuronGateLineAttention::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
  {
   if(!cQKV.UpdateInputWeights(NeuronOCL))
      return false;
   if(!cGate.UpdateInputWeights(NeuronOCL))
      return false;
   if(!CNeuronSpikeConv::updateInputWeights(cMHAttention.AsObject()))
      return false;
//---
   return true;
  }

Метод последовательно передаёт управление объектам cQKV и cGate, обновляя их веса на основе накопленных градиентов. Затем управление передаётся родительскому классу для обновления параметров блока объединения результатов многоголового внимания.

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

На этом мы завершаем работу с классом CNeuronGateLineAttention. Его полный код вместе со всеми методами представлен во вложении к статье.

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


Заключение

В этой статье мы подробно разобрали и реализовали рекуррентный блок линейного внимания с гейтами в рамках объекта CNeuronGateLineAttention. Шаг за шагом мы прошли от инициализации и генерации тензоров до прямого прохода, обратного распространения ошибки и оптимизации весов, показав, как каждый компонент влияет на обработку финансовых временных рядов.

Особое внимание было уделено архитектурным решениям: гейтовая регуляция, рекуррентное накопление состояния, комбинирование многоголового внимания и единый маршрут остаточных связей для всех модулей внутри слоя. Всё это создаёт механизм, способный выделять значимые сигналы, фильтровать шум и учитывать как краткосрочные колебания рынка, так и долгосрочные тенденции.

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


Ссылки


Программы, используемые в статье

# Имя Тип Описание
1 Study.mq5 Советник Советник офлайн обучения моделей
2 StudyOnline.mq5 Советник Советник онлайн обучения моделей
3 Test.mq5 Советник Советник для тестирования модели
4 Trajectory.mqh Библиотека класса Структура описания состояния системы и архитектуры моделей
5 NeuroNet.mqh Библиотека класса Библиотека классов для создания нейронной сети
6 NeuroNet.cl Библиотека Библиотека кода OpenCL-программы
Прикрепленные файлы |
MQL5.zip (3135.77 KB)
Особенности написания Пользовательских Индикаторов Особенности написания Пользовательских Индикаторов
Написание пользовательских индикаторов в торговой системе MetaTrader 4
Разработка продвинутых торговых систем ICT: Реализация сигналов в индикаторе Order Blocks Разработка продвинутых торговых систем ICT: Реализация сигналов в индикаторе Order Blocks
В этой статье вы узнаете, как разработать индикатор Order Blocks, основанный на объеме стакана (глубине рынка) и оптимизировать его с помощью буферов для повышения точности. Этим мы завершаем текущий этап проекта и готовимся к следующим, в рамках которых будет реализован класс управления рисками и торговый бот, использующий сигналы, генерируемые индикатором.
Особенности написания экспертов Особенности написания экспертов
Написание и тестирование экспертов в торговой системе MetaTrader 4.
Создание пользовательской системы определения рыночного режима на языке MQL5 (Часть 2): Советник Создание пользовательской системы определения рыночного режима на языке MQL5 (Часть 2): Советник
В этой статье подробно описано создание адаптивного экспертного советника (MarketRegimeEA) с помощью детектора режимов из Части 1. Он автоматически переключает торговые стратегии и параметры рисков для трендового, флэтового или волатильного рынков. Сюда включены практическая оптимизация, обработка переходов и индикатор для нескольких таймфреймов.