Aprendizado de máquina

Métodos para aprendizado de máquina.

A função de ativação de uma rede neural determina o valor de saída de um neurônio dependendo do resultado da soma ponderada das entradas. A escolha da função de ativação tem um grande impacto nas capacidades e no desempenho da rede neural. Diferentes partes do modelo (camadas) podem usar diferentes funções de ativação.

MQL5 implementa não apenas todas as funções de ativação conhecidas, mas também suas derivadas. As funções derivadas permitem que os parâmetros do modelo sejam atualizados eficientemente com base no processo de treinamento.

A tarefa por trás do treinamento de uma rede neural é encontrar um algoritmo que minimize o erro na amostra de treinamento, utilizando a função de perda (loss function). O valor da função perda caracteriza a magnitude do desvio do valor previsto pelo modelo em relação ao real. Dependendo do tipo de problema que está sendo resolvido, diferentes funções de perda são usadas. Por exemplo: para um problema de regressão mean squared error (MSE), para a classificação binária binary cross-entropy (BCE).

Função

Ação

Activation

Calcula os valores da função de ativação e registra no vetor/matriz passado

Derivative

Calcula os valores da derivada da função de ativação e escreve no vetor/matriz passado

Loss

Calcula os valores da função de perda e grava no vetor/matriz passado

LossGradient

Calcula o vetor ou a matriz de gradiente da função de perda

RegressionMetric

Calcula a métrica de regressão como o erro de desvio da linha de regressão criada na matriz de dados especificada

ConfusionMatrix

Calcula a matriz de erros. O método é aplicado a um vetor de valores previstos

ConfusionMatrixMultilabel

Calcula a matriz de erros para cada rótulo. O método é aplicado a um vetor de valores previstos

ClassificationMetric

Calcula uma métrica de classificação para avaliar a qualidade dos dados previstos em relação aos dados reais. O método é aplicado a um vetor de valores previstos

ClassificationScore

Diferentemente de outros métodos na seção Aprendizado de máquina, esse método é aplicado a um vetor de valores reais em vez de um vetor de valores previstos

PrecisionRecall

Calcula os valores para traçar a curva precision-recall. Esse método, assim como o método ClassificationScore, é aplicado a um vetor de valores verdadeiros

ReceiverOperatingCharacteristic

Calcula os valores para traçar a curva Receiver Operating Characteristic (ROC). Esse método, assim como o método ClassificationScore, é aplicado a um vetor de valores verdadeiros

Exemplo:

Este exemplo mostra o treinamento de um modelo usando operações de matriz. O modelo aprende com a função (a + b + c)^2 / (a^2 + b^2 + c^2). A entrada é uma matriz de dados iniciais, na qual a, b e c estão contidos em colunas separadas. A saída do modelo retorna o resultado da função.

matrix weights1weights2weights3;               // matrizes de pesos
matrix output1output2result;                   // matrizes de saída das camadas neurais
input int layer1 = 200;                            // tamanho da 1ª camada oculta
input int layer2 = 200;                            // tamanho da 2ª camada oculta
input int Epochs = 20000;                          // número de épocas de aprendizado
input double lr = 3e-6;                            // taxa de aprendizado
input ENUM_ACTIVATION_FUNCTION ac_func = AF_SWISH// função de ativação
//+------------------------------------------------------------------+
//| Função para executar o script                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   int train = 1000;    // tamanho da amostra de treinamento
   int test = 10;       // tamanho da amostra de teste
   matrix m_datam_target;
//--- geramos uma amostra de treinamento
   if(!CreateData(m_datam_targettrain))  
      return;
//--- treinamos o modelo
   if(!Train(m_datam_targetEpochs))      
      return;
//--- geramos uma amostra de teste
   if(!CreateData(m_datam_targettest))   
      return;
//--- teste do modelo
   Test(m_datam_target);                   
  }
//+------------------------------------------------------------------+
//| Método de geração de amostras                                    |
//+------------------------------------------------------------------+
bool CreateData(matrix &datamatrix &targetconst int count)
  {
//--- inicializamos as matrizes de entrada e saída
   if(!data.Init(count3) || !target.Init(count1))
      return false;
//--- preenchemos a matriz de dados inicial com valores aleatórios
   data.Random(-1010);                     
//--- calculamos os valores-alvo para a amostra de treinamento
   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 o resultado
   return true;
  }
//+------------------------------------------------------------------+
//| Método de treinamento modelo                                     |
//+------------------------------------------------------------------+
bool Train(matrix &datamatrix &targetconst int epochs = 10000)
  {
//--- criamos o modelo
   if(!CreateNet())
      return false;
//--- treinamos o modelo
   for(int ep = 0ep < epochsep++)
     {
      //--- propagação
      if(!FeedForward(data))
         return false;
      PrintFormat("Epoch %d, loss %.5f"epresult.Loss(targetLOSS_MSE));
      //--- retropropagação e atualização das matrizes de pesos
      if(!Backprop(datatarget))
         return false;
     }
//--- retornamos o resultado
   return true;
  }
//+------------------------------------------------------------------+
//| Método de criação do modelo                                      |
//+------------------------------------------------------------------+
bool CreateNet()
  {
//--- inicializamos as matrizes de peso
   if(!weights1.Init(4layer1) || !weights2.Init(layer1 + 1layer2) || !weights3.Init(layer2 + 11))
      return false;
//--- preenchemos as matrizes de peso com valores aleatórios
   weights1.Random(-0.10.1);
   weights2.Random(-0.10.1);
   weights3.Random(-0.10.1);
//--- retornamos o resultado
   return true;
  }
//+------------------------------------------------------------------+
//| Método de propagação                                             |
//+------------------------------------------------------------------+
bool FeedForward(matrix &data)
  {
//--- verificamos o tamanho dos dados de entrada
   if(data.Cols() != weights1.Rows() - 1)
      return false;
//--- calculamos a primeira camada neural
   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 a função de ativação
   if(!output1.Activation(tempac_func))
      return false;
//--- calculamos a segunda camada neural
   if(!temp.Resize(temp.Rows(), weights2.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights2.Rows() - 1))
      return false;
   output2 = temp.MatMul(weights2);
//--- calculamos a função de ativação
   if(!output2.Activation(tempac_func))
      return false;
//--- calculamos a terceira camada neural
   if(!temp.Resize(temp.Rows(), weights3.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights3.Rows() - 1))
      return false;
   result = temp.MatMul(weights3);
//--- retornamos o resultado
   return true;
  }
//+------------------------------------------------------------------+
//| Método de retropropagação                                        |
//+------------------------------------------------------------------+
bool Backprop(matrix &datamatrix &target)
  {
//--- verificamos a dimensionalidade da matriz de valores-alvo
   if(target.Rows() != result.Rows() ||
      target.Cols() != result.Cols())
      return false;
//--- determinamos o desvio dos valores calculados em relação aos valores alvo
   matrix loss = (target - result) * 2;
//--- traçamos um gradiente para a camada anterior
   matrix gradient = loss.MatMul(weights3.Transpose());
//--- atualizamos a matriz de peso da última camada
   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;
//--- ajustamos o gradiente de erro pela derivada da função de ativação
   if(!output2.Derivative(tempac_func))
      return false;
   if(!gradient.Resize(gradient.Rows(), gradient.Cols() - 1))
      return false;
   loss = gradient * temp;
//--- diminuímos o gradiente para uma camada abaixo
   gradient = loss.MatMul(weights2.Transpose());
//--- atualizamos a matriz de peso da 2ª camada 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;
//--- ajustamos o gradiente de erro pela derivada da função de ativação
   if(!output1.Derivative(tempac_func))
      return false;
   if(!gradient.Resize(gradient.Rows(), gradient.Cols() - 1))
      return false;
   loss = gradient * temp;
//--- atualizamos a matriz de peso da 1ª camada 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 o resultado
   return true;
  }
//+------------------------------------------------------------------+
//| Método de teste do modelo                                        |
//+------------------------------------------------------------------+
bool Test(matrix &datamatrix &target)
  {
//--- propagação nos dados de teste
   if(!FeedForward(data))
      return false;
//--- registramos no log os resultados do cálculo do modelo e os valores verdadeiros
   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 o resultado
   return true;
  }
//+------------------------------------------------------------------+