Redes neurais em trading: sinais de negociação robustos em qualquer regime de mercado (ST-Expert)
Introdução
Os mercados financeiros modernos são um ecossistema dinâmico, no qual milhões de operações, decisões de órgãos reguladores, relatórios corporativos e sinais macroeconômicos se combinam em um padrão complexo. Para um trader ou analista, a principal tarefa é reconhecer regularidades nesse padrão e, com base nelas, elaborar uma previsão. Mas é justamente aqui que surge a contradição central: o mercado muda mais rápido do que os modelos convencionais conseguem se adaptar. O que funcionava ontem pode, amanhã, tornar-se não apenas inútil, mas também perigoso.
Estamos acostumados a pensar em termos de correlações. Há uma relação estável entre o preço do petróleo e a cotação do dólar canadense, entre as taxas de juros do Fed e o setor de tecnologia, entre a demanda por ouro e a dinâmica do dólar. Mas basta o ambiente externo mudar para que essas dependências se desfaçam. No colapso provocado pela Covid em 2020, em poucas semanas as relações habituais entre ações, títulos e commodities deixaram de refletir a realidade. Mesmo mudanças de regime mais suaves, como os ciclos de alta e queda das taxas do Fed, são capazes de alterar drasticamente as correlações e comprometer modelos que pareciam confiáveis.
A essência do problema é que os algoritmos modernos são treinados em intervalos de dados relativamente curtos e homogêneos. Nessas condições de laboratório, eles apresentam resultados impressionantes, identificando relações sutis entre ativos. Mas, assim que o mercado se afasta da distribuição observada no treinamento, a precisão das previsões cai de forma acentuada. Na prática, os modelos funcionam muito bem em períodos tranquilos, mas não sabem lidar com transições de fase do mercado.
Essa situação lembra, em muitos aspectos, as redes de transporte urbano, usadas como exemplo pelos autores do trabalho "Robust Traffic Forecasting against Spatial Shift over Years" para propor o novo framework ST-Expert. Enquanto a cidade permanece inalterada, as previsões de tráfego funcionam muito bem. Mas basta construir um novo entroncamento viário ou inaugurar um grande shopping center para que as rotas anteriores deixem de ser relevantes. No ambiente financeiro, esses fatores de mudança são decisões regulatórias, sanções, conflitos geopolíticos ou o surgimento de novas tecnologias. O mapa de interdependências muda, e os modelos anteriores deixam de ser eficazes.
Para enfrentar essa tarefa, os autores do ST-Expert propõem uma solução original baseada em Mixture of Experts. A ideia central é que o modelo não aprende a partir de uma única estrutura rígida de dependências, mas de um conjunto de geradores de grafos, os chamados gráfons. Cada um deles representa um tipo específico de comportamento do mercado. Um identifica regularidades em condições de tendência estável, outro descreve a fase de alta volatilidade, um terceiro detecta correlações locais dentro dos setores. Quando o mercado muda, o sistema não entra em colapso: ele combina de forma adaptativa os padrões já aprendidos, criando novas relações entre os instrumentos e preservando a precisão da previsão.
É justamente aqui que aparece a primeira e, talvez, principal vantagem da abordagem: a capacidade de se adaptar a novas condições de mercado. Se os modelos convencionais acabam presos a um período histórico específico, o novo framework trata o mercado como um mosaico, no qual cada regime é apenas um fragmento temporário de um todo maior. Com isso, o algoritmo consegue compor uma nova combinação a partir dos elementos já aprendidos e gerar uma previsão precisa justamente onde outros sistemas perdem robustez. Para o trader, isso significa menos sinais falsos em períodos de turbulência e mais confiabilidade na construção de estratégias de longo prazo.
Mas a adaptabilidade é apenas um dos aspectos. Uma vantagem igualmente importante é a universalidade da arquitetura. A camada de gráfons especialistas pode ser facilmente integrada a soluções existentes. Ela pode ser adicionada tanto a redes neurais de grafos, que analisam interdependências em rede entre ativos, quanto a Transformers, que trabalham com séries temporais de cotações. Isso torna a abordagem especialmente valiosa para profissionais de mercado. Ela não exige uma reformulação radical da infraestrutura e pode fortalecer sistemas já ajustados e estabilizados.
Outra vantagem está na robustez diante das chamadas mudanças de regime. A história dos mercados financeiros mostra de forma convincente que a estabilidade é rara, enquanto a mudança é a regra. Cada década traz uma nova crise, e cada fase dentro de uma crise vem acompanhada por uma cascata de choques imprevisíveis. A tentativa de encontrar invariantes eternos acaba sendo uma ilusão. O novo framework reconhece de forma realista a variabilidade dos mercados e se apoia justamente na capacidade de alternar entre cenários. Isso é especialmente importante para testes de estresse e previsões de longo prazo, em que o custo de um erro é extremamente alto.
Ao mesmo tempo, a abordagem permanece compacta e eficiente. Em aplicações financeiras, o tempo é um fator crítico. A decisão sobre uma operação precisa ser tomada em milissegundos. Por isso, por mais precisos que sejam, os modelos não podem ser excessivamente pesados. O framework proposto leva esse fator em conta. Ele adiciona flexibilidade e robustez sem elevar drasticamente os custos computacionais. Com isso, pode ser aplicado em sistemas em tempo real, desde o trading algorítmico até a gestão de riscos.
Por fim, vale destacar também a flexibilidade de expansão. Os gráfons especialistas não se limitam a um único mercado ou a uma única classe de ativos. Eles podem ser usados em ações, títulos, câmbio e mercados de criptomoedas. Além disso, são capazes de integrar dados de diferentes tipos, desde cotações e fluxos de notícias até indicadores macroeconômicos. Isso abre caminho para a criação de modelos realmente abrangentes, capazes de levar em conta a estrutura multicamadas dos sistemas financeiros.
Trata-se de uma visão fundamentalmente nova sobre o próprio modo de modelar em condições de incerteza. Se os modelos tradicionais insistem em procurar certas regularidades eternas, o ST-Expert ensina o sistema a viver em um mundo em constante mudança. Ele transforma a previsão em um processo dinâmico, capaz de levar em conta mudanças inesperadas e se reconfigurar em tempo real.
Algoritmo ST-Expert
A criação de um modelo preditivo confiável para os mercados financeiros exige a capacidade de distinguir e incorporar diferentes regimes de mercado. Na prática, a estrutura das correlações entre ativos está longe de ser estática. O que ontem parecia uma regra estável, amanhã pode se revelar uma coincidência aleatória. Em períodos de alta do setor de tecnologia, as relações entre ações de empresas de TI e taxas básicas de juros podem ser mínimas, mas, aos primeiros sinais de superaquecimento, elas ganham protagonismo. Nos mercados de commodities, a correlação entre o preço do petróleo e as divisas de países exportadores se manifesta com especial força em períodos de crise e depois pode praticamente desaparecer. Fica evidente que um modelo que tenta reduzir toda essa diversidade a uma única matriz fixa de relações está condenado a perder precisão.
É por isso que os autores propõem uma abordagem baseada na identificação de segmentos temporais característicos, dentro dos quais o mercado se comporta de forma relativamente homogênea. A ideia é simples. Se toda a história for tratada como um único conjunto de dados, os regimes importantes deixam de ser distinguíveis, e nenhum especialista conseguirá aprender corretamente seus padrões característicos. Mas, se a história for dividida em períodos, cada um com seu próprio tipo estável de correlações, é possível criar um especialista dedicado para cada um desses períodos. Em seguida, o modelo passa a combinar esses especialistas, criando uma representação flexível do ambiente de mercado.
Formalmente, isso leva ao problema da divisão máxima de grafos espaço-temporais (Maximum Spatiotemporal Graph Division, MSGD). Toda a série temporal (que denotaremos por T) é dividida em K intervalos não sobrepostos. Cada intervalo T_i inclui pares (X_t, Y_t) para t ∈ [ti, t{i+1}). O aspecto central é que, dentro desse intervalo, as relações de mercado são descritas pela mesma estrutura Rk, enquanto, em intervalos diferentes, essas estruturas são distintas.
![]()
Na prática, isso significa que as sessões da manhã no mercado acionário podem ser semelhantes entre si, mesmo quando ocorrem em dias diferentes. A atividade dos investidores de varejo cria um tipo de correlação, enquanto as horas da noite, quando os participantes institucionais passam a atuar no mercado, formam um quadro de relações completamente diferente. A ideia do MSGD é dividir os dados justamente de modo que a diferença entre os intervalos segmentados seja máxima.

