Нейросети в трейдинге: Оптимизация Cross-Attention для анализа длинных последовательностей рынка (STCA)
Введение
Финансовые рынки напоминают огромный живой организм. Каждое движение цены, каждый всплеск объёма и каждая пауза в торговле — это своего рода сигнал, который трейдеру нужно вовремя распознать. Для того чтобы принимать решения, важно видеть не просто последовательность цифр на графике, а закономерности, скрытые за ними. Каждый день рынок генерирует тысячи сигналов, и ключ к успешной торговле — определить, какие из них действительно значимы в данный момент. Традиционные подходы, основанные на простых индикаторах или коротких паттернах, часто упускают из виду глубокую структуру событий. Именно здесь на помощь приходят современные нейросетевые модели, способные работать с длинными последовательностями и выявлять закономерности, которые человеческий глаз не всегда способен заметить.
Современные трансформеры, изначально разработанные для обработки текстов, прекрасно справляются с длинными последовательностями и сложными зависимостями. Однако на рынке возникают специфические трудности. В языке важен порядок слов, а на рынке значение события не всегда определяется только его позицией во времени. Пробитие уровня утром может иметь одно значение, а аналогичное событие через несколько часов — совершенно другое. Self-Attention по всей истории становится вычислительно слишком тяжёлым и редко оправданным, если последовательность насчитывает тысячи баров. Для трейдера это значит выбор между потерей важной информации и снижением скорости анализа ради полноты картины.
В этом проекте мы опираемся на архитектурные идеи, предложенные авторами работы "Make It Long, Keep It Fast: End-to-End 10k-Sequence Modeling at Billion Scale on Douyin". Их модель способна эффективно обрабатывать историю длиной до 10 000 событий. В оригинальной работе механизм был разработан для анализа длинных последовательностей взаимодействий пользователей с контентом, позволяя кодировать всю историю один раз и быстро сопоставлять её с целевым объектом. Мы переносим эту идею на финансовые рынки, рассматривая сценарий или торговую гипотезу как цель, а историю — как последовательность рыночных событий. Так, внимание модели направляется от выбранного сценария к ключевым событиям рыночной истории, помогая выявлять сигналы, которые имеют реальную ценность для принятия торговых решений. Модель ищет закономерности, соотнося их с конкретной торговой идеей, словно опытный трейдер просматривает дневники прошлых движений рынка, отбирая самые значимые эпизоды.
Ключевым преимуществом такой архитектуры является способность эффективно работать с очень длинными последовательностями. История кодируется один раз, а сценарии обращаются к уже сформированному представлению. Это позволяет анализировать тысячи и десятки тысяч баров без потери скорости или точности. Более того, механизм Cross-Attention способен различать события, которые внешне похожи, но имеют разный смысл. Пробитие уровня в начале тренда и аналогичное пробитие в конце импульса — это разные сигналы, и модель улавливает их отличие благодаря структурированному представлению истории.
Для практического трейдера такая модель становится инструментом, близким к человеческому мышлению. Сначала формулируется гипотеза. Затем модель просматривает историю рынка, выявляя состояния, которые соответствуют этой гипотезе. Каждое событие анализируется с точки зрения его влияния на текущую ситуацию, и в результате формируется целостное представление, объединяющее прошлое и текущий сценарий. Это позволяет сочетать долговременную память рынка с контекстной чувствительностью, чего трудно достичь традиционными индикаторами или скользящими средними.
Важно подчеркнуть практическую ценность такого подхода. Возможность анализировать длинную историю через призму сценариев позволяет строить стратегии, устойчивые к повторяющимся рыночным режимам. Флэтовые периоды, импульсные скачки и развороты становятся структурированными событиями, на которые можно опираться при прогнозе будущих движений.
Алгоритм STCA
При построении архитектуры авторы работы "Make It Long, Keep It Fast: End-to-End 10k-Sequence Modeling at Billion Scale on Douyin" исходят из довольно простого, но важного наблюдения. В задачах ранжирования основной сигнал для прогнозирования реакции пользователя на некоторый объект возникает прежде всего из прямого сопоставления этого объекта с историей взаимодействий пользователя. Связи же между самими элементами истории, хотя и могут содержать дополнительную информацию, в большинстве случаев играют второстепенную роль. Иными словами, чтобы понять, заинтересует ли пользователя новый элемент, гораздо важнее сопоставить его с предыдущим опытом пользователя, чем анализировать все возможные отношения между событиями его истории.
Классическая архитектура трансформеров подходит к этой задаче иначе. Если объединить целевой объект и историю пользователя в одну последовательность [t; H], механизм Self-Attention начинает строить связи между каждой парой элементов. Такой подход универсален, но крайне затратен. Вычислительная сложность растёт квадратично по длине последовательности O(L²). В результате длина истории неизбежно ограничивается. Либо модель работает быстро, но видит лишь короткий фрагмент прошлого. Либо пытается учитывать длинную историю ценой резкого роста вычислительных затрат.
Авторы фреймворка предлагают более прагматичный компромисс между выразительной способностью модели и стоимостью вычислений. Они сознательно уменьшают внимание к взаимодействиям между элементами самой истории и сосредотачивают вычисления на действительно важном для задачи — на взаимодействии цели с историей. Для этого используется механизм Single-query Target-to-history Cross-Attention (STCA).
Ключевая идея проста: целевой объект выступает единственным запросом (Query) внимания, тогда как элементы истории играют роль ключей (Key) и значений (Value). Фактически модель задаёт истории один прямой вопрос: какие события прошлого наиболее релевантны для данного объекта? Благодаря тому, что запрос только один, вычислительная сложность слоя становится линейной по длине истории O(Ldh). При этом исчезает необходимость формировать промежуточные структуры Score размера L×L, характерные для Self-Attention. В результате резко снижается число операций и объём используемой памяти.
Эта архитектурная особенность оказывается критически важной на практике. Освободив вычислительный бюджет от дорогостоящего анализа связей внутри самой истории, модель получает возможность работать с гораздо более длинными последовательностями. В оригинальной работе авторы демонстрируют обработку историй порядка десяти тысяч событий, сохраняя тот же вычислительный бюджет, который классические трансформеры тратят на значительно более короткие последовательности. Таким образом, STCA позволяет масштабировать длину контекста без экспоненциального роста вычислительной нагрузки.
Обработка начинается с кодирования исходных данных. Каждый элемент истории (vj, aj), где vj обозначает объект взаимодействия и aj — тип действия пользователя, преобразуется в вектор признаков xj ∈ Rd. В этом векторе объединяются несколько компонентов: эмбеддинг объекта, тип действия и позиционная информация. Последовательность всех элементов формирует матрицу истории.
X = [x1, x2, …, xL] ∈ RL×d.
Целевой объект кодируется аналогичным образом в отдельный вектором xt ∈ Rd.
Перед использованием в механизме внимания полученные представления проходят через блок SwiGLUFFN, сочетающий нелинейность SwiGLU с линейной проекцией, сохраняющей размерность признаков. После этого применяется нормализация слоя (LayerNorm), что стабилизирует распределение активаций и облегчает обучение модели.
На каждом слое Attentionвектор цели проецируется в пространство запросов, а элементы истории — в пространства ключей и значений. Затем вычисляется распределение внимания. Оно показывает, какие элементы истории оказываются наиболее значимыми для текущего объекта. Чем сильнее сходство между целью и некоторым эпизодом истории, тем больший вес получает соответствующий элемент. Итоговое представление формируется как взвешенная комбинация этих элементов.
Таким образом модель фактически просматривает длинную историю взаимодействий и выделяет в ней те эпизоды, которые наиболее релевантны для текущей цели. Одни события оказываются практически незаметными, другие, напротив, получают высокий вес и оказывают решающее влияние на итоговое представление.
После того как первый слой Cross-Attention сопоставляет целевой объект с историей, модель получает первое агрегированное представление истории относительно цели. Однако на этом анализ не заканчивается. Архитектура STCA строится как стек из нескольких слоёв Attention, где каждый следующий слой уточняет понимание истории, опираясь на результаты предыдущих шагов.
Ключевая особенность заключается в том, что запрос внимания не остаётся фиксированным. После каждого слоя он обновляется через механизм Target-Conditioned Fusion. Интуитивно это похоже на последовательное уточнение гипотезы: сначала модель делает грубое сопоставление цели с историей, затем пересматривает результаты, добавляя новые детали.
На i-м слое Attention формируется вектор результатов oi, представляющий агрегированную информацию из истории. Вместо того чтобы просто передать его дальше, модель объединяет все полученные к этому моменту представления в [o1 | … | oi | xt], где xt — исходный вектор цели. Таким образом в новом запросе одновременно присутствуют:
- исходная информация о цели,
- результаты анализа истории на предыдущих уровнях,
- постепенно накапливаемый контекст.
Поскольку размер этой конкатенации растёт с каждым слоем, используется обучаемая линейная проекция WCi+1, которая сжимает объединённый вектор обратно до размерности d. После этого применяется нелинейный блок SwiGLUFFN, формируя обновлённый запрос.
q(i+1) =SwiGLUFFN(i+1)([o1 | … | oi | xt] WC(i+1))
За этой формулой скрывается довольно интуитивный процесс. Модель постепенно собирает из истории контекст сценария, а затем использует этот контекст, чтобы снова обратиться к той же истории. Это похоже на работу аналитика: сначала он замечает очевидные сигналы, затем начинает искать подтверждения или уточнения, возвращаясь к тем же данным, но уже с новым пониманием ситуации.
После прохождения всех 𝑀 слоёв, модель получает набор промежуточных представлений o1, …, oM. Каждый из них отражает историю под немного разным углом. Один слой может концентрироваться на последних событиях, другой — на более редких, но характерных паттернах, третий — на долгосрочных зависимостях. В совокупности они образуют своего рода многоуровневое описание истории.
Именно поэтому на финальном этапе все эти представления снова объединяются вместе с исходным вектором цели. Полученная конкатенация проходит через блок SwiGLUFFN, формируя итоговый вектор 𝑧. В этом векторе уже нет разделения на цель и историю. Это единое представление, в котором информация о целевом объекте переплетена с наиболее релевантными эпизодами прошлого.
Далее архитектура дополняет этот вектор другими источниками информации. В рекомендательных системах это могут быть дополнительные пользовательские признаки или характеристики кандидатов. Все эти токены объединяются в общий набор 𝑋mix, который подаётся в блок финального взаимодействия между всеми источниками информации. Здесь формируется скрытое представление ℎ, на основе которого вычисляется итоговая оценка.
Если посмотреть на эту схему через призму финансовых рынков, возникает любопытная интерпретация. Роль цели может играть конкретный торговый сценарий, например, возможное продолжение тренда, импульсное движение или выход из консолидации. История рынка становится последовательностью наблюдаемых состояний. На первом уровне модель ищет грубые совпадения между сценарием и историей. На следующих уровнях она начинает уточнять контекст, постепенно выделяя именно те эпизоды прошлого, которые действительно похожи на текущую ситуацию.
В результате формируется представление, которое можно интерпретировать как агрегированную модель сценария, построенную на основе всей доступной истории. И именно эта особенность делает STCA особенно интересной архитектурой для задач, где важен анализ длинных последовательностей и поиск редких, но значимых паттернов — таких, как поведение финансовых рынков.

Ещё одна важная деталь архитектуры STCA связана с вычислительной оптимизацией механизма внимания. Она становится возможной благодаря тому, что на каждом слое используется ровно один запрос. Это обстоятельство радикально меняет структуру вычислений по сравнению с классическим Attention.
Рассмотрим стандартную форму вычисления Cross-Attention на примере матрицы истории X ∈ RL×d и запроса цели, представленного вектором q ∈ Rd. Размерность одной головы внимания равна dh = d/h. Тогда механизм внимания записывается в привычной форме.
Attn(q, X) = SoftMax((qWQ)(XWK)T/√dh)•(XWV)
Здесь используются три проекции: WQ, WK, WV ∈ Rd×dh. В этой записи есть один важный нюанс. Чтобы получить ключи и значения, модель выполняет две линейные проекции для всех L элементов истории. При длинных последовательностях именно эти операции начинают доминировать в вычислительных затратах.
Однако в STCA есть особенность — запрос только один. А значит порядок операций можно изменить. Вместо того чтобы сначала проектировать всю историю в пространство ключей, можно объединить часть операций заранее.
Авторы предлагают сначала вычислить промежуточный вектор u.
u = (qWQ) WKT
Данный вектор имеет размерность 1×d. После этого веса внимания определяются напрямую через скалярные произведения этого вектора с элементами истории.
ɑ = SoftMax(uXT/√dh)
Таким образом ключиXWK больше не нужно вычислять явно для всех элементов последовательности. Авторы фреймворка фактически переносят часть преобразований из пространства истории в пространство запроса. Поскольку запрос всего один, эта операция становится значительно дешевле.
После получения коэффициентов внимания, агрегированное представление истории вычисляется стандартным образом. Сначала формируется взвешенная сумма элементов истории ɑX, а затем результат проходит через проекцию значений.
o = (ɑX) WV
На первый взгляд это может показаться просто алгебраической перестановкой операций. Но на практике эффект оказывается весьма заметным. В стандартной формуле требуется дважды проектировать все L элементов истории — сначала в пространство ключей, затем в пространство значений. В оптимизированной версии одна из этих операций переносится на сторону запроса, что существенно сокращает объём вычислений при больших L.
Важно отметить, что в таком виде операция 𝑊𝑉 также выполняется только один раз, уже после агрегирования всей последовательности. Иными словами, проекция применяется не к каждому элементу истории, а лишь к результирующему вектору. При длинных последовательностях это означает существенное сокращение числа операций.
Более того, если рассматривать полную схему многоголового внимания, становится заметна ещё одна возможность оптимизации. В стандартной архитектуре после вычисления выходов всех голов применяется дополнительная линейная проекция 𝑊𝑂, которая собирает результаты многоголового внимания в единое представление. Поскольку операция 𝑊𝑉 в оптимизированной формуле выполняется уже после агрегирования истории, её можно алгебраически объединить с этой финальной проекцией.
На практике это означает, что часть линейных преобразований может быть слита в одну операцию, уменьшая число проходов по данным и снижая нагрузку на память. Для длинных последовательностей подобные инженерные детали оказываются весьма существенными. Стоимость вычислений определяется уже не столько самой формулой внимания, сколько количеством операций над длинными тензорами.
Таким образом, предложенная авторами фреймворка STCA перестройка вычислений затрагивает сразу несколько уровней архитектуры. С одной стороны, она устраняет необходимость проецировать всю историю в пространство ключей. С другой — позволяет перенести проекцию значений после агрегирования последовательности и потенциально объединить её с финальной проекцией многоголового внимания. В совокупности это делает механизм STCA значительно более экономичным при работе с длинными последовательностями, что и открывает возможность анализа историй длиной в тысячи и десятки тысяч событий.
Отдельного пояснения требует предположение о наличии единственного запроса в слое внимания. В описании оптимизации авторы фреймворка рассматривают наиболее простой случай — когда в механизме Cross-Attention используется один запрос, соответствующий целевому объекту. Именно эта постановка позволяет наиболее наглядно показать, как перестановка операций устраняет необходимость проецировать всю последовательность истории в пространство ключей.
Однако важно понимать, что приведённый вывод носит иллюстративный характер. Архитектура принципиально не ограничена одним запросом. В ряде практических конфигураций их число может быть больше. Тем не менее даже в таком случае сохраняется ключевое свойство предложенной схемы: число запросов остаётся существенно меньше длины анализируемой истории.
Именно этот дисбаланс между количеством запросов и размером исторической последовательности делает предложенную оптимизацию устойчиво полезной. В стандартной реализации внимания стоимость вычислений определяется необходимостью выполнять линейные проекции для каждого элемента истории. Когда история насчитывает тысячи событий, именно эти операции начинают доминировать в вычислительном бюджете модели. Перенос части вычислений на сторону запросов позволяет существенно сократить число таких операций.
Даже если вместо одного запроса используется несколько, их количество, как правило, остаётся на порядки меньше длины последовательности L. В этом случае вычисления масштабируются пропорционально числу запросов, а не размеру истории. Таким образом, предложенная перестройка формулы внимания остаётся эффективной и при более общем сценарии работы модели.
Именно эта комбинация архитектурной идеи и инженерной оптимизации делает предложенный подход особенно привлекательным для задач, где история данных играет ключевую роль — будь то рекомендательные системы или анализ длительных временных рядов, характерных для финансовых рынков.
Реализация средствами MQL5
После рассмотрения теоретических аспектов архитектуры, предложенной авторами фреймворка STCA, логично перейти к практической части нашей работы. Теория задаёт направление и объясняет ключевые принципы. Однако реальная ценность подобных моделей раскрывается лишь при переносе их в рабочий алгоритм. Именно на этом этапе становится понятно, насколько изящные математические идеи выдерживают столкновение с ограничениями вычислительной среды, особенностями памяти и требованиями производительности.
В рамках данного проекта мы сосредоточимся на прикладной реализации описанных подходов средствами MQL5. Наша задача — адаптировать предложенную архитектуру к практическим условиям построения моделей для анализа рыночных данных. Такой перенос требует аккуратной инженерной работы. Необходимо сохранить логику исходного алгоритма, одновременно учитывая специфику среды исполнения и требования к эффективности вычислений.
Начнём мы, пожалуй, с одного из наиболее важных элементов всей архитектуры — оптимизации алгоритма многоголового внимания. Именно этот компонент определяет основную вычислительную нагрузку модели при работе с длинными последовательностями. Даже небольшие улучшения на уровне реализации Attention-механизма способны существенно повлиять на общую производительность системы.
Особенно это актуально в контексте рассматриваемого фреймворка. Одной из ключевых целей STCA является возможность анализа очень длинных историй взаимодействий. В подобных условиях стандартная реализация Attention быстро упирается в ограничения памяти и вычислительных ресурсов. Поэтому предложенные авторами архитектурные и алгебраические преобразования требуют внимательной и аккуратной реализации.
Перед тем как перейти непосредственно к практической реализации, стоит обратить внимание на один важный методологический момент. В оригинальной работе авторы фреймворка STCA демонстрируют оптимизацию вычислений на базе классической формулы Self-Attention. Их выводы и алгебраические преобразования показаны на стандартной схеме механизма внимания, что позволяет ясно проследить логику упрощения вычислений при наличии одного или небольшого числа запросов.
Однако сама идея оптимизации не привязана жёстко именно к базовой реализации Self-Attention. По сути, авторы показывают более общий принцип. Если число запросов существенно меньше длины анализируемой последовательности, часть линейных преобразований можно перенести на сторону запросов и тем самым уменьшить количество операций над длинными тензорами. Это наблюдение сохраняет свою актуальность и для других эффективных реализаций механизма внимания.
В частности, предложенный подход естественным образом сочетается с алгоритмом FlashAttention-2, который мы подробно рассматривали ранее в рамках фреймворка OneTrans. FlashAttention-2 решает другую, но не менее важную задачу — оптимизацию памяти и пропускной способности вычислений при работе с длинными последовательностями. Алгоритм минимизирует количество обращений к глобальной памяти и выполняет вычисления в потоковом режиме, что существенно повышает эффективность обработки больших матриц внимания.
Если объединить эту технику с архитектурной идеей STCA, возникает особенно интересная комбинация. С одной стороны, STCA сокращает саму структуру вычислений, с другой — FlashAttention-2 обеспечивает высокоэффективную реализацию оставшихся операций на уровне низкоуровневых вычислений. В результате модель получает возможность работать с существенно более длинными последовательностями, не выходя за разумные пределы вычислительного бюджета.
Именно поэтому мы будем рассматривать предложенную оптимизацию применительно к алгоритму FlashAttention-2.
Для начала внесём конструктивные изменения на стороне OpenCL-программы. Именно здесь формируется вычислительное ядро алгоритма, поэтому корректная организация операций на этом уровне во многом определяет общую эффективность модели. В рамках данной работы мы создадим новый кернел, в котором объединим два подхода — архитектурную идею STCA и вычислительные принципы FlashAttention.
Напомню, что ранее реализованный нами кернел для алгоритма FlashAttention был построен в классической парадигме многоголового внимания. На вход он получал уже подготовленные тензоры Query, Key и Value. При этом ключи и значения хранились в едином буфере, содержащем многомерный тензор. В нем для каждого элемента последовательности заранее были вычислены соответствующие линейные проекции. Такой подход полностью соответствует стандартной архитектуре Transformer.
Применение идей, предложенных в фреймворке STCA, заметно меняет эту схему. Как было представлено в теоретической части данной статьи, ключевая оптимизация заключается в отказе от необходимости формировать отдельные проекции для каждого элемента длинной исторической последовательности. Если число запросов существенно меньше длины истории, часть вычислений можно перенести на сторону запросов и тем самым исключить дорогостоящие преобразования над большим числом токенов.
В результате структура исходных данных для механизма внимания становится иной. Тензор Query сохраняет свою привычную форму. Он по-прежнему содержит модифицированные векторы-запросы многоголового внимания, сформированные на предыдущих этапах. Именно эти векторы играют роль активных наблюдателей, которые будут сопоставляться с историей.
А вот структура данных для Key и Value претерпевает принципиальное изменение. Мы полностью отказываемся от их явного формирования. Вместо вычисления проекций XWK и XWV для каждого элемента последовательности, механизм внимания напрямую работает с исходными эмбеддингами исторических данных. Иными словами, в качестве ключей и значений используется сам тензор X, содержащий закодированную историю наблюдений.
Такое решение на первый взгляд может показаться нетрадиционным, однако оно полностью следует логике оптимизации STCA. Поскольку запросов значительно меньше, чем элементов истории, гораздо выгоднее перенести линейную проекцию 𝑊𝐾 на сторону Query. Обработка небольшого числа векторов-запросов требует гораздо меньше вычислений, чем преобразование всех элементов истории. После этого векторы запросов напрямую сопоставляются с исходными эмбеддингами истории. Аналогично, проекцию 𝑊𝑉 выгоднее применять к уже агрегированным результатам внимания.
Алгоритм кернел MHFlashSTCA начинается с определения глобальных и локальных идентификаторов потоков. Это позволяет каждому потоку идентифицировать необходимый запрос, голову внимания и участок анализируемой истории.
__kernel void MHFlashSTCA(__global const float *query, __global const float *X, __global float *logsumexp, __global float *output, const int dimension, const int total_X, const int mask_future ) { //--- init const int q_id = get_global_id(0); const int local_id = get_local_id(1); const int h_id = get_global_id(2); const int total_q = get_global_size(0); const int total_loc = get_local_size(1); const int total_heads = get_global_size(2);
Размеры глобальной и локальной сетки потоков сохраняются в отдельных переменных для удобства дальнейших вычислений.
Для аккумулирования промежуточных результатов создаются локальные массивы. Один для скалярных значений. Другой для SIMD-обработки по 4 элемента одновременно. Это позволяет ускорить вычисления на GPU и минимизировать обращения к глобальной памяти, что критично при работе с длинными последовательностями.
__local float temp[LOCAL_ARRAY_SIZE];
__local float4 temp4[LOCAL_ARRAY_SIZE];
Сразу после этого определяется смещение в плоском буфере для конкретного запроса и головы. И инициализируются переменные для численно стабильного вычисления SoftMax.
const int shift_q = RCtoFlat(h_id, 0, total_heads, dimension, q_id); float prev_max = MIN_VALUE; float sumexp = 0; float out = 0;
Основной цикл проходит по элементам истории, распределяя работу между потоками. Каждый поток обрабатывает свой участок последовательности, переходя через шаг, равный размеру локальной группы.
for(int x_id = local_id; x_id < max(total_X, dimension); x_id += total_loc) { const int shift_x = RCtoFlat(x_id, 0, total_X, dimension, 0); //--- Score float score = 0; if(x_id < total_X && (mask_future == 0 || q_id <= x_id)) { for(int d = 0; d < dimension; d += 4) { float4 q = IsNaNOrInf4((float4)( (d < dimension ? query[shift_q + d] : 0.0f), ((d + 1) < dimension ? query[shift_q + d + 1] : 0.0f), ((d + 2) < dimension ? query[shift_q + d + 2] : 0.0f), ((d + 3) < dimension ? query[shift_q + d + 3] : 0.0f) ), 0.0f); float4 k = IsNaNOrInf4((float4)( (d < dimension ? X[shift_x + d] : 0.0f), ((d + 1) < dimension ? X[shift_x + d + 1] : 0.0f), ((d + 2) < dimension ? X[shift_x + d + 2] : 0.0f), ((d + 3) < dimension ? X[shift_x + d + 3] : 0.0f) ), 0.0f); score += IsNaNOrInf(dot(q, k), 0.0f); } } else score = MIN_VALUE;
Внутри цикла вычисляется скалярное произведение между текущим запросом и элементом истории. Для ускорения применяются SIMD-операции по четырем компонентам сразу, при этом результаты проверяются на корректность с помощью функции IsNaNOrInf4.
Маскирование предотвращает заглядывание в будущие элементы истории, если это задано пользователем. А для элементов вне границ последовательности присваивается минимальное значение, чтобы они не влияли на SoftMax.
Далее выполняется нормализация score для численной стабильности. Сначала вычисляется локальный максимум с помощью LocalMax.
//--- norm score float max = fmax(prev_max, LocalMax(score, 1, temp)); if(score > MIN_VALUE) score = exp(score - max); else score = 0.0f; if(sumexp == 0.0f) sumexp = LocalSum(score, 1, temp); else sumexp = IsNaNOrInf(exp(prev_max - max) * sumexp, 0.0f) + LocalSum(score, 1, temp);
Затем применяется экспоненцирование с вычитанием этого максимума. Сумма экспонент аккумулируется с учётом предыдущего значения, корректируя его для изменения максимума и обеспечивая стабильность вычислений.
Одновременно происходит взвешивание исходных эмбеддингов истории. Каждая группа из четырех компонентов текущего элемента истории умножается на вычисленный score и суммируется по локальным потокам, формируя агрегированный выход для конкретного запроса и головы.
for(int d = 0; d < dimension; d += 4) { float4 val = (float4)0.0f; if(score > 0.0f && x_id < total_X) { float4 v = (float4)( (d < dimension ? X[shift_x + d] : 0.0f), ((d + 1) < dimension ? X[shift_x + d + 1] : 0.0f), ((d + 2) < dimension ? X[shift_x + d + 2] : 0.0f), ((d + 3) < dimension ? X[shift_x + d + 3] : 0.0f) ); val = IsNaNOrInf4(v * score, 0.0f); } val = LocalSum4(val, 1, temp4); float add = 0.0f; bool update_out = true; switch(local_id - d) { case 0: add = val.s0; break; case 1: add = val.s1; break; case 2: add = val.s2; break; case 3: add = val.s3; break; default: update_out = false; break; } if(update_out) { if(out != 0.0f) out = IsNaNOrInf(exp(prev_max - max) * out + add, 0.0f); else out = add; } } prev_max = max; }
После окончания обработки всех элементов истории, результат делится на сумму экспонент, получая окончательный SoftMax-взвешенный выход, который записывается в глобальный буфер.
if(local_id < dimension) { if(sumexp > 0.0f) output[shift_q + local_id] = IsNaNOrInf(out / sumexp, 0.0f); else output[shift_q + local_id] = 0.0f; }
Для каждой головы и запроса также сохраняется LogSumExp, который используется для численно устойчивых вычислений операций обратного прохода.
if(local_id == 0) { int shift_logse = RCtoFlat(q_id, h_id, total_q, total_heads, 0); if(sumexp > 0.0f) logsumexp[shift_logse] = IsNaNOrInf(prev_max + log(sumexp), 0.0f); else logsumexp[shift_logse] = 0.0f; } }
В этом кернеле объединены ключевые идеи STCA и FlashAttention. Один или несколько запросов проходят дополнительную обработку с перенесённой проекцией, при этом элементы истории используются напрямую в виде исходных эмбеддингов без отдельного формирования Key и Value. Все операции распределены по потокам и оптимизированы через локальные массивы и SIMD-вычисления, что позволяет эффективно работать с длинными историческими последовательностями. SoftMax реализован с численной стабильностью, а структура кернела обеспечивает минимальные накладные расходы памяти и вычислительные затраты, сохраняя при этом полную информативность механизма внимания.
Заключение
Предложенный в работе "Make It Long, Keep It Fast: End-to-End 10k-Sequence Modeling at Billion Scale on Douyin" фреймворк STCA предлагает инновационный подход к обработке сверхдлинных последовательностей за счёт использования целенаправленного механизма внимания. Основной акцент делается на взаимодействии текущего запроса с историческими данными пользователя. Такая архитектура позволяет существенно сократить вычислительные затраты и требования к памяти, одновременно сохраняя информативность и точность анализа. Это особенно важно при работе с историческими последовательностями длиной до десяти тысяч элементов. Ключевым элементом фреймворка является стратегия одного запроса к истории (Single-query Target-to-history Cross-Attention), обеспечивающая линейную сложность по длине последовательности и позволяющая масштабировать модели без потери качества при ограниченных ресурсах.
В практической части нашей статьи мы начали работу по переносу предложенных подходов в область решения задач финансовых рынков. В частности, была реализована интеграция принципов STCA в механизм FlashAttention на уровне OpenCL-программы, что позволило адаптировать эффективное вычисление внимания к историческим данным рынка. При этом сохранена логика обработки длинных последовательностей с минимальными проекциями, а исходные эмбеддинги истории используются напрямую, что снижает нагрузку на вычислительные ресурсы и упрощает структуру данных. В следующей статье мы продолжим работу.
Ссылки
- Make It Long, Keep It Fast: End-to-End 10k-Sequence Modeling at Billion Scale on Douyin
- Другие статьи серии
Программы, используемые в статье
| # | Имя | Тип | Описание |
|---|---|---|---|
| 1 | Study.mq5 | Советник | Советник офлайн-обучения моделей |
| 2 | StudyOnline.mq5 | Советник | Советник онлайн-обучения моделей |
| 3 | Test.mq5 | Советник | Советник для тестирования модели |
| 4 | Trajectory.mqh | Библиотека класса | Структура описания состояния системы и архитектуры моделей |
| 5 | NeuroNet.mqh | Библиотека класса | Библиотека классов для создания нейронной сети |
| 6 | NeuroNet.cl | Библиотека | Библиотека кода OpenCL-программы |
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Автоматизация торговых стратегий на MQL5 (Часть 20): Мультисимвольная стратегия с использованием CCI и AO
Неопределенность как модель (Часть 1): Случайные величины — язык неопределенности
Машинное обучение и Data Science (Часть 43): Поиск скрытых паттернов в индикаторах с помощью моделей латентных гауссовых смесей LGMM
Искусство работы с логами (Часть 10): Подавление повторяющихся логов (suppression)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования