Aprendizaje automático

Métodos para el aprendizaje automático.

La función de activación en una red neuronal determina el valor de salida de las neuronas según el resultado de la suma ponderada de las entradas. La elección de la función de activación influye sustancialmente en las capacidades y el rendimiento de la red neuronal. Las diferentes partes del modelo (capas) pueden utilizar funciones de activación distintas.

MQL5 implementa no solo todas las funciones de activación conocidas, sino también sus derivadas. Las derivadas de las funciones permiten actualizar eficazmente los parámetros del modelo según el error de aprendizaje.

La tarea de entrenar una red neuronal consiste en encontrar un algoritmo que minimice el error en la muestra de entrenamiento, usando para ello la función de pérdida. El valor de la función de pérdida describe la magnitud de desviación del valor predicho por el modelo respecto al valor real. Dependiendo del tipo de tarea a resolver se usarán diferentes funciones de pérdida. Por ejemplo: para un problema de regresión, será mean squared error (MSE), para la clasificación binaria, será binary cross-entropy (BCE)..

Función

Acción

Activation

Calcula los valores de la función de activación y los escribe en el vector/matriz trasmitido

Derivative

Calcula los valores de la derivada de la función de activación y los escribe en el vector/matriz transmitido

Loss

Calcula los valores de la función de pérdida y los escribe en el vector/matriz trasmitido

LossGradient

Calcula un vector o matriz de gradientes de la función de pérdida

RegressionMetric

Calcula la métrica de regresión como el error de desviación respecto a la línea de regresión trazada en el conjunto de datos especificado.

ConfusionMatrix

Calcula la matriz de error. El método se aplica a un vector de valores predichos

ConfusionMatrixMultilabel

Calcula la matriz de error para cada etiqueta. El método se aplica a un vector de valores predichos

ClassificationMetric

Calcula la métrica clasificatoria para evaluar la calidad de los datos previstos respecto a los datos reales. El método se aplica a un vector de valores predichos

ClassificationScore

Calcula la métrica clasificatoria para evaluar la calidad de los datos previstos respecto a los datos reales

PrecisionRecall

Calcula los valores para construir la curva precision-recall. Este método, al igual que el método ClassificationScore, se aplica al vector de valores verdaderos.

ReceiverOperatingCharacteristic

Calcula los valores para construir la curva Receiver Operating Characteristic (ROC). Este método, al igual que el método ClassificationScore, se aplica al vector de valores verdaderos.

Ejemplo:

Este ejemplo muestra el entrenamiento de un modelo usando operaciones matriciales. El modelo se entrena con la función (a + b + c)^2 / (a^2 + b^2 + c^2). La entrada es una matriz de datos de origen en las que a, b y c se encuentran en columnas aparte. La salida del modelo retorna el resultado de la función.

matrix weights1weights2weights3;               // matrices de coeficientes de peso
matrix output1output2result;                   // matrices de salidas de redes neuronales
input int layer1 = 200;                            // tamaño de la 1-era capa oculta
input int layer2 = 200;                            // tamaño de la 2-nda capa oculta
input int Epochs = 20000;                          // número de epocas de entrenamiento
input double lr = 3e-6;                            // tasa de aprendizaje
input ENUM_ACTIVATION_FUNCTION ac_func = AF_SWISH// función de activación
//+------------------------------------------------------------------+
//| Función de inicio del script                                     |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   int train = 1000;    // tamaño de la muestra de entrenamiento
   int test = 10;       // tamaño de la muestra de prueba
   matrix m_datam_target;
//--- generamos la muestra de entrenamiento
   if(!CreateData(m_datam_targettrain))  
      return;
//--- entrenamos el modelo
   if(!Train(m_datam_targetEpochs))      
      return;
//--- generamos una muestra de prueba
   if(!CreateData(m_datam_targettest))   
      return;
//--- probamos el modelo
   Test(m_datam_target);                   
  }
//+------------------------------------------------------------------+
//| Método para generar la muestra                                   |
//+------------------------------------------------------------------+
bool CreateData(matrix &datamatrix &targetconst int count)
  {
//--- inicializar las matrices de entrada y salida
   if(!data.Init(count3) || !target.Init(count1))
      return false;
//--- rellenar la matriz de datos de entrada con valores aleatorios
   data.Random(-1010);                     
//--- calculamos los valores objetivo de la muestra de entrenamiento
   vector X1 = MathPow(data.Col(0) + data.Col(1) + data.Col(1), 2);
   vector X2 = MathPow(data.Col(0), 2) + MathPow(data.Col(1), 2) + MathPow(data.Col(2), 2);
   if(!target.Col(X1 / X20))
      return false;
//--- retornamos el resultado
   return true;
  }
//+------------------------------------------------------------------+
//| Método para entrenar el modelo                                   |
//+------------------------------------------------------------------+
bool Train(matrix &datamatrix &targetconst int epochs = 10000)
  {
//--- creamos el modelo
   if(!CreateNet())
      return false;
//--- entrenamos el modelo
   for(int ep = 0ep < epochsep++)
     {
      //--- pasada directa
      if(!FeedForward(data))
         return false;
      PrintFormat("Epoch %d, loss %.5f"epresult.Loss(targetLOSS_MSE));
      //--- pasada inversa y actualización de las matrices de pesos
      if(!Backprop(datatarget))
         return false;
     }
//--- retornamos el resultado
   return true;
  }
//+------------------------------------------------------------------+
//| Método para crear el modelo                                      |
//+------------------------------------------------------------------+
bool CreateNet()
  {
//--- inicializamos las matrices de pesos
   if(!weights1.Init(4layer1) || !weights2.Init(layer1 + 1layer2) || !weights3.Init(layer2 + 11))
      return false;
//--- rellenamos las matrices de pesos con valores aleatorios
   weights1.Random(-0.10.1);
   weights2.Random(-0.10.1);
   weights3.Random(-0.10.1);
//--- retornamos el resultado
   return true;
  }
//+------------------------------------------------------------------+
//| Método de pasada directa                                         |
//+------------------------------------------------------------------+
bool FeedForward(matrix &data)
  {
//--- comprobamos el tamaño de los datos de origen
   if(data.Cols() != weights1.Rows() - 1)
      return false;
//--- calculamos la primera capa neuronal
   matrix temp = data;
   if(!temp.Resize(temp.Rows(), weights1.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights1.Rows() - 1))
      return false;
   output1 = temp.MatMul(weights1);
//--- calculamos la función de activación
   if(!output1.Activation(tempac_func))
      return false;
//--- calculamos la segunda red neuronal
   if(!temp.Resize(temp.Rows(), weights2.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights2.Rows() - 1))
      return false;
   output2 = temp.MatMul(weights2);
//--- calculamos la función de activación
   if(!output2.Activation(tempac_func))
      return false;
//--- calculamos la tercera capa neuronal
   if(!temp.Resize(temp.Rows(), weights3.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights3.Rows() - 1))
      return false;
   result = temp.MatMul(weights3);
//--- retornamos el resultado
   return true;
  }
//+------------------------------------------------------------------+
//| Método de pasada inversa                                         |
//+------------------------------------------------------------------+
bool Backprop(matrix &datamatrix &target)
  {
//--- comprobamos la dimensionalidad de la matriz de valores objetivo
   if(target.Rows() != result.Rows() ||
      target.Cols() != result.Cols())
      return false;
//--- determinamos la desviación de los valores calculados respecto a los valores objetivo
   matrix loss = (target - result) * 2;
//--- gradiente hasta la capa anterior
   matrix gradient = loss.MatMul(weights3.Transpose());
//--- actualizamos la matriz de pesos de la última capa
   matrix temp;
   if(!output2.Activation(tempac_func))
      return false;
   if(!temp.Resize(temp.Rows(), weights3.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights3.Rows() - 1))
      return false;
   weights3 = weights3 + temp.Transpose().MatMul(loss) * lr;
//--- corregimos el gradiente de error usando la derivada de la función de activación
   if(!output2.Derivative(tempac_func))
      return false;
   if(!gradient.Resize(gradient.Rows(), gradient.Cols() - 1))
      return false;
   loss = gradient * temp;
//--- bajamos el gradiente a una capa inferior
   gradient = loss.MatMul(weights2.Transpose());
//--- actualizamos la matriz de pesos de la 2-nda capa oculta
   if(!output1.Activation(tempac_func))
      return false;
   if(!temp.Resize(temp.Rows(), weights2.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights2.Rows() - 1))
      return false;
   weights2 = weights2 + temp.Transpose().MatMul(loss) * lr;
//--- corregimos el gradiente de error usando la derivada de la función de activación
   if(!output1.Derivative(tempac_func))
      return false;
   if(!gradient.Resize(gradient.Rows(), gradient.Cols() - 1))
      return false;
   loss = gradient * temp;
//--- actualizamos la matriz de pesos de la 1-era capa oculta
   temp = data;
   if(!temp.Resize(temp.Rows(), weights1.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights1.Rows() - 1))
      return false;
   weights1 = weights1 + temp.Transpose().MatMul(loss) * lr;
//--- retornamos el resultado
   return true;
  }
//+------------------------------------------------------------------+
//| Método de prueba del modelo                                      |
//+------------------------------------------------------------------+
bool Test(matrix &datamatrix &target)
  {
//--- pasada directa con los datos de prueba
   if(!FeedForward(data))
      return false;
//--- mostramos en el log los resultados del cálculo del modelo y los valores reales
   PrintFormat("Test loss %.5f"result.Loss(targetLOSS_MSE));
   ulong total = data.Rows();
   for(ulong i = 0i < totali++)
      PrintFormat("(%.2f + %.2f + %.2f)^2 / (%.2f^2 + %.2f^2 + %.2f^2) =  Net %.2f, Target %.2f"data[i0], data[i1], data[i2],
                  data[i0], data[i1], data[i2], result[i0], target[i0]);
//--- retornamos el resultado
   return true;
  }
//+------------------------------------------------------------------+