Русский
preview
Redes neurais em trading: Treinamento de modelos spiking profundos (SEW-ResNet)

Redes neurais em trading: Treinamento de modelos spiking profundos (SEW-ResNet)

MetaTrader 5Sistemas de negociação |
29 0
Dmitriy Gizlyk
Dmitriy Gizlyk

Introdução

Os mercados financeiros são uma arena em que os interesses de milhões de participantes se confrontam, e cada decisão pode resultar em lucro ou prejuízo. Nessas condições, a capacidade de extrair rapidamente informações de fluxos de dados complexos torna-se um fator decisivo para o sucesso. Nas últimas décadas, as redes neurais artificiais assumiram uma posição de destaque nas tarefas de processamento de informações, demonstrando sua eficácia nas mais diversas áreas, desde visão computacional até tradução automática de textos. Esse sucesso se deve ao aprendizado profundo: quanto maior o número de camadas na arquitetura do modelo, mais complexas e multifacetadas são as representações que ele consegue identificar e descrever. No trading, esse princípio se manifesta de forma particularmente evidente. Modelos profundos são capazes de distinguir os padrões mais sutis no comportamento dos preços e separar o ruído de curto prazo das tendências persistentes.

No entanto, o desenvolvimento dos modelos neurais deparou-se com um paradoxo. O aumento da profundidade da rede, que deveria trazer apenas benefícios, em determinado momento passou a produzir um efeito inesperado. Em vez de aumentar, a precisão estagnava e, em alguns casos, até se deteriorava. A situação lembrava um mecanismo sobrecarregado, no qual novos componentes, em vez de facilitar o funcionamento, introduziam falhas. A solução surgiu com o conceito de conexões residuais: o modelo aprende não apenas a extrair novos atributos, mas também a corrigir os já identificados, acrescentando a eles pequenos ajustes. Essa ideia foi incorporada à arquitetura ResNet, que representou um verdadeiro avanço ao permitir a construção de modelos muito profundos sem perda de qualidade.

Paralelamente às arquiteturas clássicas, porém, surgiu uma linha de pesquisa que vem atraindo cada vez mais a atenção de pesquisadores e profissionais: as redes neurais spiking. Sua principal característica é apresentar um funcionamento mais próximo ao do cérebro. Diferentemente dos modelos convencionais, nelas a informação é transmitida por impulsos individuais, ou seja, por eventos. Para os mercados financeiros, essa abordagem é especialmente valiosa, pois também nesse domínio predomina uma lógica orientada a eventos: a divulgação de um relatório, uma declaração de um órgão regulador ou um aumento repentino da atividade são eventos importantes aos quais o sistema deve reagir imediatamente. Além disso, os modelos spiking prometem maior eficiência energética e a capacidade de processar fluxos de dados em tempo real.

Apesar da impressionante plausibilidade biológica e das novas possibilidades que oferecem, os modelos spiking ainda ficavam atrás das redes neurais clássicas em diversas tarefas práticas. Isso se tornava particularmente evidente em conjuntos de dados complexos, nos quais eram necessários alta precisão e uma análise aprofundada. Em determinado momento, ficou claro que o caminho para novos avanços passava pela incorporação das ideias do aprendizado profundo à arquitetura dos modelos spiking. Surgiram, assim, as primeiras tentativas de adaptar a ResNet ao formato spiking. O conceito de Spiking ResNet parecia promissor: transferir os blocos residuais da arquitetura clássica e substituir as funções de ativação por neurônios spiking. Essa abordagem permitia aplicar o princípio já consolidado de profundidade e conexões residuais a um novo contexto orientado a eventos.

Os resultados foram mistos. Por um lado, os modelos convertidos a partir de redes neurais clássicas demonstravam excelente precisão e estabeleciam um patamar elevado para outras soluções. Por outro, o treinamento direto da Spiking ResNet revelou uma série de problemas: degradação da qualidade à medida que a profundidade aumentava, problemas de desaparecimento e explosão dos gradientes e dificuldades para implementar corretamente o mapeamento de identidade. Tudo isso mantinha sem solução o problema de construir modelos spiking realmente profundos e estáveis.

Nesse contexto, o surgimento do framework SEW-ResNet, apresentado no trabalho "Deep Residual Learning in Spiking Neural Networks", representou um avanço significativo. A ideia central consistia em reformular o mecanismo de aprendizado residual para adaptá-lo às arquiteturas spiking. Os autores do framework propuseram a abordagem Spike-Element-Wise, que permite implementar naturalmente o mapeamento de identidade e, ao mesmo tempo, evitar os principais problemas relacionados aos gradientes. Os testes práticos confirmaram a validade do conceito. O SEW-ResNet demonstrou não apenas maior precisão, mas também capacidade de escalar à medida que a profundidade do modelo aumenta, algo que até então não havia sido alcançado. Além disso, pela primeira vez foi possível construir uma rede spiking com mais de 100 camadas, mantendo a estabilidade do treinamento e superando, em desempenho, muitas das soluções existentes.