Sob as condições

Aqui, como medida de diferença d(•,•), os autores do framework propõem usar o coeficiente τ de Kendall, que reflete o quanto as estruturas de correlação diferem entre períodos. As restrições α1, α2definem o comprimento mínimo e máximo permitido do intervalo, enquanto T representa a duração total da série.
Assim, a tarefa se resume a segmentar a série histórica em partes que diferem o máximo possível entre si pelo tipo de dependência. Em outras palavras, buscamos regimes de mercado puros: fase de alta, fase de mercado lateral, fase de alta volatilidade. Essa abordagem lembra a criação de índices temáticos. Cada índice reúne papéis de um mesmo tipo e mostra seu comportamento sem misturá-lo com outros segmentos do mercado.
Resolver esse problema, é claro, não é simples. Ela não admite forma analítica, por isso os autores do framework recorrem à programação dinâmica. Isso permite selecionar de forma eficiente tanto o número de intervalos K quanto seus limites, mesmo com grandes volumes de dados.
Uma vez definidos os períodos, surge a pergunta: como especificar exatamente a estrutura das relações em cada um deles? Para isso, introduz-se o conceito de gráfon, um gerador probabilístico de grafos. Diferentemente de uma matriz de adjacência fixa, aqui o gráfon é definido por uma matriz probabilística P, em que o elemento P(i,j) reflete a probabilidade de conexão entre os ativos i e j. Assim, o gráfon não fixa rigidamente a presença de arestas, mas descreve sua distribuição probabilística. Essa representação está muito mais próxima da realidade dos mercados financeiros, onde as relações têm caráter estocástico.
Para criar o gráfon de cada especialista, são usadas matrizes de embeddings treináveis Egk ∈ R|V|*d e uma camada dinâmica de embedding Et ∈ R|V|*d, dependente dos dados de mercado atuais. Assim, a matriz probabilística do k-ésimo especialista é calculada pela fórmula:
![]()
em que σ é a sigmoide, que converte todos os valores para o intervalo (0,1).
Para obter um grafo concreto a partir dessa matriz probabilística, aplica-se a reparametrização via Gumbel-SoftMax.

