English Русский 中文 Deutsch 日本語 Português 한국어 Français Italiano Türkçe
preview
Ejemplo de un conjunto de modelos ONNX en MQL5

Ejemplo de un conjunto de modelos ONNX en MQL5

MetaTrader 5Aprendizaje automático | 31 julio 2023, 10:35
305 0
MetaQuotes
MetaQuotes

Introducción

Para lograr un comercio estable, resulta deseable diversificar tanto los instrumentos negociados como las estrategias comerciales. La situación es la misma con los modelos de aprendizaje automático: resulta más sencillo crear varios modelos más simples que uno complejo, si bien podríamos tener dificultades al ensamblar estos modelos en un modelo ONNX.

Sin embargo, podemos combinar el uso de varios modelos ONNX ya entrenados en un programa MQL5. Vamos a ver lo fácil que resulta implementar uno de los conjuntos llamado clasificador de votación.


Modelos Usados

Para nuestro ejemplo, tomaremos 2 modelos simples: un modelo de predicción de precios de regresión y un modelo de predicción del movimiento de los precios de clasificación. La principal diferencia de los modelos uno respecto a otro es que la regresión predice la cantidad, mientras que la clasificación predice la etiqueta (clase).

El primer modelo es regresivo.

El entrenamiento se realizará con EURUSD D1 desde 2003 hasta finales de 2022. Para el entrenamiento, se utilizará una serie de 10 precios OHLC. Para mejorar la entrenabilidad del modelo, los precios se normalizan, y la desviación del precio promedio en la serie se divide por la desviación estándar en la serie. Esto nos permite encajar la serie en un rango determinado, con una media de 0 y una extensión de 1, lo cual mejora la convergencia durante el entrenamiento.

Como resultado, se podrá predecir el precio de cierre del día siguiente.

El modelo es muy simple y se ha implementado solo con fines ilustrativos.

# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com

from datetime import datetime
import MetaTrader5 as mt5
import tensorflow as tf
import numpy as np
import pandas as pd
import tf2onnx
from sklearn.model_selection import train_test_split
from tqdm import tqdm
from sys import argv

if not mt5.initialize():
    print("initialize() failed, error code =",mt5.last_error())
    quit()

# we will save generated onnx-file near the our script
data_path=argv[0]
last_index=data_path.rfind("\\")+1
data_path=data_path[0:last_index]
print("data path to save onnx model",data_path)

# input parameters
inp_model_name = "model.eurusd.D1.10.onnx"
inp_history_size = 10
inp_start_date = datetime(2003, 1, 1, 0)
inp_end_date = datetime(2023, 1, 1, 0)

# get data from client terminal
eurusd_rates = mt5.copy_rates_range("EURUSD", mt5.TIMEFRAME_D1, inp_start_date, inp_end_date)
df = pd.DataFrame(eurusd_rates)


#
# collect dataset subroutine
#
def collect_dataset(df: pd.DataFrame, history_size: int):
    """
    Collect dataset for the following regression problem:
    - input: history_size consecutive H1 bars;
    - output: close price for the next bar.

    :param df: D1 bars for a range of dates
    :param history_size: how many bars should be considered for making a prediction
    :return: features and labels
    """
    n = len(df)
    xs = []
    ys = []
    for i in tqdm(range(n - history_size)):
        w = df.iloc[i: i + history_size + 1]

        x = w[['open', 'high', 'low', 'close']].iloc[:-1].values
        y = w.iloc[-1]['close']
        xs.append(x)
        ys.append(y)

    X = np.array(xs)
    y = np.array(ys)
    return X, y
###


# get prices
X, y = collect_dataset(df, history_size=inp_history_size)

# normalize prices
m = X.mean(axis=1, keepdims=True)
s = X.std(axis=1, keepdims=True)
X_norm = (X - m) / s
y_norm = (y - m[:, 0, 3]) / s[:, 0, 3]

# split data to train and test sets
X_train, X_test, y_train, y_test = train_test_split(X_norm, y_norm, test_size=0.2, random_state=0)

# define model
model = tf.keras.Sequential([
    tf.keras.layers.LSTM(64, input_shape=(inp_history_size, 4)),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dropout(0.1),
    tf.keras.layers.Dense(32, activation='relu'),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dropout(0.1),
    tf.keras.layers.Dense(32, activation='relu'),
    tf.keras.layers.Dense(1)
])