Ao trazer essa discussão para o contexto financeiro, fica claro que avanços desse tipo abrem perspectivas inteiramente novas. Modelos profundos treinados com dados em forma de impulsos podem analisar os eventos do mercado tal como eles realmente ocorrem. Não como séries numéricas agregadas por médias, mas como uma sequência de sinais discretos, cada um com seu próprio significado. Essa visão está mais próxima da natureza do mercado, em que os preços raramente se movem de forma suave e uniforme, reagindo com muito mais frequência a picos de liquidez, notícias ou ao sentimento dos participantes. Tecnologias como o SEW-ResNet prometem permitir que os algoritmos identifiquem essas mudanças no exato momento em que surgem.

Assim, o problema de construir modelos spiking profundos e estáveis vai muito além do interesse acadêmico. No setor financeiro, em que a velocidade de reação e a capacidade de processar dados complexos determinam a vantagem competitiva, a adoção de soluções desse tipo pode se tornar um passo decisivo para o desenvolvimento de novas estratégias e ferramentas. Hoje estamos no limiar da integração das ideias do SEW-ResNet em sistemas algorítmicos práticos. Ao longo deste artigo, analisaremos esse caminho sob a perspectiva da implementação das abordagens propostas com MQL5. Isso nos permitirá compreender melhor a própria arquitetura e avaliar seu potencial prático em condições reais de mercado.


Algoritmo SEW-ResNet

Qualquer framework de redes neurais spiking se baseia em uma ideia simples, mas fundamental: a unidade computacional básica é o neurônio spiking. Nas redes neurais artificiais clássicas, esse elemento pode ser descrito como uma soma generalizada de produtos, na qual os sinais percorrem conexões com pesos e, em seguida, são transformados por uma função de ativação. Em um modelo spiking, porém, tudo é muito mais dinâmico e mais próximo da biologia. A informação não flui de forma contínua, mas é transmitida por eventos individuais: impulsos, ou spikes. Cada impulso se assemelha a uma descarga elétrica que, no cérebro real, é transmitida de um neurônio para outro.

Para formalizar esse processo e torná-lo adequado ao processamento computacional, utiliza-se um modelo unificado. Ele descreve a dinâmica temporal do neurônio, dividindo-a em uma sequência de passos discretos. Em cada passo, o sistema executa três tarefas principais:

  1. Calcular o novo potencial de membrana.
  2. Determinar se ocorreu um spike.
  3. Redefinir o potencial caso o neurônio tenha disparado.
Essas três etapas são descritas por um sistema de equações que serve de base para praticamente todos os modelos spiking modernos.

A primeira equação descreve a evolução do potencial.

Aqui, Vt-1 representa o potencial de membrana no passo anterior, enquanto Xt corresponde à corrente de entrada recebida naquele instante. A função f(•) determina como o potencial é atualizado e varia de acordo com o tipo de neurônio escolhido. Na prática, ela representa a dinâmica interna do neurônio, descrevendo como ele responde ao sinal de entrada.

A etapa seguinte consiste em verificar se o potencial de membrana ultrapassou o limiar.

Se o potencial atingir o limiar Vth, o neurônio dispara e gera um impulso. A função de Heaviside Θ(•) atua aqui como uma chave binária, retornando 1 quando o limiar é ultrapassado e 0 caso contrário. Em outras palavras, ou o evento ocorre, ou não ocorre.

Em seguida, entra em ação o mecanismo de redefinição do potencial.

Se houver um spike, o potencial retorna a um nível fixo VReset. Esse comportamento lembra a descarga de uma bateria: depois de liberar energia, o sistema precisa retornar ao estado inicial para se preparar para o próximo sinal. Se nenhum impulso for gerado, o potencial mantém seu valor atual e continua se acumulando.

Tudo isso forma um esquema coerente, capaz de reproduzir a dinâmica dos neurônios biológicos sem deixar de ser suficientemente simples para o processamento computacional. Além disso, a flexibilidade do modelo é proporcionada pela função f(•). No modelo mais simples, Integrate-and-Fire, ela assume a seguinte forma:

Ou seja, o potencial simplesmente aumenta pelo valor da corrente de entrada. Já no modelo mais realista Leaky Integrate-and-Fire, leva-se em conta o decaimento da carga acumulada.

O parâmetro τ determina a velocidade desse decaimento, refletindo o fato de que o neurônio não consegue armazenar energia indefinidamente: se nenhum impulso for gerado, ele perde gradualmente a carga acumulada.

Assim, o pesquisador dispõe de uma estrutura universal na qual os processos básicos, isto é, a geração do spike e a redefinição do potencial, permanecem os mesmos para todos os modelos, enquanto os ajustes mais específicos são definidos pela escolha da função f(•).

No entanto, surge aqui uma dificuldade importante relacionada ao treinamento. A função degrau clássica, responsável por determinar se um spike será gerado, não é diferenciável. Isso significa que o método padrão de retropropagação do erro, no qual se baseia o aprendizado profundo, não pode ser aplicado nesse caso. À primeira vista, trata-se de um obstáculo sério. Se não for possível calcular o gradiente, também se torna impossível ajustar os pesos do modelo.

A solução surgiu com o chamado método dos gradientes substitutos. A ideia é usar a função degrau real durante a propagação para frente, pois é justamente ela que representa a natureza dos spikes. Porém, ao calcular as derivadas durante a propagação reversa, substituímos essa função por uma aproximação suave, a função σ(), que apresenta comportamento semelhante, mas possui um gradiente analítico conveniente. Esse uso combinado de duas funções permite treinar modelos spiking de maneira semelhante às redes neurais profundas convencionais, preservando ao mesmo tempo a natureza orientada a eventos dos cálculos.

Essa combinação, formada pelo modelo unificado de neurônios e pelo método dos gradientes substitutos, estabelece uma base sólida para a construção de arquiteturas complexas. É justamente aqui que começa a história do SEW-ResNet.

Quando falamos de arquiteturas profundas, foi o bloco residual que serviu de base para o surgimento da ResNet e permitiu superar o principal problema das redes muito profundas: a degradação da qualidade. A ideia parecia simples, mas era revolucionária. Se não conseguimos treinar todas as novas camadas para que reproduzam exatamente o sinal de entrada, podemos fornecer a elas um caminho alternativo, uma conexão direta pela qual a informação possa passar sem distorções. Esse é o princípio do mapeamento de identidade. Ele garante que o aumento da profundidade do modelo não prejudique a qualidade. No pior dos casos, as novas camadas não alteram negativamente o resultado; no melhor, enriquecem a representação dos dados.

Na ResNet clássica, esse bloco é composto por duas camadas convolucionais consecutivas, normalização e uma função de ativação ReLU. Se representarmos a entrada do bloco por Xl e a saída por Yl, a fórmula geral assume a seguinte forma:

Aqui, Fl(•) representa o termo residual acrescentado ao sinal original. Se ele for igual a zero, o resultado será simplesmente Yl = ReLU(Xl). Como a saída após a ReLU é não negativa, para a maioria dos valores obtemos, na prática, um mapeamento de identidade: a entrada é igual à saída. Esse era o segredo do sucesso da ResNet.

A tentativa de transferir essa estrutura para o universo spiking parecia bastante natural. Nos trabalhos sobre Spiking ResNet, o bloco mantém a mesma estrutura, mas a ReLU é substituída por um neurônio spiking.

Aqui, Sl e Ol representam, respectivamente, a entrada e a saída do bloco no passo temporal t, enquanto SN representa o disparo do neurônio spiking.

É nesse ponto que surge uma diferença fundamental. Nas redes clássicas, a ReLU atua como um filtro contínuo, deixando passar os valores positivos sem modificá-los. Por isso, implementar um mapeamento de identidade é relativamente fácil. No caso de um neurônio spiking, porém, as condições são muito mais rígidas. Para garantir a igualdade SN(Slt) = Slt o último neurônio do bloco precisa disparar a cada spike de entrada e permanecer inativo quando nenhum spike for recebido. No modelo IF mais simples, isso ainda pode ser implementado: basta escolher o limiar de ativação e as condições iniciais de modo que uma entrada igual a 1 sempre gere um impulso, enquanto uma entrada igual a 0 nunca o faça. Mas, assim que adotamos um modelo mais complexo, como o LIF com constante de tempo treinável τ, a situação se complica. O potencial passa a ser atualizado em incrementos fracionários dependentes de τ, e encontrar um limiar universal que funcione em todos os casos torna-se praticamente impossível.

Assim, os blocos residuais da Spiking ResNet acabam apresentando limitações. Eles não são adequados a todos os modelos de neurônios, o que compromete o princípio de universalidade já em sua base.

Mas esse não é o único problema. Mesmo quando conseguimos configurar os blocos para implementar o mapeamento de identidade, surge uma ameaça ainda mais séria: o desaparecimento e a explosão dos gradientes. Em uma rede profunda, a propagação do gradiente por uma sequência de blocos spiking reduz-se ao produto de diversos fatores associados à derivada da função de ativação em degrau. Como essa função é discreta, nas aproximações usadas para calcular os gradientes substitutos, sua derivada quase sempre é muito pequena, levando ao desaparecimento do gradiente, ou produz um crescimento instável, resultando em sua explosão. Consequentemente, à medida que o número de camadas aumenta, torna-se praticamente impossível treinar a rede. Os sinais de erro deixam de se propagar pelas camadas mais profundas, os pesos não são ajustados, e os gradientes tendem a zero ou crescem sem limite.

Esse efeito corresponde à conhecida degradação, mas nas redes spiking ele se manifesta de forma ainda mais acentuada do que nas arquiteturas clássicas. Foi justamente por isso que a Spiking ResNet, em sua forma original, não conseguiu demonstrar que o aumento da profundidade efetivamente traz benefícios. Em muitos casos, inclusive, um modelo spiking profundo apresentava desempenho inferior ao de uma versão mais rasa.

Ainda assim, vale observar que esses blocos encontraram uma aplicação importante na conversão de modelos clássicos para o formato spiking. Nesse caso, o objetivo é diferente: adaptar um modelo já treinado ao processamento orientado a eventos. Os blocos spiking podem então ser combinados com normalização adicional e conseguem reproduzir com bastante eficiência as características de frequência das ativações ReLU do modelo original.

É nesse ponto que entra em cena o bloco Spike-Element-Wise, que desempenha essencialmente o mesmo papel que o bloco residual clássico desempenhou nas redes neurais profundas: permitir a construção de SNNs mais profundas sem perda de estabilidade.

O que torna o bloco SEW tão especial? Antes de tudo, sua simplicidade. Ele se baseia em uma operação elemento a elemento g, que combina dois fluxos de informação: a saída da transformação spiking e o sinal original. Graças à natureza binária dos spikes, essa estrutura funciona como uma chave ideal: com a configuração adequada, o bloco torna-se completamente transparente, implementando o mapeamento de identidade. Não se trata de um ajuste delicado, dependente de um modelo específico de neurônio ou dos parâmetros da dinâmica de membrana, mas de uma abordagem universal que funciona em qualquer configuração. É justamente aí que reside a força do SEW: sua universalidade.

Imagine uma longa sequência de blocos SEW. Nas arquiteturas clássicas semelhantes à ResNet, a partir de determinada profundidade começamos a perder o sinal: os gradientes ficam cada vez menores e a rede deixa de aprender. Ou ocorre o contrário: nos blocos RBA, os sinais crescem de forma descontrolada, levando à explosão dos gradientes. No SEW, esse cenário não ocorre. Sua saída permanece sempre limitada, os gradientes se mantêm iguais a um e o treinamento pode permanecer estável mesmo em redes com centenas de blocos. Em outras palavras, o SEW nos devolve a mesma vantagem que a ResNet proporcionou ao universo das redes neurais clássicas.

Também é interessante observar como o problema do downsampling é resolvido. Nas ResNets clássicas, quando a dimensionalidade é alterada, o shortcut é implementado por meio de convoluções sem ativação. No bloco SEW, adiciona-se um neurônio spiking ao shortcut, criando uma estrutura mais orgânica e neurobiologicamente plausível. Como resultado, os blocos de downsampling alteram a dimensionalidade e continuam operando em modo spiking, preservando a plausibilidade biológica do modelo.

Em uma perspectiva mais ampla, o bloco SEW abre caminho para uma classe inteiramente nova de aplicações. Antes dele, as arquiteturas SNN eram, em grande medida, objeto de interesse acadêmico. Era difícil demais manter o equilíbrio entre profundidade e capacidade de treinamento. Com o surgimento do SEW, elas passam a se apresentar como concorrentes sérias das redes neurais clássicas em tarefas reais. E as vantagens das SNNs são evidentes: elas são energeticamente eficientes, assíncronas, adaptam-se muito bem a chips neuromórficos e permitem construir cálculos mais próximos da dinâmica real do cérebro.

Ao passarmos da descrição teórica para os experimentos práticos, a diferença entre a Spiking ResNet e a SEW-ResNet torna-se evidente. Em tarefas estáticas, como a classificação de imagens dos conjuntos CIFAR ou ImageNet, as duas arquiteturas apresentam resultados semelhantes. No entanto, basta aumentar a profundidade e o número de camadas para que a Spiking ResNet comece a apresentar dificuldades. Os gradientes desaparecem, o erro aumenta e, em vez de melhoria, ocorre degradação da qualidade. É o cenário clássico em que a profundidade deixa de ser uma vantagem e passa a se tornar um problema.

Nessas mesmas condições, a SEW-ResNet apresenta um comportamento diametralmente oposto. Quanto mais profundo o modelo, mais estável é seu comportamento e maior tende a ser a precisão final. Isso é especialmente importante em tarefas cujo sucesso depende da capacidade do modelo de capturar dependências temporais de longo alcance. Nos mercados financeiros, é exatamente esse o tipo de situação que encontramos: picos raros e abruptos de atividade, longos períodos de baixa movimentação, mudanças de regime do mercado e dependências temporais extensas que precisam ser mantidas na memória.

Para compreender o valor da SEW-ResNet no trading, podemos traçar uma analogia com o próprio mercado. Nele também existem sinais em forma de spikes: notícias inesperadas, movimentos bruscos das cotações e aumentos repentinos de liquidez. Os modelos clássicos de redes neurais, que trabalham com ativações médias, lembram um trader que vê apenas um gráfico suavizado e deixa escapar os impulsos mais abruptos. As arquiteturas spiking, especialmente a SEW-ResNet, permitem perceber o mercado em sua forma natural e orientada a eventos, em que o mais importante não é uma tendência suave, mas o momento exato da mudança abrupta e o contexto em que ela ocorre.

Em testes comparativos realizados em conjuntos que simulam fluxos de eventos, a SEW-ResNet demonstrou uma vantagem significativa tanto em precisão quanto em velocidade de convergência. Além disso, foi a primeira abordagem a permitir o treinamento de modelos SNN com mais de 100 camadas sem degradação catastrófica.

Na aplicação prática a dados financeiros, a SEW-ResNet abre novas possibilidades. Ela permite construir modelos capazes de identificar padrões locais nas cotações e relacioná-los a dependências históricas de longo prazo. Por exemplo, o modelo pode detectar um breve pico de atividade em resposta a uma notícia econômica e, ao mesmo tempo, considerar que picos semelhantes no passado levaram a uma tendência persistente de médio prazo. Isso se torna possível justamente graças à profundidade, que agora não prejudica o treinamento, mas contribui para torná-lo mais eficaz.

Além disso, a alta eficiência energética e a natureza orientada a eventos das SNNs tornam a SEW-ResNet adequada para sistemas de baixa latência. Em condições de trading de alta frequência ou análise algorítmica, em que cada milissegundo conta, a capacidade do modelo de processar rapidamente eventos spiking torna-se uma vantagem crítica.

A visualização do framework elaborada pelos autores é apresentada abaixo.

!


Implementação com MQL5

Depois de analisarmos em detalhes os fundamentos teóricos e as características arquiteturais do framework SEW-ResNet, chegamos naturalmente à etapa de implementação prática. Aqui, é importante avançar do simples para o complexo, partindo da base para os componentes de nível superior. O primeiro elemento dessa sequência é a implementação da função básica de um neurônio spiking.

À primeira vista, pode parecer bastante natural implementar a geração de spikes como uma função separada, da mesma forma que as funções de ativação clássicas já estão implementadas em nossa biblioteca. No entanto, os neurônios spiking impõem requisitos fundamentalmente diferentes. Ao contrário das ativações tradicionais, que calculam imediatamente o valor de saída com base no sinal recebido, o neurônio spiking possui uma dinâmica temporal. Ele não apenas reage à entrada, mas também acumula informações e potencial de membrana e, ao atingir o limiar, gera um spike, ou seja, um impulso discreto que carrega informação.

Essa dinâmica temporal não pode ser reduzida a uma simples função estática. Para modelá-la corretamente, é necessária uma memória própria, na forma de buffers que acumulam o potencial e que, em essência, lembram os estados ocultos dos modelos recorrentes. É justamente aí que está o principal desafio. Usar a ativação spiking como uma simples função exigiria automaticamente modificar todos os objetos de camada já criados. Na prática, isso comprometeria a compatibilidade arquitetural da biblioteca e destruiria a modularidade já estabelecida.

Por isso, adotamos uma solução diferente e mais madura: a geração de spikes será implementada como um objeto de camada neural separado. À primeira vista, essa decisão pode parecer excessiva, mas, na prática, é estratégica. O objeto da camada pode ser integrado a qualquer arquitetura existente sem interferir no funcionamento dos demais componentes. Ele se torna um bloco independente, que pode ser combinado com outras camadas à medida que aumentamos a complexidade do modelo.

Mas, antes de passarmos diretamente ao código, vale a pena destacar brevemente os princípios fundamentais da nossa implementação. Na descrição teórica do framework SEW-ResNet, os autores estabeleceram as ideias básicas, criando uma base que abre amplo espaço para experimentação, mas sem definir soluções específicas de engenharia. São justamente essas soluções que nos permitem construir modelos spiking profundos efetivamente treináveis.

O primeiro princípio está relacionado ao acúmulo do potencial de membrana do neurônio. Para isso, incorporamos um mecanismo de atualização de estado por gate inspirado nos modelos recorrentes. Agora, cada neurônio spiking possui seu próprio gate, que controla a rapidez com que o potencial de membrana reage aos sinais recebidos. E, o mais importante, esse gate é implementado como um parâmetro treinável, independente dos dados de entrada.

O significado prático dessa abordagem pode ser facilmente entendido por meio de uma analogia com um trader no mercado. Cada neurônio aprende a desenvolver sua própria estratégia de reação aos eventos. Se o sinal for ruidoso e instável, o neurônio se comporta de forma conservadora, acumula informações e reage apenas a mudanças realmente significativas. Se, por outro lado, o sinal for limpo e previsível, o neurônio pode gerar imediatamente um spike, registrando um impulso relevante. Como resultado, cada elemento adquire um comportamento próprio, enquanto o modelo como um todo ganha a flexibilidade necessária para lidar com diferentes tipos de sequências de entrada.

Essa abordagem é especialmente adequada aos mercados financeiros, em que os dados frequentemente alternam entre períodos de baixa atividade e picos abruptos de movimentação. Alguns eventos exigem uma resposta cautelosa, enquanto outros requerem uma reação rápida e decisiva. A possibilidade de ajustar cada neurônio às características específicas do sinal de entrada permite que o modelo se adapte a essas condições, preservando a precisão e a estabilidade do treinamento.

Além disso, adotaremos do framework SpikingBrain um mecanismo eficiente de aprendizado adaptativo dos valores de limiar, implementado no kernel FloatToSpike. Esse mecanismo permite que os neurônios ajustem de forma flexível seu limiar de ativação às estatísticas dos sinais de entrada, o que é especialmente importante ao trabalhar com dados heterogêneos e ruidosos. No entanto, em nossa implementação introduzimos uma pequena alteração, mas de importância fundamental, que amplia as capacidades do modelo.

Agora, quando um impulso é gerado, o potencial acumulado do neurônio é reduzido pelo valor do limiar de ativação.

__kernel void FloatToSpike(__global float* values,
                           __global const float* levels,
                           __global float* outputs
                          )
  {
   const size_t id = get_global_id(0);
   float val = IsNaNOrInf(values[id], 0.0f);
   if(val == 0.0f)
      outputs[id] = 0.0f;
   else
     {
      const float lev = IsNaNOrInf(levels[id], 0.0f);
      if(fabs(val) < lev)
         outputs[id] = 0.0f;
      else
        {
         outputs[id] = (float)sign(val);
         values[id] = IsNaNOrInf(sign(val)*(fabs(val)-lev), 0.0f);
        }
     }
  }

Optamos deliberadamente por não redefinir o potencial para um valor fixo VReset. À primeira vista, isso pode parecer um detalhe pouco relevante, mas, na prática, proporciona um nível de flexibilidade completamente novo. Essa abordagem permite criar uma espécie de gradação dos impulsos. Um sinal mais intenso deixa um efeito residual mais duradouro no potencial de membrana, influenciando os eventos subsequentes. Em outras palavras, o neurônio passa a preservar o histórico dos impulsos significativos, criando um efeito de inércia temporal.

No contexto dos mercados financeiros, isso adquire um valor prático especial. Os eventos de mercado raramente são isolados. O movimento do preço de um instrumento costuma se prolongar em uma série de impulsos relacionados, enquanto a reação do mercado a uma notícia pode se estender ao longo do tempo. A capacidade do neurônio de reter parte do potencial acumulado permite que o modelo preserve informações sobre eventos relevantes e responda adequadamente às suas consequências, criando uma memória dinâmica interna. Essa dinâmica de funcionamento dos neurônios torna a SEW-ResNet mais sensível aos padrões reais do mercado e, ao mesmo tempo, reduz a influência do ruído aleatório.

Assim, uma pequena alteração pontual no mecanismo transforma o neurônio de uma simples chave entre spike e ausência de spike em um elemento dinâmico completo, capaz de produzir diferentes níveis de resposta. Essa combinação de precisão, adaptabilidade e capacidade de acumular informações ao longo do tempo é uma das principais características da nossa implementação e estabelece uma base sólida para a construção de modelos profundos, estáveis e adaptativos.

A solução proposta é implementada como um novo objeto CNeuronSpikeActivation, herdado da classe base CNeuronBaseOCL. Esse objeto incorpora toda a dinâmica do neurônio spiking, incluindo o acúmulo do potencial de membrana, o limiar adaptativo e o mecanismo de gradação da geração de impulsos.

class CNeuronSpikeActivation  :  CNeuronBaseOCL
  {
protected:
   CNeuronBaseOCL    cHV;
   CParams           cLevels;
   CParams           cGates;
   //---
   virtual bool      FloatToSpike(void);
   virtual bool      FloatToSpikeGrad(void);
   //---
   virtual bool      feedForward(CNeuronBaseOCL *NeuronOCL) override;
   virtual bool      updateInputWeights(CNeuronBaseOCL *NeuronOCL) override;
   virtual bool      calcInputGradients(CNeuronBaseOCL *NeuronOCL) override;

public:
                     CNeuronSpikeActivation(void) {};
                    ~CNeuronSpikeActivation(void) {};
   //---
   virtual bool      Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                          uint neurons, ENUM_OPTIMIZATION optimization_type, uint batch);
   //---
   virtual int       Type(void) override const  {  return defNeuronSpikeActivation;   }
   //--- methods for working with files
   virtual bool      Save(const int file_handle) override;
   virtual bool      Load(const int file_handle) override;
   virtual void      SetOpenCL(COpenCLMy *obj)   override;
   //---
   virtual bool      WeightsUpdate(CNeuronBaseOCL *source, float tau) override;
   virtual void      SetActivationFunction(ENUM_ACTIVATION value) override { };
   virtual void      TrainMode(bool flag) override;
   virtual bool      Clear(void) override;
  };

Dentro do objeto, destacam-se vários componentes principais:

  • cHV é responsável pela dinâmica interna do neurônio, acumulando o potencial e levando em conta os eventos spiking;
  • cLevels armazena os parâmetros dos limiares, permitindo seu aprendizado adaptativo;
  • cGates implementa o mecanismo de atualização do potencial de membrana por gate, permitindo que cada neurônio regule individualmente a velocidade de resposta ao sinal de entrada.

Assim, cada neurônio pode desenvolver uma estratégia própria de resposta a eventos ruidosos ou relevantes, o que é especialmente importante na análise de séries temporais financeiras.

Todos os objetos internos da nova classe são declarados estaticamente, o que permitiu manter vazios o construtor e o destrutor da classe: nenhuma ação adicional é necessária ao criar ou excluir o objeto. Essa solução simplifica significativamente a arquitetura, torna seu comportamento mais previsível e facilita a integração do novo neurônio à biblioteca existente.

Toda a inicialização da nova camada neural está concentrada no método Init, que funciona como ponto de entrada para a configuração de todos os componentes do objeto. É nele que são definidos os principais parâmetros.

bool CNeuronSpikeActivation::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                                  uint numNeurons, ENUM_OPTIMIZATION optimization_type, uint batch)
  {
   if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, numNeurons, optimization_type, batch))
      return false;

A inicialização começa com a chamada do método homônimo da classe pai, que configura os parâmetros fundamentais do neurônio. Após sua execução bem-sucedida, os componentes internos são criados e inicializados. cHV é responsável pela dinâmica do potencial de membrana. É configurada uma ativação nula, e os buffers são limpos para que o neurônio comece em um estado inicial limpo.

   uint index = 0;
   if(!cHV.Init(0, index, OpenCL, Neurons(), optimization, iBatch))
      return false;
   cHV.SetActivationFunction(None);
   cHV.Clear();

Em seguida, é criado o objeto cLevels, responsável pelos limiares de ativação adaptativos. Para ele, é definida a função de ativação SoftPlus, que proporciona uma atualização suave e estável dos limiares, enquanto os pesos são inicializados com o valor -3.0f, estabelecendo um limiar inicial conservador. Esse limiar permite que o neurônio acumule os sinais de entrada e reaja apenas a eventos realmente significativos, sem, no entanto, manter todos os neurônios inativos desde o início do treinamento. Isso é importante. Os neurônios continuam capazes de gerar os primeiros spikes já nas etapas iniciais, garantindo um fluxo contínuo de informações pelo modelo e permitindo que os gradientes se propaguem de forma eficiente durante o treinamento.

Em outras palavras, evitamos uma situação em que os neurônios permaneçam completamente passivos nas etapas iniciais: eles participam do treinamento desde o início, mas reagem de forma cautelosa. Esse equilíbrio entre uma inicialização conservadora e a atividade dos neurônios cria condições favoráveis para o aprendizado gradual do modelo e estabiliza as etapas iniciais do treinamento.

   index++;
   if(!cLevels.Init(0, index, OpenCL, Neurons(), optimization, iBatch))
      return false;
   cLevels.SetActivationFunction(SoftPlus);
   CBufferFloat* temp = cLevels.getWeightsParams();
   if(!temp ||
      !temp.Fill(-3.0f))
      return false;

Na etapa seguinte, inicializamos o objeto cGates, que implementa o mecanismo de atualização do potencial de membrana por gate. A ele é atribuída a ativação SIGMOID, permitindo que cada neurônio aprenda seu próprio coeficiente de resposta aos novos sinais. Os pesos são inicializados com zeros, o que proporciona um comportamento neutro no início do treinamento. Após a passagem do sinal pela função SIGMOID, o resultado fica próximo de 0.5, ponto em que a sigmoide apresenta comportamento praticamente linear. Isso é fundamental. Nessa região, os gradientes mantêm magnitude suficiente permitindo ajustar rapidamente os parâmetros do gate.

Em outras palavras, no início do treinamento o neurônio recebe uma configuração equilibrada: o gate não bloqueia completamente o sinal nem permite sua passagem integral, mantendo espaço para adaptação. Já nos primeiros passos do treinamento, o modelo consegue regular de forma flexível a velocidade de acúmulo do potencial de membrana de cada neurônio, adaptando-se às características dos dados de entrada. Isso é especialmente importante para séries temporais financeiras, nas quais os sinais podem ser tanto calmos e previsíveis quanto abruptos e ruidosos. E a dinâmica de resposta adequada dos neurônios afeta diretamente a precisão das previsões.

   index++;
   if(!cGates.Init(0, index, OpenCL, Neurons(), optimization, iBatch))
      return false;
   cGates.SetActivationFunction(SIGMOID);
   temp = cGates.getWeightsParams();
   if(!temp ||
      !temp.Fill(0.0f))
      return false;
//---
   return true;
  }

Assim, o método de inicialização configura a camada neural e cria uma estrutura pronta para operação, flexível e adaptativa, capaz de acumular informações, controlar o limiar de ativação e responder individualmente aos sinais de entrada.

Após concluir a inicialização do objeto, o próximo passo lógico é implementar o algoritmo de propagação para frente, ou seja, definir como o neurônio processa os dados de entrada e gera spikes. Esse processo é implementado no método feedForward, que constitui o núcleo do funcionamento do neurônio.

bool CNeuronSpikeActivation::feedForward(CNeuronBaseOCL *NeuronOCL)
  {
   if(!NeuronOCL)
      return false;
//---
   if(!cHV.SwapOutputs())
      return false;

O algoritmo começa com uma pequena etapa de preparação. Primeiro, verificamos se o ponteiro recebido para o objeto NeuronOCL da camada anterior é válido. Isso garante que os dados necessários ao processamento realmente estejam disponíveis. Em seguida, chamamos o método SwapOutputs para o objeto cHV, atualizando o estado interno do potencial de membrana. Os valores atuais passam a representar o estado anterior, e o neurônio fica preparado para processar o novo passo temporal. Essa etapa é essencial para acumular corretamente o potencial e gerar spikes levando em conta o histórico dos sinais.

Se a rede estiver no modo de treinamento, também executamos a propagação para frente dos objetos internos cLevels e cGates. O primeiro é responsável pela adaptação do limiar de ativação, enquanto o segundo atualiza o gate do potencial de membrana. São justamente esses componentes que permitem ao neurônio ajustar de forma flexível sua sensibilidade aos dados analisados e aprender de maneira eficiente mesmo com sinais ruidosos ou sujeitos a mudanças.

   if(bTrain)
     {
      if(!cLevels.FeedForward())
         return false;
      if(!cGates.FeedForward())
         return false;
     }

Em seguida, o sinal de entrada é somado elemento a elemento ao potencial de membrana, levando em conta os gates. Essa operação implementa um dos princípios fundamentais dos neurônios spiking: o sinal de entrada é acumulado considerando o estado atual do neurônio e sua resposta individual à novidade dos sinais recebidos. Essa abordagem permite que o modelo preserve uma memória dinâmica e responda de forma flexível a dependências temporais complexas, o que é especialmente importante para séries temporais financeiras, nas quais cada mudança pode continuar influenciando os eventos subsequentes por um período prolongado.

   if(!GateElementMult(NeuronOCL.getOutput(), cHV.getPrevOutput(),
                       cGates.getOutput(), cHV.getOutput()))
      return false;
   return FloatToSpike();
  }

A chamada do método FloatToSpike conclui a propagação para frente, gerando spikes com base no estado atual da membrana e no limiar adaptativo. Como resultado, o método feedForward produz o sinal de saída do neurônio, pronto para ser processado nas etapas seguintes de uma SEW-ResNet profunda.

Como podemos observar, o algoritmo do método de propagação para frente apresenta uma estrutura linear e previsível. Cada operação, desde a atualização do potencial de membrana até a aplicação do gate e a geração de spikes, é executada de forma sequencial e transparente, sem ramificações complexas nem fluxos de dados conflitantes. Essa abordagem traz uma consequência prática importante: a propagação do gradiente do erro e o treinamento do modelo permanecem estáveis e não são complicados pelo processamento paralelo das informações, o que é especialmente valioso em redes profundas com grande número de neurônios.

Os métodos de propagação reversa, responsáveis pelo cálculo dos gradientes e pela atualização dos pesos, são deixados para estudo independente nesta implementação. O código completo da classe CNeuronSpikeActivation e de todos os seus métodos está disponível em anexo, permitindo ao leitor examinar detalhadamente a implementação e utilizá-la na construção de seus próprios modelos.

Assim, CNeuronSpikeActivation constitui uma ferramenta universal e flexível para a construção de modelos spiking profundos baseados em SEW-ResNet com MQL5. Sua arquitetura permite experimentar diferentes esquemas de acúmulo do potencial, de adaptação do limiar e de geração de spikes sem comprometer a compatibilidade com os objetos de camadas neurais já existentes. É justamente essa abordagem modular e extensível que permite construir modelos profundos, estáveis e adaptativos para a análise das séries temporais complexas características dos mercados financeiros.

Hoje avançamos significativamente, e este é um bom momento para consolidar o conhecimento adquirido. No próximo artigo, retomaremos a implementação das abordagens propostas pelos autores do framework SEW-ResNet, dando continuidade à construção de modelos spiking eficientes e adaptativos com MQL5.


Conclusão

Neste artigo, conhecemos o framework SEW-ResNet, cuja principal vantagem é permitir a implementação direta do aprendizado residual em modelos spiking. Isso possibilita construir modelos profundos sem degradação do desempenho. O uso da natureza binária dos spikes em conjunto com operações elemento a elemento proporciona estabilidade diante do desaparecimento e da explosão dos gradientes.

Na parte prática, analisamos em detalhes os princípios de implementação dos neurônios spiking e do algoritmo básico de propagação para frente com MQL5. Mostramos como o uso de um limiar adaptativo, da atualização do potencial de membrana por gate e de um mecanismo de acúmulo do potencial permite que os neurônios respondam de forma eficiente a dados sequenciais e ruidosos.

No próximo artigo, continuaremos ampliando os recursos da SEW-ResNet para construir um modelo spiking profundo completo destinado à análise e à previsão de dados financeiros.


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/19839

Arquivos anexados |
MQL5.zip (3163.98 KB)
Desenvolvendo uma Estratégia de Pullback: Validação Desenvolvendo uma Estratégia de Pullback: Validação
A etapa de validação de um pullback avança com inclinação das EMAs, limites mínimo e máximo de distância por ATR, janela flexível do gatilho ATR e Walk-Forward Efficiency. As baterias comparam componentes e medem continuidade fora da amostra, dependência exclusiva da gestão. O resultado destaca plataformas paramétricas e critérios práticos para selecionar candidatos e evitar sobreajuste.
Criação de um robô market-neutral probabilístico com base na distribuição dos retornos Criação de um robô market-neutral probabilístico com base na distribuição dos retornos
Uma estratégia de trading market-neutral baseada na distribuição empírica dos retornos oferece uma alternativa aos métodos clássicos de análise técnica, substituindo a previsão da direção do preço pelo posicionamento estatístico de ordens em níveis com determinada probabilidade de serem atingidos. O artigo analisa em detalhes o formalismo matemático usado no cálculo de percentis, os algoritmos de ponderação do volume das posições de acordo com a probabilidade de execução e os mecanismos de adaptação às mudanças nas condições de mercado por meio da expiração da grade. Também é apresentada uma implementação completa em MQL5.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Redes neurais em trading: Dos transformers aos neurônios spiking (Conclusão) Redes neurais em trading: Dos transformers aos neurônios spiking (Conclusão)
As redes neurais já estão transformando a forma como analisamos os mercados, e novas arquiteturas abrem possibilidades ainda maiores. Neste artigo, concluímos nosso desenvolvimento com o framework SpikingBrain, que nos apresenta novas perspectivas.