em que z1, z2 são amostrados da distribuição Gumbel(0,1), e s é o parâmetro de temperatura.
Na prática, esse recurso permite amostrar arestas específicas, evitando uma binarização rígida e, ao mesmo tempo, minimizando o impacto de correlações fracas dominadas por ruído, tão abundantes nos mercados financeiros.
Como resultado, cada especialista recebe seu próprio gerador de grafos, que representa um tipo específico de comportamento do mercado. Alguns gráfons tenderão a formar clusters densos, por exemplo, dentro de setores. Outros gerarão conexões mais esparsas, características de correlações globais entre classes de ativos. Juntos, eles formam um ensemble completo de especialistas, capaz de descrever e combinar novos regimes de mercado, mesmo que esses regimes não tenham ocorrido anteriormente.
No entanto, a criação dos especialistas é apenas o primeiro passo. O ponto central é treiná-los em um ambiente de mudança constante. No mundo real, as dependências de mercado estão sujeitas a alterações contínuas. As estruturas de correlação entre ativos se formam e se desfazem sob a influência de uma ampla gama de fatores. Decisões de bancos centrais alteram o comportamento de divisas e títulos. Mudanças na política tributária ou na regulação reconfiguram relações setoriais. Crises ou mudanças tecnológicas provocam seus próprios ajustes bruscos. Para um modelo treinado em um conjunto de dados relativamente estável, alterações desse tipo representam um problema sério. Seu mapa do mercado deixa subitamente de coincidir com a realidade.
Para preparar o sistema para esse tipo de incerteza, os autores do framework propõem usar aprendizado episódico. A essência dessa abordagem consiste em separar as funções dos especialistas. Quando uma observação xi ∈ Ti é passada como entrada, apenas o gráfon Pi associado ao respectivo intervalo temporal fica responsável pela tarefa principal de previsão. Ele é usado para gerar o grafo Gi ⁓ Pi, que depois alimenta o módulo ST-GNN para gerar a previsão.
![]()
Assim, é justamente o especialista associado que é treinado pela função de perda principal, responsável pela precisão da previsão.

Mas o treinamento não termina aí. Os demais especialistas {Pk}Kk=1,k≠i, embora não sejam usados para a previsão direta nesse caso, desempenham uma função auxiliar importante. A partir deles, gera-se uma mistura de gráfons Pimix(x), que deve reproduzir com a maior precisão possível a estrutura do gráfon de referência Pi.
Para isso, introduz-se uma rede de gating, que calcula um vetor de pesos a partir da entrada original xi.
![]()
Esses pesos determinam em que proporção os demais especialistas são combinados.

Em seguida, essa mistura é comparada com o gráfon de referência Pi.

É importante observar que a otimização associada a Lmix atualiza exclusivamente os pesos de mistura w, sem alterar os parâmetros dos próprios gráfons. Com isso, os especialistas preservam sua independência e continuam se especializando em seus próprios regimes de mercado, enquanto o vetor de pesos aprende a combiná-los corretamente para reproduzir as propriedades do gráfon de referência.
Assim, o treinamento se organiza em duas frentes paralelas. Cada especialista aprimora sua capacidade de prever dentro de seu próprio regime de mercado, sem interferir nas áreas dos demais especialistas, enquanto a rede de gating é treinada em uma tarefa de imitação. Ela deve aprender a reunir o conhecimento dos demais especialistas de modo que, em conjunto, eles reproduzam a estrutura da referência atual. Essa separação de papéis torna o modelo, ao mesmo tempo, profundamente especializado e flexível, capaz de se adaptar a novas situações de mercado.
Isso pode ser comparado à dinâmica de uma equipe de analistas. Cada um deles tem sua própria área de especialização. Um entende melhor os ativos ligados a commodities, outro se especializa em mercados de câmbio, um terceiro em títulos. Quando surge uma nova situação, quem faz a previsão é justamente o analista cuja área de conhecimento é mais relevante. Os demais, nesse momento, desempenham uma função auxiliar. Eles ajudam a equipe a avaliar melhor até que ponto suas visões combinadas conseguem reproduzir o entendimento essencial do especialista principal.
Após o treinamento, quando o modelo se depara com dados reais de mercado, ele passa a operar pela primeira vez em um cenário de incerteza total. Se, durante o treinamento, ele sempre teve acesso ao gráfon correto Pi, associado ao respectivo intervalo temporal, agora essa informação auxiliar já não está disponível. Isso corresponde à situação natural do trading. O trader pode se apoiar em regularidades históricas, mas nunca sabe de antemão em que fase exata do ciclo o mercado se encontra hoje.
O primeiro passo na fase de ambiente de produção consiste em fazer todos os especialistas gerarem simultaneamente um conjunto de gráfons probabilísticos. Cada um deles gera uma interpretação própria da estrutura de relações entre os ativos. Na prática, cada especialista propõe sua própria hipótese sobre o mercado. Um identifica clusters claramente definidos por setor; outro, correlações globais entre divisas e ativos ligados a commodities; um terceiro, interdependências locais instáveis, mas significativas.
A etapa seguinte consiste em calcular o vetor de pesos com base no sinal de mercado atual xtest.
![]()
Esses pesos refletem a relevância de cada especialista naquele instante. Pode-se dizer que a rede de gating atua como um árbitro, definindo a importância da opinião de cada especialista naquele exato momento. Se, por exemplo, o mercado estiver passando por um pico de volatilidade em ativos ligados a commodities, os especialistas treinados em cenários correspondentes receberão um peso maior.
Depois do cálculo dos pesos forma-se o gráfon combinado final, que representa uma visão agregada das relações de mercado.
A principal diferença entre a fase de produção e a fase de treinamento é que, agora, todos os especialistas participam simultaneamente. Antes, o sistema sabia qual era o especialista correto e usava os demais apenas para imitação; agora, precisa confiar na avaliação coletiva. Esse ponto é fundamental. O mercado real não fornece referências prontas, e o modelo precisa ser capaz de sintetizar uma nova representação a partir do conhecimento acumulado.
Na etapa final, um grafo específico é amostrado a partir da matriz probabilística obtida que reflete a distribuição atual das relações entre os ativos. É ele que alimenta o módulo ST-GNN para gerar a previsão. Aqui, o sistema, na prática, gera uma previsão da dinâmica do mercado apoiando-se não em uma estrutura rigidamente fixa, mas em uma representação flexível, gerada conjuntamente por todos os especialistas.
O resultado é um modelo que, em produção, se comporta como um gestor de portfólio experiente. Ele não depende de uma única fonte de informação, mas compara e combina diferentes pontos de vista, criando um mapa dinâmico do mercado. Essa abordagem torna o modelo robusto, flexível e capaz de preservar a precisão da previsão mesmo quando as regularidades habituais do mercado deixam de valer sob a pressão de novos eventos.
Outra vantagem fundamental da abordagem proposta está na universalidade dos gráfons treináveis. Embora, na descrição acima, eles sejam usados em conjunto com redes neurais de grafos espaço-temporais (ST-GNNs), seu potencial é muito mais amplo. Em si, os gráfons são uma ferramenta flexível para descrever dependências probabilísticas e podem servir como elemento de ligação para uma série de arquiteturas.
Em particular, em modelos baseados em Transformers, o gráfon pode desempenhar o papel de uma máscara dinâmica ou de uma matriz de atenção formada pelo modelo, na qual as relações entre os elementos da sequência são determinadas não por regras predefinidas, mas por uma estrutura probabilística aprendida. Isso abre caminho para a criação de Transformers mais adaptativos, capazes de identificar melhor regularidades de mercado em mudança. Além disso, os gráfons também podem ser usados em sistemas híbridos, nos quais CNNs, RNNs e mecanismos de atenção são combinados, aumentando a eficiência desses componentes.
A visualização do framework ST-Expert criada pelos autores é apresentada a seguir.

Implementação em MQL5
Depois de examinar os aspectos teóricos do framework ST-Expert, passamos à implementação prática dessa abordagem em MQL5. E começaremos, naturalmente, pela criação dos gráfons. Mas, antes disso, vamos discutir as decisões adotadas em nossa implementação.
Pessoalmente, há dois pontos no treinamento proposto pelos autores do framework que me causam ressalvas. O primeiro é a necessidade de pré-processar o conjunto de treinamento para identificar regimes de mercado específicos. Essa etapa é bastante trabalhosa, exige um procedimento adicional de otimização e, muitas vezes, recorre a heurísticas. Em condições reais de mercado, uma segmentação rígida desse tipo pode se revelar não apenas custosa em termos de recursos, mas também pouco confiável. As fronteiras entre regimes costumam ser difusas, e os próprios regimes podem se alternar rapidamente. Se dividirmos a série histórica de forma rígida demais, corremos o risco de perder fases de transição importantes, que muitas vezes servem justamente de base para muitos movimentos do mercado.
O segundo ponto diz respeito à própria lógica de treinamento dos gráfons e dos pesos. Na formulação original, presume-se que, quando uma observação do intervalo Ti é usada como entrada, é justamente o especialista correspondente Pi que gera a previsão, enquanto os demais são combinados em uma mistura que deve reproduzir sua estrutura. Formalmente, esse esquema parece elegante. Cada gráfon aprende a prever seu próprio regime, e a rede de gating aprende a reunir os demais de modo que eles consigam imitar a referência. No entanto, na prática, surge um problema sutil. Na prática, fixamos rigidamente os papéis dos especialistas e eliminamos seu aprendizado cruzado. Isso cria o risco de especialização demasiadamente estreita, quando um especialista realmente funciona bem apenas em seu domínio restrito, mas perde completamente a eficácia diante da menor mudança no contexto de mercado.
Além disso, esse tipo de esquema torna o treinamento dos pesos dependente da correção do gráfon de referência. Se, em algum momento, Pi tiver sido contaminado por ruído ou tiver registrado um estado de mercado atípico, a rede de gating será obrigada a aprender a reproduzi-lo, em vez de identificar uma regularidade mais geral. Em dados financeiros, saturados de ocorrências aleatórias de valores atípicos e correlações espúrias, isso pode se tornar uma fonte significativa de erros.
Em nossa implementação, vamos tentar suavizar essa hierarquia rígida. Em vez de associar de forma permanente cada especialista a seu regime, permitiremos que cada gráfon contribua para a previsão com uma probabilidade que depende do estado atual do mercado. Formalmente, o sistema conta com N especialistas, e cada especialista gera sua própria previsão. O gating é uma rede leve que retorna logits a partir dos features de mercado. Para adicionar um caráter episódico e impedir que um único especialista monopolize a atenção, usamos uma máscara aleatória de Dropout e aplicamos o SoftMax aos logits mascarados. Com isso, obtemos os pesos e a previsão final do ensemble. Esse esquema permite que os pesos aprendam não apenas pela tarefa de imitar a referência, mas também pela melhoria coletiva da previsão, quando a importância de um especialista é determinada pelo quanto sua contribuição melhora o ensemble naquele estado de mercado.
A função de perda é definida como uma combinação de tarefas. Ela deve se basear em uma medida da qualidade do ensemble, à qual se acrescenta uma soma ponderada das perdas individuais dos especialistas. Isso estimula os especialistas a melhorarem suas previsões justamente nas situações em que eles são importantes.
Dropout no gating transforma o treinamento em um desafio episódico. Em cada batch, o conjunto ativo de especialistas muda ligeiramente, e o modelo aprende a não depender continuamente de um único especialista favorecido pelo acaso. Durante o treinamento, o Dropout fica ativado; na inferência, ele é desativado, o que permite usar o conhecimento de todos os especialistas.
A nova classe CNeuronGraphons serve como um wrapper de domínio para nossa implementação de um ensemble flexível de gráfons. Ela encapsula o estado do gate, os embeddings dos dados de entrada, os parâmetros dos especialistas e o próprio conjunto de gráfons: tudo o que é necessário para gerar, a cada etapa, um gráfon ponderado a partir de múltiplas opiniões dos especialistas.
class CNeuronGraphons : public CNeuronBaseOCL { protected: CLayer acProbability; CLayer acDataEmb; CParams cExpertsEmb; CNeuronBaseOCL cGraphs; //--- virtual bool feedForward(CNeuronBaseOCL *NeuronOCL) override; virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) override; virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL) override; public: CNeuronGraphons(void) {}; ~CNeuronGraphons(void) {}; virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint units, uint window, uint emb_dimension, uint experts, float dropout, ENUM_OPTIMIZATION optimization_type, uint batch); //--- virtual int Type(void) override const { return defNeuronGraphons; } //--- methods for working with files virtual bool Save(int const file_handle) override; virtual bool Load(int const file_handle) override; //--- virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau) override; virtual void SetOpenCL(COpenCLMy *obj) override; virtual void SetActivationFunction(ENUM_ACTIVATION value) override { }; virtual void TrainMode(bool flag) override; };
Dentro da classe, são declarados quatro objetos internos, cada um com uma função específica. Detalharemos esses pontos durante a implementação dos métodos. Todos eles são declarados de forma estática, o que significa que o ciclo de vida desses componentes é gerenciado pela própria classe. Com isso, o construtor e o destrutor podem permanecer vazios. Não é necessária nenhuma inicialização ou limpeza adicional a cada instanciação do objeto. Essa solução simplifica a gestão de recursos, reduz o overhead em múltiplas instanciações e torna o comportamento da classe mais previsível.
A inicialização por meio de Init oferece controle total sobre a configuração: número de saídas, índice do neurônio na rede, ponteiro para o contexto OpenCL, número de units internos e janela de agregação, tamanho do embedding, número de especialistas, taxa de dropout, tipo de otimização e tamanho do batch. Isso permite, por um lado, definir uma implementação MLP leve do gate para testes rápidos e, por outro, alternar, se necessário, para a via OpenCL de alto desempenho. O método TrainMode(bool) controla o modo de operação: no treinamento, o inverted Dropout é ativado e podem ser usados recursos estocásticos adicionais; na inferência, a desativação do Dropout torna o comportamento determinístico, o que é importante para a produção e para decisões de trading estáveis.
Toda a arquitetura do objeto e a configuração dos componentes internos ficam concentradas no método Init, que atua como orquestrador de toda a montagem. Ele inicializa a hierarquia básica de neurônios, vincula os componentes internos ao contexto OpenCL e verifica cuidadosamente cada etapa para que, ao final, o módulo esteja pronto para operar.
bool CNeuronGraphons::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint units, uint window, uint emb_dimension, uint experts, float dropout, ENUM_OPTIMIZATION optimization_type, uint batch) { if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, units * units, optimization_type, batch)) return false; activation = None;
Primeiro, é chamado o método homônimo da classe base. Essa é a inicialização preliminar obrigatória do objeto base. Se ela retornar false, significa que a infraestrutura básica não está pronta e que não faz sentido prosseguir com a montagem; por isso, o método encerra imediatamente sua execução com o resultado false. após a execução bem-sucedida, desativamos explicitamente a função de ativação, pois as funções de ativação específicas dos subcomponentes serão definidas individualmente mais adiante.
Na etapa seguinte, o buffer cGraphs é inicializado. Aqui, preparamos o contêiner para armazenar os gráfons individuais dos nossos especialistas. Depois disso definimos explicitamente a função de ativação SIGMOID, para que suas saídas operem no intervalo necessário.
int index = 0; if(!cGraphs.Init(0, index, OpenCL, Neurons()*experts, optimization, iBatch)) return false; cGraphs.SetActivationFunction(SIGMOID);
Em seguida, declaramos um conjunto de variáveis locais para armazenar temporariamente ponteiros para os subcomponentes que serão usados durante a montagem passo a passo do modelo.
CNeuronBaseOCL *neuron = NULL; CNeuronConvOCL *conv = NULL; CNeuronTransposeOCL *transp = NULL; CNeuronDropoutOCL *dout = NULL; CNeuronSoftMaxOCL *softmax = NULL;
Passamos à montagem do modelo de geração das probabilidades de uso dos especialistas. Primeiro, limpamos o array dinâmico correspondente e o associamos ao contexto OpenCL.
//--- Probability acProbability.Clear(); acProbability.SetOpenCL(OpenCL); index++; conv = new CNeuronConvOCL(); if(!conv || !conv.Init(experts, index, OpenCL, window, window, experts, units, 1, optimization, iBatch) || !acProbability.Add(conv)) { DeleteObj(conv); return false; } conv.SetActivationFunction(SoftPlus);
Em seguida, iniciamos a montagem passo a passo. Criamos primeiro uma camada convolucional com não linearidade SoftPlus, o que produz uma transformação suave e monotonicamente crescente dos logits antes da próxima camada. Depois dela, criamos uma camada totalmente conectada que retorna um número de valores igual a experts: esse é justamente o vetor de logits antes do Dropout.
index++; neuron = new CNeuronBaseOCL(); if(!neuron || !neuron.Init(0, index, OpenCL, experts, optimization, iBatch) || !acProbability.Add(neuron)) { DeleteObj(neuron); return false; }
Como antes, em caso de erro de alocação ou inicialização, liberamos corretamente o objeto e encerramos a inicialização com false.
Em seguida, criamos a camada Dropout. É justamente esse objeto que implementa a desativação aleatória de especialistas mencionada anteriormente.
index++; dout = new CNeuronDropoutOCL(); if(!dout || !dout.Init(0, index, OpenCL, experts, dropout, optimization, iBatch) || !acProbability.Add(dout)) { DeleteObj(dout); return false; }
O próximo passo é criar a camada SoftMax, que converte os logits obtidos anteriormente em um vetor de um vetor de pesos de relevância dos especialistas.
index++; softmax = new CNeuronSoftMaxOCL(); if(!softmax || !softmax.Init(0, index, OpenCL, experts, optimization, iBatch) || !acProbability.Add(softmax)) { DeleteObj(softmax); return false; } softmax.SetHeads(1);
Em seguida, iniciamos a preparação do bloco de embeddings dos dados de entrada acDataEmb. Limpamos o bloco, o associamos ao OpenCL e, de modo análogo, iniciamos a montagem a partir de camadas convolucionais. Aqui, usamos uma pequena MLP composta por duas camadas convolucionais sequenciais, com não linearidade SoftPlus entre elas.
//--- Data Embedding acDataEmb.Clear(); acDataEmb.SetOpenCL(OpenCL); index++; conv = new CNeuronConvOCL(); if(!conv || !conv.Init(0, index, OpenCL, window, window, 2 * emb_dimension, units, 1, optimization, iBatch) || !acDataEmb.Add(conv)) { DeleteObj(conv); return false; } conv.SetActivationFunction(SoftPlus); index++; conv = new CNeuronConvOCL(); if(!conv || !conv.Init(0, index, OpenCL, 2 * emb_dimension, 2 * emb_dimension, emb_dimension, units, 1, optimization, iBatch) || !acDataEmb.Add(conv)) { DeleteObj(conv); return false; } conv.SetActivationFunction(None);
Na saída dessa MLP, esperamos obter os embeddings de cada passo temporal da sequência multimodal analisada. No entanto, para gerar os gráfons, precisaremos de uma cópia transposta dessa representação. Por isso, logo em seguida, adicionamos uma camada de transposição dos dados.
index++; transp = new CNeuronTransposeOCL(); if(!transp || !transp.Init(0, index, OpenCL, units, emb_dimension, optimization, iBatch) || !acDataEmb.Add(transp)) { DeleteObj(transp); return false; } transp.SetActivationFunction((ENUM_ACTIVATION)conv.Activation());
Depois disso, resta apenas inicializar o objeto gerador dos embeddings dos nossos especialistas, cExpertsEmb. Aqui preparamos o espaço para suas representações individuais.
index++; if(!cExpertsEmb.Init(0, index, OpenCL, units * emb_dimension * experts, optimization, iBatch)) return false; //--- return true; }
Por fim, se não houver erros, o método retorna true, sinalizando que o objeto foi totalmente inicializado e está pronto para o treinamento.
No comportamento do método, vemos uma lógica bem definida: primeiro é preparado o contêiner de gráfons; depois, é montado o pipeline de geração de probabilidades; em seguida, é gerado o embedding dos dados de entrada; e, por fim, alocamos o espaço de parâmetros dos especialistas. Essa sequência garante uma montagem lógica, conveniente para depuração e para a integração posterior com OpenCL.
O método feedForward implementa a propagação para frente como uma fábrica de sinais cuidadosamente definida. Primeiro, salvamos o ponteiro para a fonte atual do sinal em uma variável local e declaramos outra variável para armazenar temporariamente a referência à camada em processamento.
bool CNeuronGraphons::feedForward(CNeuronBaseOCL *NeuronOCL) { CNeuronBaseOCL* prev = NeuronOCL; CNeuronBaseOCL* current = NULL;
Em seguida, percorremos o bloco de previsão das probabilidades de uso dos especialistas. Percorremos todos os subcomponentes em um laço responsáveis pela geração dos logits.
//--- Probability for(int i = 0; i < acProbability.Total(); i++) { current = acProbability[i]; if(!current || !current.FeedForward(prev)) return false; prev = current; }
A cada iteração, obtemos o próximo componente e chamamos sua propagação para frente. Se o componente estiver ausente ou seu FeedForward retornar false, encerramos imediatamente a execução do método com o resultado false. Essa é uma política fail-fast rigorosa e confiável, que protege contra uma montagem incorreta do pipeline.
Após a execução bem-sucedida da camada, deslocamos o ponteiro para o objeto dos dados de entrada. A próxima camada usará como entrada a saída da camada atual. Como resultado desse laço, obtemos o vetor de probabilidades normalizadas.
Em seguida, reinicializamos o ponteiro para a fonte dos dados de entrada e percorremos o bloco acDataEmb seguindo o mesmo padrão. Essa segunda passagem linear gera os embeddings dos dados de entrada.
//--- Data Embedding prev = NeuronOCL; for(int i = 0; i < acDataEmb.Total(); i++) { current = acDataEmb[i]; if(!current || !current.FeedForward(prev)) return false; prev = current; }
Em seguida, há uma pequena ramificação importante: se estivermos em modo de treinamento, chamamos o método de geração dos embeddings dos especialistas. Isso significa que os parâmetros ou as representações dos especialistas são atualizados apenas na execução de treinamento. No modo de inferência, esperamos que cExpertsEmb já contenha os pesos prontos e omitimos essa etapa, economizando tempo.
//--- Experts if(bTrain) if(!cExpertsEmb.FeedForward()) return false;
Em seguida, começa a álgebra central. Calculamos as dimensões auxiliares da arquitetura do objeto.
//--- Graphs uint units = (uint)MathSqrt((double)Neurons()); uint emb_dim = acDataEmb[-1].Neurons() / units; uint experts = cExpertsEmb.Neurons() / acDataEmb[-1].Neurons();
Esses cálculos simples garantem a compatibilidade das dimensões antes das multiplicações matriciais. A primeira multiplicação matricial gera, para cada especialista, sua própria matriz do grafo. O buffer resultante cGraphs armazena ordenadamente a sequência dessas matrizes para todos os especialistas.
if(!MatMul(cExpertsEmb.getOutput(), current.getOutput(), cGraphs.getOutput(), units, emb_dim, units, experts, false)) return false; if(cGraphs.Activation() != None) if(!Activation(cGraphs.getOutput(), cGraphs.getOutput(), cGraphs.Activation())) return false;
Após obter as matrizes brutas dos gráfons, aplicamos a não linearidade de verificação. Nessa etapa, a função de ativação escolhida é aplicada a todos os elementos do buffer de saída. Essa é uma etapa importante para colocar os valores no intervalo necessário e adicionar a não linearidade desejada.
A redução final transforma o conjunto de matrizes dos especialistas e o vetor de probabilidades em um único tensor final do grafo ponderado. Em outras palavras, usamos o vetor de pesos normalizados da última camada acProbability e agregamos as matrizes de todos os especialistas em um único resultado ponderado.
//--- Result if(!MatMul(acProbability[-1].getOutput(), cGraphs.getOutput(), Output, 1, experts, units * units, 1, false)) return false; //--- return true; }
Se todas as etapas forem executadas com sucesso, o método retorna true, confirmando o término correto da propagação para frente.
O algoritmo dos métodos de propagação reversa segue a mesma lógica da propagação para frente, mas avança na direção inversa. Os sinais do erro passam por todas as camadas na ordem inversa, os gradientes são cuidadosamente acumulados e transmitidos das saídas para as entradas, garantindo o treinamento correto de todos os componentes. Como a estrutura é totalmente espelhada em relação ao método feedForward e todas as etapas podem ser facilmente acompanhadas pela sequência já analisada, não há necessidade de detalhar agora cada uma delas. Para uma compreensão completa e para o trabalho prático com todos os métodos da classe, todo o código, incluindo a propagação reversa, é apresentado no anexo.
Hoje trabalhamos bem, e chegou a hora de fazer uma breve pausa, deixar as informações assentarem e se organizarem na cabeça. No próximo artigo, continuaremos o trabalho iniciado e examinaremos em detalhes a aplicação prática dos gráfons.
Conclusão
Neste artigo, examinamos em detalhes os aspectos teóricos do framework ST-Expert, que combina os princípios de gating flexível, aprendizado coletivo e agregação adaptativa. Vimos como a combinação dos blocos de geração de probabilidades, dos embeddings dos dados de entrada e das representações dos especialistas permite criar modelos robustos diante do ruído e da incerteza.
Na parte prática, foi apresentada a arquitetura da classe CNeuronGraphons, que permite implementar a criação e o treinamento dos gráfons. Os métodos descritos formam uma base sólida para o uso prático nas próximas etapas.
Referências
Programas usados no artigo
| # | Nome | Tipo | Descrição |
|---|---|---|---|
| 1 | Study.mq5 | Expert Advisor | EA de treinamento offline de modelos |
| 2 | StudyOnline.mq5 | Expert Advisor | EA de treinamento online de modelos |
| 3 | Test.mq5 | Expert Advisor | EA para teste do modelo |
| 4 | Trajectory.mqh | Biblioteca de classes | Estrutura de descrição do estado do sistema e da arquitetura dos modelos |
| 5 | NeuroNet.mqh | Biblioteca de classes | Biblioteca de classes para criação de rede neural |
| 6 | NeuroNet.cl | Biblioteca | Biblioteca de código do programa OpenCL |
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/19595
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.
Desenvolvendo uma estratégia de pullback: Fundamentos
Robô de trading multithreaded com machine learning: da concepção à concretização
Está chegando o novo MetaTrader 5 e MQL5
Redes neurais em trading: uma visão unificada do espaço e do tempo (final)
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso