Нейросети в трейдинге: Двухуровневая адаптация торговой политики (Объект верхнего уровня)
Введение
Рынок редко повторяет одну ситуацию в точности. Одинаковый ценовой импульс может требовать разных действий. Если позиции нет, модель может рассматривать вход. Для уже открытой сделки тот же импульс может подтвердить удержание позиции или потребовать снизить риск. Решение зависит от рынка, состояния счёта, открытой позиции и предыдущих действий.
Нейронная торговая политика сводит такой опыт к одному набору весов. Это даёт модели способность к обобщению. Но локальные закономерности при этом могут теряться. Особенно заметно это на неоднородной рыночной выборке. Похожие состояния иногда требуют противоположных действий, а общий градиент вынужден искать компромисс.
Постоянное переобучение всей сети не решает проблему. Это требует времени и может изменить уже полезное поведение. Полностью замороженная политика тоже не идеальна. Рынок меняется, и ранее редкие состояния со временем могут стать привычными. Между этими крайностями нужен отдельный механизм памяти. Он должен накапливать повторяющиеся способы локальной коррекции политики и возвращать их только в подходящем контексте.
Такую идею развивает фреймворк D2Skill. В авторской работе политика дополняется динамическим банком навыков двух уровней. Task Skills дают высокоуровневую поддержку на уровне всей задачи. Step Skills работают с отдельными состояниями траектории и помогают исправлять локальные ошибки. Банк строится по опыту обучения. Его содержимое расширяется и очищается по мере накопления данных. Полезность навыков оценивается ретроспективно. Для этого авторы сравнивают прогоны политики без навыков и с применением навыков.
В авторском фреймворке различается и способ извлечения опыта. Task Skill связан с общей задачей и может сопровождать всю траекторию. Step Skill привязан к текущему наблюдению и извлекается заново по ходу взаимодействия. Это различие для нас важнее конкретной формы навыка. Оно задаёт два масштаба контекста, которые нельзя свести к одному запросу без потери смысла.
Авторы D2Skill оценивают навык по тому, как он фактически влияет на поведение политики. Для оценки навыка сравниваются две траектории одной и той же версии модели: базовая и скорректированная навыками. Разница между результатами показывает, принесло ли такое вмешательство пользу. Этот принцип мы сохраним и в нашей реализации. Но прежде нужно встроить оба уровня памяти в Актёр и разнести по времени: применение навыков, их обновление и последующую оценку.
В нашей торговой адаптации сохраняется тот же принцип двух уровней, но меняется форма памяти. Исходный D2Skill работает с рекомендациями для агента. Наша модель оперирует числовыми тензорами. Навык хранит коррекцию скрытого представления Актёра. Источником коррекции служит псевдоостаток после обратного прохода. Если сходные наблюдения несколько раз подтверждают одно направление, его можно сохранить и использовать позже.
Такая коррекция не является готовым приказом купить или продать. Она не меняет правила управления риском и не подменяет выходные слои. Навык лишь сдвигает внутреннее представление. После этого Актёр продолжает обычный расчёт и сам формирует действие. Если подходящего опыта нет, модель должна работать без дополнительной поправки.
В первой статье серии мы проверили базовую гипотезу. Был создан объект CD2SkillItem. Он накапливает устойчивую часть последовательности псевдоостатков и возвращает её в вычислительный граф. В контролируемом эксперименте мы сравнили два представления коррекции. Для дальнейшей работы выбрали раздельное накопление направления и масштаба. Одновременно был построен конвейер обновления и применения навыка на GPU.
Одного навыка оказалось недостаточно. Разные рыночные режимы могут давать противоположные поправки. Во второй статье мы построили объект CD2SkillBank. Он связывает коррекции с контекстными ключами, выбирает подходящий опыт и может отказаться от вмешательства. В банке появился жизненный цикл элементов. Новый опыт проходит через Candidate. Фактическое влияние учитывается через Influence, а итоговая ценность уточняется через Utility.
После этого остаётся связать два уровня памяти с торговой политикой. Сам CD2SkillBank не знает, какое внутреннее состояние описывает общую задачу, а какое относится к текущему шагу. Он также не определяет точку применения коррекции. Эти решения должны приниматься на уровне модели.
В этой статье мы построим объект верхнего уровня. Он объединит два банка внутри Актёра и включит их в существующий вычислительный процесс. Банк Task Skills будет работать с более общим представлением торговой задачи. Банк Step Skills получит локальное представление прогнозного сценария. Нам нужно сохранить исходную архитектуру, причинный порядок обучения и независимость Критика.

Основные задачи объекта верхнего уровня
На предыдущем этапе мы получили самостоятельный банк навыков. Он умеет хранить несколько вариантов опыта, выбирать подходящую коррекцию и обновлять её после обратного прохода. Но торговое решение принимает не банк. Оно рождается внутри Актёра, где последовательно обрабатываются состояние счёта, позиции и прогнозные сценарии. Следующий шаг — встроить готовую память в существующую политику.
Это первая задача нового уровня. D2Skill должен усиливать модель, а не перестраивать её вокруг себя. У нас уже есть рабочий вычислительный процесс. Для него определены входы и выходы, размерности тензоров, прямой и обратный проходы, вычисления на GPU через OpenCL и обновление весов. Если ради памяти изменить несколько частей сети, результат будет трудно интерпретировать. Мы не поймём, помогли навыки или поведение изменилось из-за новой архитектуры.
В торговом роботе действует тот же подход. Добавляя новый фильтр, разумно сохранить остальную систему без лишних изменений. Иначе тест покажет общий результат нескольких вмешательств. С D2Skill нам нужен такой же чистый эксперимент. При отключённой памяти Актёр должен сохранять базовый путь. Если банк не нашёл подходящего навыка, результат также не должен меняться из-за самого факта присутствия нового модуля.
Совместимость нужна не только в прямом проходе. Градиенты должны проходить по прежнему вычислительному графу. Обычные веса должны обновляться по прежним правилам. Целевые модели, сохранение состояния и восстановление сети тоже не должны ломаться. Память добавляет локальную коррекцию, но вся остальная модель должна продолжать работать штатно.
Производительность тоже важна. Основные тензоры уже находятся на GPU, и банк должен работать с ними там же. Постоянное копирование больших массивов на CPU и обратно сведёт на нет преимущества вычислений на GPU.
После решения вопроса интеграции нужно разделить два масштаба памяти. В исходном D2Skill Task Skills относятся к задаче в целом, а Step Skills помогают на отдельных шагах. В нашей адаптации это различие переносится в скрытые представления Актёра. Один банк должен работать с более общим контекстом торговой задачи. Второй должен получать представление текущего прогнозного состояния.
В авторском D2Skill граница между уровнями задаётся самим запросом к памяти. Для Task Skills используется описание задачи. Для Step Skills к нему добавляется текущее наблюдение. В торговой модели текстового описания нет. Ту же идею нужно выразить через разные скрытые состояния. Общий запрос связываем с торговой задачей, а локальный — с текущим прогнозным состоянием.
Например, цена ускоряет рост. При отсутствии позиции это может поддержать идею покупки. Для уже открытой длинной позиции тот же импульс имеет другой смысл. Он скорее подтверждает выбранное направление. При короткой позиции модель должна оценить риск продолжения движения против сделки. Рыночный импульс похож, но контекст задачи различается.
Обратная ситуация тоже встречается часто. Позиция и состояние счёта могут несколько баров почти не меняться. За это время рынок успевает перейти от импульса к консолидации или развороту. Общая торговая задача остаётся прежней, но локальная реакция должна измениться. Один общий контекст для двух типов навыков здесь будет слишком грубым.
Task Skills и Step Skills должны работать независимо. Это не требует двух разных алгоритмов банка. Поиск, Candidate, жизненный цикл, Influence и Utility уже реализованы в CD2SkillBank. Различие задаётся входными данными и точкой применения коррекции. Каждый банк должен видеть только своё латентное пространство.
Не менее важно выбрать место вмешательства. Навык не должен корректировать сырые котировки. На этом уровне модель ещё не сформировала содержательный контекст. Но и прямое изменение готового торгового действия нам не подходит. Тогда память превратится в дополнительный генератор сигналов. Нужна промежуточная точка. Представление уже должно иметь торговый смысл, а дальнейший выбор действия должен оставаться за базовой моделью.
Для Task Skills такой точкой становится представление задачи перед сопоставлением с прогнозными сценариями. Для Step Skills нужен отдельный участок сценарного потока. Там уже закодирован возможный ход рынка, но ещё не сформирован итоговый ответ Актёра. Обе коррекции входят в модель на разных уровнях и не складываются напрямую.
Это разделение важно ещё по одной причине. Task Skill и Step Skill могут влиять на итоговое действие в одну сторону. Могут и частично компенсировать друг друга. Заранее назначить одной коррекции больший вес нельзя. Лучше вернуть каждую в её собственный участок модели. Дальнейший вычислительный процесс сам объединит их влияние.
Применение навыка при этом остаётся условным. Рыночная память никогда не охватит все возможные состояния. Новый режим может не иметь близкого аналога. В такой ситуации банк должен вернуть нулевую коррекцию. Базовая политика продолжит расчёт без чужого опыта.
Отдельная группа вопросов возникает при обучении. Навык формируется по псевдоостатку после обратного прохода. Но новый сигнал не должен влиять на решение, из которого он был получен. Иначе появится скрытое заглядывание вперёд. В торговле смысл этой ошибки очевиден. Нельзя сначала узнать результат сделки, а затем использовать его при расчёте исходного входа.
Сбор опыта и применение памяти нужно развести. В режиме формирования банк наблюдает состояние. После обратного прохода он получает псевдоостаток и обновляет память. Сформированная на этом шаге коррекция сможет повлиять только на будущие решения. В режиме оценки или вывода уже накопленный навык можно применять к текущему состоянию.
Для этого объекту верхнего уровня нужны явные режимы работы. Они определяют не только возможность применения коррекции. Режим определяет, можно ли изменять банк, учитывать применение навыка, накапливать Influence и обновлять направление при онлайн-калибровке. Один объект сможет обслуживать разные этапы работы без перестройки сети.
Обратный проход тоже нужно разделить по двум уровням. Банк Task Skills должен получить псевдоостаток своего представления. Банк Step Skills должен получить градиент сценарной ветви. Общий градиент здесь не подходит. Два навыка живут в разных пространствах и корректируют разные части Актёра.
Псевдоостаток нельзя отождествлять с финансовым результатом. Градиент показывает локальное направление изменения модели. Influence оценивает фактическое воздействие применённой коррекции. Utility отвечает на другой вопрос. Она связывает это воздействие с результатом завершённой последовательности. В авторском D2Skill такой ретроспективный сигнал строится через сравнение базовых прогонов политики и прогонов с применением навыков. Мы сохраняем этот принцип, но сам расчёт терминального результата оставляем внешнему контуру обучения.
Ещё одно ограничение касается Критика. D2Skill предназначен для адаптации торговой политики. Значит, память должна изменять Актёра. Если тот же механизм одновременно включить в Критик, изменятся и решение, и система его оценки. Тогда будет трудно отделить пользу навыка от изменения самой шкалы оценки.
Критик сохраняет исходную архитектуру. Он получает скорректированное действие через общий процесс обучения, но собственной памяти D2Skill не имеет. Такое разделение даёт более стабильную точку сравнения и сохраняет прежнюю роль Критика.
Навыки также нужно отделить от обычных весов сети. Веса описывают общее преобразование входных данных. Банк хранит контекстный опыт конкретной политики. Его нельзя безусловно смешивать при каждом обновлении целевой сети. Иначе память одного экземпляра будет перезаписывать историю другого.
Но при сохранении модели банки терять нельзя. Вместе с Актёром должны восстанавливаться ключи, коррекции и накопленная статистика. Память входит в общее состояние модели, но обслуживается отдельно от обычного обновления весов.
Требования к объекту верхнего уровня теперь определены. Он должен встроиться в действующий ORION и сохранить базовый вычислительный путь. Task Skills и Step Skills нужно развести по разным представлениям. Навыки применяются только при подходящем контексте, а обучение сохраняет причинный порядок. Критик остаётся без D2Skill. Банки работают на GPU и сохраняются вместе с Актёром. Эти требования и перенесём в реализацию.
Построение объекта верхнего уровня
В качестве основы мы продолжаем использовать ORION. В этом фреймворке прогноз и торговое решение разделены. Прогнозный модуль формирует несколько вариантов развития рынка. Торговая политика получает эти сценарии вместе с состоянием счёта и позиции. Затем она определяет, что каждый вариант означает для текущей задачи.
Связь между двумя частями обеспечивает объект CNeuronScenarioCrossAttention. Объект формирует запросы из торгового контекста, обрабатывает прогнозные сценарии и сопоставляет два потока. Для Актёра он также учитывает историю предыдущих интерпретаций.
Это удобная точка для внедрения D2Skill. Здесь уже нет сырых котировок. Модель успела сформировать содержательные скрытые представления. Но торговое действие ещё не принято. Значит, память может скорректировать внутреннее состояние и затем вернуть управление обычному пути ORION.
Объект CD2Skill наследуем от CNeuronScenarioCrossAttention. Родительский класс сохраняет основную логику сценарного внимания. Новый объект добавляет два банка навыков и управляет их работой.
class CD2Skill : public CNeuronScenarioCrossAttention { private: CD2SkillBank m_task_bank; CD2SkillBank m_step_bank; bool m_ready; bool m_online_direction_update; ENUM_D2SKILL_MODE m_mode; protected: virtual bool feedForwardSecond(CNeuronBaseOCL *NeuronOCL, CNeuronBaseOCL *Forecast) override; virtual bool calcInputGradientsSecond(CNeuronBaseOCL *NeuronOCL, CNeuronBaseOCL *Forecast) override; virtual bool updateInputWeightsSecond(CNeuronBaseOCL *NeuronOCL, CNeuronBaseOCL *Forecast) override; bool InitBanks(ENUM_OPTIMIZATION optimization_type, uint batch); bool TaskSkillEnabled(void) const; bool StepSkillEnabled(void) const; bool SkillUpdatesEnabled(void) const; bool OnlineDirectionUpdatesEnabled(void) const; bool UpdateOnlineDirection(CD2SkillBank *bank, CBufferFloat *gradient); public: CD2Skill(void); virtual ~CD2Skill(void); virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *opencl, uint scenarios = 21, uint horizon = 12, uint latent = 16, bool critic = false, ENUM_OPTIMIZATION optimization_type = ADAM, uint batch = 1, uint variables = 1, uint stack_size = 1, uint top_k = 1) override; virtual int Type(void) const override; virtual bool Save(const int file_handle) override; virtual bool Load(const int file_handle) override; bool Load(const int file_handle, COpenCLMy *opencl); virtual void SetOpenCL(COpenCLMy *opencl) override; virtual void TrainMode(bool flag) override; virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau) override; virtual bool UpdateInputStateSecond(CObject *SourceObject, CNeuronBaseOCL *Forecast) override; virtual bool Clear(void) override; bool SetMode(const ENUM_D2SKILL_MODE mode); bool SetOnlineDirectionUpdate(const bool enabled); ENUM_D2SKILL_MODE Mode(void) const; bool ResetEpisodeInfluence(void); bool Ready(void) const; CD2SkillBank *TaskBank(void); CD2SkillBank *StepBank(void); CD2SkillBank *Bank(void); const CD2SkillBank *Bank(void) const; const CD2SkillBank *TaskBank(void) const; const CD2SkillBank *StepBank(void) const; bool Enable(const bool task, const bool step); bool TaskFeedForward(CNeuronBaseOCL *source); bool StepFeedForward(CNeuronBaseOCL *source); bool TaskUpdate(CBufferFloat *state, CBufferFloat *gradient); bool StepUpdate(CBufferFloat *state, CBufferFloat *gradient); bool TaskUtility(const float delta_j); bool StepUtility(const float delta_j); bool BackwardSecond(CNeuronBaseOCL *source, CNeuronBaseOCL *forecast); };
В объявлении класса видно, что архитектура остаётся компактной. Постоянная память представлена полями m_task_bank и m_step_bank. Оба имеют тип CD2SkillBank. Поле m_mode задаёт текущий режим D2Skill. Поле m_ready показывает, завершена ли инициализация. Отдельный флаг m_online_direction_update разрешает ограниченную подстройку направления навыка при онлайн-калибровке.
Остальную архитектуру мы получаем от CNeuronScenarioCrossAttention. Внутри нового класса нет второго механизма сценарного внимания или копии прогнозного потока. Мы используем уже существующие компоненты ORION и добавляем память только в нужных местах.
Эта роль отражена и в наборе методов. feedForwardSecond организует прямой проход с двумя банками. calcInputGradientsSecond возвращает градиенты и обучает навыки. updateInputWeightsSecond обслуживает обычные веса. Save и Load сохраняют полный объект. Публичные методы управления позволяют отдельно включать банки, выбирать режим и передавать Utility после завершения последовательности.
Инициализация начинается с базового слоя ORION. Это соответствует нашему требованию совместимости.
bool CD2Skill::Init(uint numOutputs, uint myIndex, COpenCLMy *opencl, uint scenarios, uint horizon, uint latent, bool critic, ENUM_OPTIMIZATION optimization_type, uint batch, uint variables, uint stack_size, uint top_k) { if(critic) ReturnFalse; m_ready = false; m_mode = D2_DISABLED; if(!CNeuronScenarioCrossAttention::Init(numOutputs, myIndex, opencl, scenarios, horizon, latent, false, optimization_type, batch, variables, stack_size, top_k)) ReturnFalse; if(!InitBanks(optimization_type, batch)) ReturnFalse; m_task_bank.SetEnabled(false); m_step_bank.SetEnabled(false); m_ready = true; return(true); }
Метод Init сначала проверяет назначение объекта. Если запрошен режим Критика, инициализация завершается неудачей. Для Критика мы сохраняем обычный CNeuronScenarioCrossAttention. Память D2Skill используется только в Актёре.
Далее вызывается родительский Init со всеми параметрами сценарного слоя. Сначала создаётся полноценный объект ORION. Только после этого метод InitBanks добавляет память навыков. Если любой этап завершился ошибкой, CD2Skill не считается готовым.
После создания оба банка остаются выключенными. Это важная часть интеграции. Само присутствие CD2Skill в модели не должно менять её решения. Память включается отдельно, когда соответствующий этап обучения к этому готов.
Размерности двух банков определяются в методе InitBanks.
bool CD2Skill::InitBanks(ENUM_OPTIMIZATION optimization_type, uint batch) { const uint task_dimension = iQueries * iScenarios * iDimension; const uint step_dimension = iScenarios * iVariables * iHorizon * iDimension; if(task_dimension == 0 || step_dimension == 0 || !OpenCL) ReturnFalse; if(!m_task_bank.Init(task_dimension, 100000, OpenCL, iScenarios, optimization_type, batch)) ReturnFalse; if(!m_step_bank.Init(step_dimension, 100001, OpenCL, iScenarios, optimization_type, batch)) ReturnFalse; m_task_bank.SetActivationFunction(None); m_step_bank.SetActivationFunction(None); return(true); }
Банк Task Skills получает размер представления запросов Актёра. Оно содержит отдельный запрос для каждого торгового контекста и каждого прогнозного сценария. В нашей реализации это состояние формируется компонентом cQueryProjection.
Банк Step Skills работает с другим пространством. Его размер включает сценарии, прогнозируемые переменные, горизонт и латентную размерность. Это соответствует выходу компонента cWz, который проецирует скрытое состояние прогнозных сценариев.
Так два одинаковых объекта CD2SkillBank получают разные роли. Банк не знает, относится ли его память к задаче или к шагу. Это определяет верхний объект. Он выбирает источник запроса и точку возврата коррекции.
Для Актёра ORION уже формирует три группы запросов. Они описывают баланс, открытые позиции и календарный контекст. Каждый запрос разворачивается на все прогнозные сценарии. Выход cQueryProjection уже содержит состояние торговой задачи и связь с набором возможных продолжений рынка. Это делает его естественным контекстом для Task Skills.
Компонент cWz решает другую задачу. Он проецирует латентное состояние каждого сценария на всём горизонте прогноза. Здесь ещё нет итогового торгового решения, зато уже присутствует структура возможного движения рынка. Это делает выход cWz подходящим контекстом для Step Skills.
Дополнительная функция активации для банков отключается. Коррекция должна сохранять знак и направление, накопленные по псевдоостаткам. После этого архитектура готова к прямому проходу.
Само включение банка отделено от режима его использования. Это позволяет не создавать несколько вариантов сети для разных этапов обучения. В режиме сбора память только наблюдает состояния и получает псевдоостатки после обратного прохода. В режиме оценки уже сформированные навыки участвуют в решении и накапливают Influence. Режим вывода использует готовую память без её изменения. Онлайн-калибровка допускает ограниченную подстройку выбранного навыка.
Такой порядок нужен не только для удобства программы. Он задаёт временную границу доступного опыта. При расчёте текущего действия Актёр видит лишь ту память, которая была сформирована раньше. Новое наблюдение становится частью банка только после завершения соответствующего обратного прохода.
Первым формируется контекст Task Skills. Как и в исходном ORION, компонент cQueryProjection обрабатывает состояние Актёра. Затем полученное представление передаётся банку.
if(!cQueryProjection.FeedForward(NeuronOCL)) ReturnFalse; CNeuronBaseOCL *task_source = cQueryProjection.AsObject(); if(TaskSkillEnabled()) { if(!m_task_bank.FeedForward(task_source)) ReturnFalse; task_source = m_task_bank.AsObject(); } else if(m_mode == D2_COLLECT && m_task_bank.Enabled() && !m_task_bank.Observe(task_source)) ReturnFalse;
Здесь видно разделение режимов. Если Task Skills разрешено применять, вызывается метод FeedForward банка. Он выполняет поиск и возвращает скорректированное представление. Указатель task_source переключается на выход банка. Дальнейший ORION работает уже с этим состоянием.
Если подходящего навыка нет, коррекция равна нулю. Базовое представление не меняется. Это сохраняет исходное поведение модели.
В режиме D2_COLLECT используется другой путь. Метод Observe фиксирует контекст для будущего обновления, но не передаёт коррекцию в Актёр. Сначала модель принимает решение без нового знания. Только после обратного прохода банк сможет использовать полученный псевдоостаток.
По такому же принципу подключается банк Step Skills. Но его запрос формируется из прогнозного потока.
if(!cWz.FeedForward(Forecast)) ReturnFalse; CNeuronBaseOCL *step_source = cWz.AsObject(); if(StepSkillEnabled()) { if(!m_step_bank.FeedForward(step_source)) ReturnFalse; step_source = m_step_bank.AsObject(); } else if(m_mode == D2_COLLECT && m_step_bank.Enabled() && !m_step_bank.Observe(step_source)) ReturnFalse;
Компонент cWz проецирует латентные состояния прогноза. Это представление поступает в банк Step Skills. При активной памяти банк возвращает коррекцию через FeedForward. В режиме сбора метод Observe только регистрирует состояние.
Два банка не передают коррекции друг другу. Task Skill меняет представление торговой задачи. Step Skill меняет сценарное представление. Они встречаются позже внутри исходного вычислительного пути ORION.
Следующий фрагмент показывает эту точку.
if(!cWu.FeedForwardBuffer(forecast.GetLogU())) ReturnFalse; if(!SumAndNormalize(step_source.getOutput(), cWu.getOutput(), cTokenSum.getOutput(), 1, false, 0, 0, 0, 1)) ReturnFalse; if(!cTokenPE.FeedForward(cTokenSum.AsObject())) ReturnFalse; if(!cTokensTranspose.FeedForward(cTokenPE.AsObject())) ReturnFalse; if(!Concat(cTokensTranspose.getOutput(), cTokensTranspose.getOutput(), cKV.getOutput(), iScenarios * iDimension, iScenarios * iDimension, iVariables * iHorizon)) ReturnFalse; if(!cAttention.FeedForward(task_source, cKV.getOutput())) ReturnFalse;
Скорректированный step_source объединяется с оценкой неопределённости прогноза. Затем формируются сценарные токены. Скорректированный task_source используется как запрос для компонента cAttention. Дальнейшая работа кросс-внимания остаётся прежней.
Для торговой модели это даёт понятное разделение ролей. Task Skills помогают уточнить, что означает текущая задача для Актёра. Step Skills уточняют интерпретацию прогнозного состояния. После этого ORION сам связывает оба представления и формирует дальнейший контекст решения.
D2Skill не выдаёт отдельный сигнал Buy или Sell. Он не обходит базовый Актёр. Память только меняет скрытые представления. Это сохраняет прежний порядок обработки сценариев, истории и выходных слоёв.
После прямого прохода остаётся обучить память. Здесь важно вернуть каждому банку градиент из той же точки, где его коррекция участвовала в расчёте. Полный обратный проход выполняет метод calcInputGradientsSecond. Основная часть наследует логику родительского класса. В конце режима сбора объект передаёт банкам состояния и соответствующие псевдоостатки.
if(!NeuronOCL.CalcHiddenGradients(cQueryProjection.AsObject())) ReturnFalse; if(SkillUpdatesEnabled() && m_task_bank.Enabled() && !m_task_bank.UpdateFromGradient(cQueryProjection.getOutput(), cQueryProjection.getGradient())) ReturnFalse; if(SkillUpdatesEnabled() && m_step_bank.Enabled() && !m_step_bank.UpdateFromGradient(cWz.getOutput(), cWz.getGradient())) ReturnFalse; if(!UpdateOnlineDirection(GetPointer(m_task_bank), m_task_bank.getGradient()) || !UpdateOnlineDirection(GetPointer(m_step_bank), m_step_bank.getGradient())) ReturnFalse;
Для Task Skills используется выход cQueryProjection и его градиент. Для Step Skills используются выход и градиент cWz. Каждый банк обучается в собственных координатах, и два псевдоостатка не смешиваются.
Дальнейшая обработка выполняется уже знакомым методом UpdateFromGradient объекта CD2SkillBank. В предыдущей статье мы подробно рассмотрели этот алгоритм. Банк проверяет контекст и направление, обновляет существующий навык или продолжает формирование Candidate. Здесь повторять внутреннюю механику не требуется.
Порядок операций сохраняет причинность. Сначала Актёр формирует действие. Затем обратный проход создаёт псевдоостаток. Только после этого память обновляется. Значит, новое наблюдение сможет повлиять лишь на следующие решения.
При активных навыках обратный проход выполняет ещё одну работу. Он позволяет оценить, в ту ли сторону сдвинула представление применённая коррекция. Для каждого банка используется градиент его собственной точки. Скалярное согласование коррекции и градиента накапливается как Influence. Этот показатель не равен прибыли. Он показывает только фактическое участие навыка в изменении внутреннего состояния.
Финансовая оценка появляется позже. После завершения последовательности внешний контур сравнивает результат с базовым поведением политики и передаёт терминальный сигнал в Utility. Логика совпадает с D2Skill: навык применяют в контексте, затем измеряют его воздействие, а практическую ценность уточняют после завершения траектории.
При работе с уже сформированными навыками объект действует иначе. В режимах оценки и онлайн-калибровки банк получает градиент своей ветви и накапливает Influence. При необходимости онлайн-калибровка может вызвать UpdateOnlineDirection и немного уточнить направление выбранного навыка. Полный жизненный цикл банка при этом не запускается заново.
Utility поступает ещё позже. Методы TaskUtility и StepUtility принимают терминальный сигнал от внешнего обучающего контура. Сам CD2Skill не рассчитывает финансовый результат. Это соответствует разделению ответственности. Объект знает, какие навыки применялись и как они повлияли на локальный градиент. Сравнение торговых траекторий и расчёт итоговой полезности остаются задачей полного процесса обучения.
Обычное обучение сети при этом не меняется. D2Skill не подменяет оптимизатор. Унаследованные параметры сценарного внимания продолжают получать градиенты и обновляться штатно, когда это разрешено выбранным этапом обучения. Банки используют собственные правила накопления. Обновление весов и обновление памяти остаются разными операциями.
Тот же принцип действует при копировании параметров между экземплярами модели. Веса можно сглаживать привычным способом, но содержимое банков не должно автоматически смешиваться. При сохранении на диск ситуация обратная. Навыки являются частью накопленного состояния Актёра. Оба банка записываются вместе с объектом и возвращаются после загрузки.
CD2Skill остаётся надстройкой над уже знакомым сценарным кросс-вниманием ORION. Он не меняет назначение родительского слоя. Новый объект добавляет две точки памяти и управляет их режимами. При отключённых навыках сохраняется базовый путь. При включённых каждый банк корректирует только своё представление.