model.compile(optimizer='adam', loss='mse', metrics=['mae'])

# model training for 50 epochs
lr_reduction = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, min_lr=0.000001)
history = model.fit(X_train, y_train, epochs=50, verbose=2, validation_split=0.15, callbacks=[lr_reduction])

# model evaluation
test_loss, test_mae = model.evaluate(X_test, y_test)
print(f"test_loss={test_loss:.3f}")
print(f"test_mae={test_mae:.3f}")

# save model to onnx
output_path = data_path+inp_model_name
onnx_model = tf2onnx.convert.from_keras(model, output_path=output_path)
print(f"saved model to {output_path}")

# finish
mt5.shutdown()
Se supone que al ejecutar nuestro modelo de regresión, el precio pronosticado resultante deberá transformarse en la clase "el precio baja, el precio no cambia, el precio sube". Esto será necesario para organizar el clasificador de votación.

El segundo modelo será el modelo de clasificación.

El entrenamiento se realizará con EURUSD D1 desde 2010 hasta finales de 2022. Para el entrenamiento, se utilizará una serie de 63 precios de cierre. En la salida, se deberá definir una de las tres clases: el precio bajará, el precio permanecerá dentro de los 10 puntos o el precio subirá. Es precisamente por la segunda clase que hemos estado entrenando con datos desde 2010, ya que en 2009 se dio una transición de la precisión de 4 dígitos a la de 5 dígitos. De esta forma, un elemento "antiguo" se convirtió en diez elementos "nuevos".

Al igual que en el modelo anterior, el precio está normalizado. Se normaliza de la misma forma: dividiendo la desviación del precio promedio de la serie por la desviación estándar de la misma. La idea de este modelo se toca en el artículo "Pronóstico de series temporales financieras con MLP en Keras" (en ruso). El modelo es puramente demostrativo, al igual que el anterior.

# Copyright 2023, MetaQuotes Ltd.
# https://www.mql5.com
#
# Classification model
# 0,0,1 - predict price down
# 0,1,0 - predict price same
# 1,0,0 - predict price up
#

from datetime import datetime
import MetaTrader5 as mt5
import tensorflow as tf
import numpy as np
import pandas as pd
import tf2onnx
from sklearn.model_selection import train_test_split
from tqdm import tqdm
from keras.models import Sequential
from keras.layers import Dense, Activation,Dropout, BatchNormalization, LeakyReLU
from keras.optimizers import SGD
from keras import regularizers
from sys import argv

# initialize MetaTrader 5 client terminal
if not mt5.initialize():
    print("initialize() failed, error code =",mt5.last_error())
    quit()

# we will save the generated onnx-file near the our script
data_path=argv[0]
last_index=data_path.rfind("\\")+1
data_path=data_path[0:last_index]
print("data path to save onnx model",data_path)

# input parameters
inp_model_name = "model.eurusd.D1.63.onnx"
inp_history_size = 63
inp_start_date = datetime(2010, 1, 1, 0)
inp_end_date = datetime(2023, 1, 1, 0)

# get data from the client terminal
eurusd_rates = mt5.copy_rates_range("EURUSD", mt5.TIMEFRAME_D1, inp_start_date, inp_end_date)
df = pd.DataFrame(eurusd_rates)


#
# collect dataset subroutine
#
def collect_dataset(df: pd.DataFrame, history_size: int):
    """
    Collect dataset for the following regression problem:
    - input: history_size consecutive H1 bars;
    - output: close price for the next bar.

    :param df: H1 bars for a range of dates
    :param history_size: how many bars should be considered for making a prediction
    :return: features and labels
    """
    n = len(df)
    xs = []
    ys = []
    for i in tqdm(range(n - history_size)):
        w = df.iloc[i: i + history_size + 1]
        x = w[['close']].iloc[:-1].values

        delta = x[-1] - w.iloc[-1]['close']
        if np.abs(delta)<=0.0001:
           y = 0, 1, 0
        else:
           if delta<0:
              y = 1, 0, 0
           else:
              y = 0, 0, 1

        xs.append(x)
        ys.append(y)

    X = np.array(xs)
    Y = np.array(ys)
    return X, Y
###


# get prices
X, Y = collect_dataset(df, history_size=inp_history_size)

# normalize prices
m = X.mean(axis=1, keepdims=True)
s = X.std(axis=1, keepdims=True)
X_norm = (X - m) / s

# split data to train and test sets
X_train, X_test, Y_train, Y_test = train_test_split(X_norm, Y, test_size=0.1, random_state=0)

# define model
model = Sequential()
model.add(Dense(64, input_dim=inp_history_size, activity_regularizer=regularizers.l2(0.01)))
model.add(BatchNormalization())
model.add(LeakyReLU())
model.add(Dropout(0.3))
model.add(Dense(16, activity_regularizer=regularizers.l2(0.01)))
model.add(BatchNormalization())
model.add(LeakyReLU())
model.add(Dense(3))
model.add(Activation('softmax'))

opt = SGD(learning_rate=0.01, momentum=0.9)
model.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accuracy'])

# model training for 300 epochs
lr_reduction = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.9, patience=5, min_lr=0.00001)
history = model.fit(X_train, Y_train, epochs=300, validation_data=(X_test, Y_test), shuffle = True, batch_size=128, verbose=2, callbacks=[lr_reduction])

# model evaluation
test_loss, test_accuracy = model.evaluate(X_test, Y_test)
print(f"test_loss={test_loss:.3f}")
print(f"test_accuracy={test_accuracy:.3f}")

# save model to onnx
output_path = data_path+inp_model_name
onnx_model = tf2onnx.convert.from_keras(model, output_path=output_path)
print(f"saved model to {output_path}")

# finish
mt5.shutdown()
Los modelos presentados han sido entrenados con datos hasta finales de 2022 para poder demostrar el funcionamiento de los modelos en el simulador de estrategias.


Conjunto de modelos ONNX en un asesor experto de MQL5

Ahora presentaremos un asesor experto simple para demostrar las posibilidades de los conjuntos de modelos. Los principios fundamentales del uso de modelos ONNX en MQL5 se describieron en la segunda parte del artículo del mismo nombre.

Declaraciones y definiciones preliminares

#include <Trade\Trade.mqh>

input double InpLots = 1.0;              // Lots amount to open position

#resource "Python/model.eurusd.D1.10.onnx" as uchar ExtModel1[]
#resource "Python/model.eurusd.D1.63.onnx" as uchar ExtModel2[]

#define SAMPLE_SIZE1 10
#define SAMPLE_SIZE2 63

long     ExtHandle1=INVALID_HANDLE;
long     ExtHandle2=INVALID_HANDLE;
int      ExtPredictedClass1=-1;
int      ExtPredictedClass2=-1;
int      ExtPredictedClass=-1;
datetime ExtNextBar=0;
CTrade   ExtTrade;

//--- price movement prediction
#define PRICE_UP   0
#define PRICE_SAME 1
#define PRICE_DOWN 2

Función OnInit

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(_Symbol!="EURUSD" || _Period!=PERIOD_D1)
     {
      Print("model must work with EURUSD,D1");
      return(INIT_FAILED);
     }

//--- create first model from static buffer
   ExtHandle1=OnnxCreateFromBuffer(ExtModel1,ONNX_DEFAULT);
   if(ExtHandle1==INVALID_HANDLE)
     {
      Print("First model OnnxCreateFromBuffer error ",GetLastError());
      return(INIT_FAILED);
     }
//--- since not all sizes defined in the input tensor we must set them explicitly
//--- first index - batch size, second index - series size, third index - number of series (OHLC)
   const long input_shape1[] = {1,SAMPLE_SIZE1,4};
   if(!OnnxSetInputShape(ExtHandle1,0,input_shape1))
     {
      Print("First model OnnxSetInputShape error ",GetLastError());
      return(INIT_FAILED);
     }
   
//--- since not all sizes defined in the output tensor we must set them explicitly
//--- first index - batch size, must match the batch size of the input tensor
//--- second index - number of predicted prices (we only predict Close)
   const long output_shape1[] = {1,1};
   if(!OnnxSetOutputShape(ExtHandle1,0,output_shape1))
     {
      Print("First model OnnxSetOutputShape error ",GetLastError());
      return(INIT_FAILED);
     }

//--- create second model from static buffer
   ExtHandle2=OnnxCreateFromBuffer(ExtModel2,ONNX_DEFAULT);
   if(ExtHandle2==INVALID_HANDLE)
     {
      Print("Second model OnnxCreateFromBuffer error ",GetLastError());
      return(INIT_FAILED);
     }
  
//--- since not all sizes defined in the input tensor we must set them explicitly
//--- first index - batch size, second index - series size
   const long input_shape2[] = {1,SAMPLE_SIZE2};
   if(!OnnxSetInputShape(ExtHandle2,0,input_shape2))
     {
      Print("Second model OnnxSetInputShape error ",GetLastError());
      return(INIT_FAILED);
     }

//--- since not all sizes defined in the output tensor we must set them explicitly
//--- first index - batch size, must match the batch size of the input tensor
//--- second index - number of classes (up, same or down)
   const long output_shape2[] = {1,3};
   if(!OnnxSetOutputShape(ExtHandle2,0,output_shape2))
     {
      Print("Second model OnnxSetOutputShape error ",GetLastError());
      return(INIT_FAILED);
     }
//--- ok
   return(INIT_SUCCEEDED);
  }

Hoy trabajaremos solo con EURUSD, D1, simplemente porque vamos a usar los datos del símbolo-periodo actual, a pesar de que los modelos están entrenados con precios diarios.

Ambos modelos están incluidos en el asesor experto como recursos.

Asegúrese de definir explícitamente los formularios de los datos de entrada y salida.

Función OnTick

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- check new bar
   if(TimeCurrent()<ExtNextBar)
      return;
//--- set next bar time
   ExtNextBar=TimeCurrent();
   ExtNextBar-=ExtNextBar%PeriodSeconds();
   ExtNextBar+=PeriodSeconds();

//--- predict price movement
   Predict();
//--- check trading according to prediction
   if(ExtPredictedClass>=0)
      if(PositionSelect(_Symbol))
         CheckForClose();
      else
         CheckForOpen();
  }

Todas las transacciones comerciales se realizarán solo al comienzo del día.

Función de predicción

//+------------------------------------------------------------------+
//| Voting classification                                            |
//+------------------------------------------------------------------+
void Predict(void)
  {
//--- evaluate first model
   ExtPredictedClass1=PredictPrice(ExtHandle1,SAMPLE_SIZE1);
//--- evaluate second model
   ExtPredictedClass2=PredictPriceMovement(ExtHandle2,SAMPLE_SIZE2);
//--- vote
   if(ExtPredictedClass1==ExtPredictedClass2)
      ExtPredictedClass=ExtPredictedClass1;
   else
      ExtPredictedClass=-1;
  }

Cuando ambos modelos hayan recibido la misma clase, esa clase se considerará seleccionada. Voto por mayoría. Y como solo hay dos modelos en el conjunto, votar por mayoría significará "por unanimidad".

Predicción del precio de cierre del día a partir de los 10 precios anteriores de OHLC

//+------------------------------------------------------------------+
//| Predict next price (first model)                                 |
//+------------------------------------------------------------------+
int PredictPrice(const long handle,const int sample_size)
  {
   static matrixf input_data(sample_size,4);    // matrix for prepared input data
   static vectorf output_data(1);               // vector to get result
   static matrix  mm(sample_size,4);            // matrix of horizontal vectors Mean
   static matrix  ms(sample_size,4);            // matrix of horizontal vectors Std
   static matrix  x_norm(sample_size,4);        // matrix for prices normalize

//--- prepare input data
   matrix rates;
//--- request last bars
   if(!rates.CopyRates(_Symbol,_Period,COPY_RATES_OHLC,1,sample_size))
      return(-1);
//--- get series Mean
   vector m=rates.Mean(1);
//--- get series Std
   vector s=rates.Std(1);
//--- prepare matrices for prices normalization
   for(int i=0; i<sample_size; i++)
     {
      mm.Row(m,i);
      ms.Row(s,i);
     }
//--- the input of the model must be a set of vertical OHLC vectors
   x_norm=rates.Transpose();
//--- normalize prices
   x_norm-=mm;
   x_norm/=ms;

//--- run the inference
   input_data.Assign(x_norm);
   if(!OnnxRun(handle,ONNX_NO_CONVERSION,input_data,output_data))
      return(-1);
//--- denormalize the price from the output value
   double predicted=output_data[0]*s[3]+m[3];
//--- classify predicted price movement
   int    predicted_class=-1;
   double delta=rates[3][sample_size-1]-predicted;
   if(fabs(delta)<=0.0001)
      predicted_class=PRICE_SAME;
   else
     {
      if(delta<0)
         predicted_class=PRICE_UP;
      else
         predicted_class=PRICE_DOWN;

     }

   return(predicted_class);
  }

Los datos de entrada se preparan según las mismas reglas que utilizamos al entrenar el modelo. Una vez ejecutado el modelo, el valor resultante se convertirá nuevamente en un precio. Según la diferencia entre el último precio de cierre de la serie y el precio obtenido, se calculará la clase.

Predicción del movimiento de precios basada en una serie de 63 precios Close diarios.

//+------------------------------------------------------------------+
//| Predict price movement (second model)                            |
//+------------------------------------------------------------------+
int PredictPriceMovement(const long handle,const int sample_size)
  {
   static vectorf input_data(sample_size);    // vector for prepared input data
   static vectorf output_data(3);             // vector to get result

//--- request last bars
   if(!input_data.CopyRates(_Symbol,_Period,COPY_RATES_CLOSE,1,sample_size))
      return(-1);
//--- get series Mean
   float m=input_data.Mean();
//--- get series Std
   float s=input_data.Std();
//--- normalize prices
   input_data-=m;
   input_data/=s;

//--- run the inference
   if(!OnnxRun(handle,ONNX_NO_CONVERSION,input_data,output_data))
      return(-1);
//--- evaluate prediction
   return(int(output_data.ArgMax()));
  }

La normalización de los precios se realiza según las mismas reglas que usamos en el primer modelo, pero el código ha resultado más compacto debido a que la entrada es un vector, no una matriz. La clase se seleccionará según el valor máximo de las tres probabilidades.

La estrategia comercial es simple. Las operaciones comerciales se realizarán al inicio de cada día. Si el pronóstico es "el precio subirá", entonces compraremos, si es "el precio bajará", venderemos.

//+------------------------------------------------------------------+
//| Check for open position conditions                               |
//+------------------------------------------------------------------+
void CheckForOpen(void)
  {
   ENUM_ORDER_TYPE signal=WRONG_VALUE;
//--- check signals
   if(ExtPredictedClass==PRICE_DOWN)
      signal=ORDER_TYPE_SELL;    // sell condition
   else
     {
      if(ExtPredictedClass==PRICE_UP)
         signal=ORDER_TYPE_BUY;  // buy condition
     }

//--- open position if possible according to signal
   if(signal!=WRONG_VALUE && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
      ExtTrade.PositionOpen(_Symbol,signal,InpLots,
                            SymbolInfoDouble(_Symbol,signal==ORDER_TYPE_SELL ? SYMBOL_BID:SYMBOL_ASK),
                            0,0);
  }
//+------------------------------------------------------------------+
//| Check for close position conditions                              |
//+------------------------------------------------------------------+
void CheckForClose(void)
  {
   bool bsignal=false;
//--- position already selected before
   long type=PositionGetInteger(POSITION_TYPE);
//--- check signals
   if(type==POSITION_TYPE_BUY && ExtPredictedClass==PRICE_DOWN)
      bsignal=true;
   if(type==POSITION_TYPE_SELL && ExtPredictedClass==PRICE_UP)
      bsignal=true;

//--- close position if possible
   if(bsignal && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      ExtTrade.PositionClose(_Symbol,3);
      //--- open opposite
      CheckForOpen();
     }
  }


Entrenaremos nuestros modelos con datos hasta principios de 2023. Por lo tanto, estableceremos el intervalo de prueba desde el comienzo del año.

Ajustes de la simulación

Aquí está el resultado de las pruebas desde el comienzo del año.

Resultados de la prueba del asesor experto


Sería interesante conocer los resultados de la prueba de cada uno de estos modelos por separado.

Para ello, modificaremos el código fuente del asesor experto,

enum EnModels
  {
   USE_FIRST_MODEL,    // Use first model only
   USE_SECOND_MODEL,   // Use second model only
   USE_BOTH_MODELS     // Use both models
  };
input EnModels InpModels = USE_BOTH_MODELS;  // Models using
input double   InpLots   = 1.0;              // Lots amount to open position

...

//+------------------------------------------------------------------+
//| Voting classification                                            |
//+------------------------------------------------------------------+
void Predict(void)
  {
//--- evaluate first model
   if(InpModels==USE_BOTH_MODELS || InpModels==USE_FIRST_MODEL)
      ExtPredictedClass1=PredictPrice(ExtHandle1,SAMPLE_SIZE1);
//--- evaluate second model
   if(InpModels==USE_BOTH_MODELS || InpModels==USE_SECOND_MODEL)
      ExtPredictedClass2=PredictPriceMovement(ExtHandle2,SAMPLE_SIZE2);

//--- check predictions
   switch(InpModels)
     {
      case USE_FIRST_MODEL :
         ExtPredictedClass=ExtPredictedClass1;
         break;
      case USE_SECOND_MODEL :
         ExtPredictedClass=ExtPredictedClass2;
         break;
      case USE_BOTH_MODELS :
         if(ExtPredictedClass1==ExtPredictedClass2)
            ExtPredictedClass=ExtPredictedClass1;
         else
            ExtPredictedClass=-1;
     }
  }

estableciendo la configuración "usar solo el primer modelo".

Configuración del asesor para usar solo el primer modelo

Resultados de la prueba del primer modelo.

Resultados de la prueba del primer modelo


Ahora probaremos solo el segundo modelo. Aquí tenemos los resultados de las pruebas del segundo modelo.

Resultados de la prueba del segundo modelo

El segundo modelo ha resultado mucho más fuerte que el primero. Los resultados confirman la teoría de que es necesario ensamblar modelos débiles, pero en este artículo no hemos tratado de la teoría del conjunto, sino de la práctica de su aplicación.

Importante: tenga en cuenta que los modelos usados en el artículo se presentan solo para demostrar cómo trabajar con modelos ONNX utilizando el lenguaje MQL5. El asesor no ha sido diseñado para comercia en cuentas reales.



Conclusión

En el presente artículo, hemos presentado un ejemplo muy simple e ilustrativo de un conjunto de dos modelos ONNX. El número de modelos usados simultáneamente es limitado y no puede exceder los 256 modelos, pero incluso el uso de más de dos modelos requerirá un enfoque distinto a la hora de programar tales expertos, concretamente, un modelo orientado a objetos.

Sin embargo, este es un tema para otro artículo.

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/12433

Archivos adjuntos |
MQL5.zip (105.08 KB)
Multibot en MetaTrader: iniciamos múltiples robots desde un gráfico Multibot en MetaTrader: iniciamos múltiples robots desde un gráfico
En este artículo, veremos una plantilla simple para crear un robot MetaTrader universal que se pueda usar en varios gráficos, pero adjunto a uno solo, sin necesidad de configurar cada ejemplar del robot en cada gráfico individual.
Estrategia comercial con el indicador de mejora de reconocimiento de velas Doji Estrategia comercial con el indicador de mejora de reconocimiento de velas Doji
El indicador sobre metabarras ha detectado más velas que el clásico. Veamos si aporta un beneficio real en el trading automatizado.
Aprendizaje automático y Data Science (Parte 14): Aplicación de los mapas de Kohonen a los mercados Aprendizaje automático y Data Science (Parte 14): Aplicación de los mapas de Kohonen a los mercados
¿Quiere encontrar un nuevo enfoque comercial que lo ayude a orientarse en mercados complejos y en cambio constante? Eche un vistazo a los mapas de Kohonen, una forma innovadora de redes neuronales artificiales que puede ayudarle a descubrir patrones y tendencias ocultos en los datos del mercado. En este artículo, veremos cómo funcionan los mapas de Kohonen y cómo usarlos para desarrollar estrategias comerciales efectivas. Creo que este nuevo enfoque resultará de interés tanto a los tráders experimentados como para los principiantes.
Redes neuronales: así de sencillo (Parte 37): Atención dispersa (Sparse Attention) Redes neuronales: así de sencillo (Parte 37): Atención dispersa (Sparse Attention)
En el artículo anterior, analizamos los modelos relacionales que utilizan mecanismos de atención en su arquitectura. Una de las características de dichos modelos es su mayor uso de recursos informáticos. Este artículo propondrá uno de los posibles mecanismos para reducir el número de operaciones computacionales dentro del bloque Self-Attention o de auto-atención, lo cual aumentará el rendimiento del modelo en su conjunto.