matrix weights1, weights2, weights3; // matrizes de pesos matrix output1, output2, result; // 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_data, m_target; //--- geramos uma amostra de treinamento if(!CreateData(m_data, m_target, train)) return; //--- treinamos o modelo if(!Train(m_data, m_target, Epochs)) return; //--- geramos uma amostra de teste if(!CreateData(m_data, m_target, test)) return; //--- teste do modelo Test(m_data, m_target); } //+------------------------------------------------------------------+ //| Método de geração de amostras | //+------------------------------------------------------------------+ bool CreateData(matrix &data, matrix &target, const int count) { //--- inicializamos as matrizes de entrada e saída if(!data.Init(count, 3) || !target.Init(count, 1)) return false; //--- preenchemos a matriz de dados inicial com valores aleatórios data.Random(-10, 10); //--- 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 / X2, 0)) return false; //--- retornamos o resultado return true; } //+------------------------------------------------------------------+ //| Método de treinamento modelo | //+------------------------------------------------------------------+ bool Train(matrix &data, matrix &target, const int epochs = 10000) { //--- criamos o modelo if(!CreateNet()) return false; //--- treinamos o modelo for(int ep = 0; ep < epochs; ep++) { //--- propagação if(!FeedForward(data)) return false; PrintFormat("Epoch %d, loss %.5f", ep, result.Loss(target, LOSS_MSE)); //--- retropropagação e atualização das matrizes de pesos if(!Backprop(data, target)) return false; } //--- retornamos o resultado return true; } //+------------------------------------------------------------------+ //| Método de criação do modelo | //+------------------------------------------------------------------+ bool CreateNet() { //--- inicializamos as matrizes de peso if(!weights1.Init(4, layer1) || !weights2.Init(layer1 + 1, layer2) || !weights3.Init(layer2 + 1, 1)) return false; //--- preenchemos as matrizes de peso com valores aleatórios weights1.Random(-0.1, 0.1); weights2.Random(-0.1, 0.1); weights3.Random(-0.1, 0.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(temp, ac_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(temp, ac_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 &data, matrix &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(temp, ac_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(temp, ac_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(temp, ac_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(temp, ac_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 &data, matrix &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(target, LOSS_MSE)); ulong total = data.Rows(); for(ulong i = 0; i < total; i++) PrintFormat("(%.2f + %.2f + %.2f)^2 / (%.2f^2 + %.2f^2 + %.2f^2) = Net %.2f, Target %.2f", data[i, 0], data[i, 1], data[i, 2], data[i, 0], data[i, 1], data[i, 2], result[i, 0], target[i, 0]); //--- retornamos o resultado return true; } //+------------------------------------------------------------------+ |