Заключение
В начале статьи мы поставили задачу перейти от отдельного банка навыков к полной двухуровневой адаптации Актёра. D2Skill должен был остаться дополнением к существующей модели. Нам требовалось сохранить вычислительный процесс ORION, разделить Task Skills и Step Skills и не переносить память политики в Критик.
Для решения задачи создан объект CD2Skill. Он наследует CNeuronScenarioCrossAttention и использует два экземпляра CD2SkillBank. Банк Task Skills работает с представлением торговой задачи. Банк Step Skills получает сценарное представление прогноза. Каждая коррекция возвращается в своё латентное пространство. Два уровня остаются независимыми и не смешиваются внутри одного вектора.
Мы также разделили сбор опыта и применение памяти. В режиме формирования банки наблюдают состояния и обновляются только после обратного прохода. При эксплуатации используется уже накопленный опыт. Каждый банк получает собственный псевдоостаток и собственный Influence. Терминальная Utility передаётся позднее из внешнего контура обучения. Такой порядок сохраняет причинность и не даёт текущему результату повлиять на уже принятое решение.
Поставленная задача решена на уровне объекта верхнего уровня. D2Skill встроен в Актёр без замены базовой архитектуры ORION. При отключённой памяти модель сохраняет исходный путь, а Критик продолжает работать без D2Skill. Следующий этап уже относится к полной торговой системе. Нам предстоит построить модель, организовать обучение и онлайн-калибровку, а затем проверить вклад Task Skills и Step Skills на исторических данных.
Ссылки
Программы, используемые в статье
| # | Имя | Тип | Описание |
|---|---|---|---|
| 1 | NeuroNet_D2Skill.mqh | Библиотека классов | Реализация CD2SkillItem, CD2SkillBank и CD2Skill |
| 2 | NeuroNet.cl | OpenCL-программа | Ядра OpenCL для поиска, обновления, жизненного цикла и Utility |
| 3 | NeuroNet_Declarations.mqh | Объявления классов | Интерфейсы объектов D2Skill |
| 4 | NeuroNet_Core.mqh | Общий API | Создание объектов D2Skill и регистрация ядер OpenCL |
| 5 | NeuroNet_Definitions.mqh | Определения | Состояния, режимы и идентификаторы ядер OpenCL |
Проект представлен на forge.mql5.io/dng.
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Интеграция MQL5 с пакетами обработки данных (Часть 7): Построение многоагентных сред для межсимвольного взаимодействия
Мастер-класс по созданию пользовательских индикаторов (Часть 1): Разработка индикатора Supertrend на MQL5
Изучение стандартной библиотеки MQL5 (Часть 13): Применение библиотеки математических решателей в торговле
Индикатор Sigma Score для MetaTrader 5: Простой детектор статистических аномалий
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования