Criação de uma rede neural em NTL +

Introdução

As redes neurais artificiais - são modelos matemáticos e as suas implementações de software ou hardware são construídos sobre o princípio da organização e funcionamento das redes neurais biológicas - redes de células nervosas (neurônios) do cérebro.

Atualmente, as redes neurais são usadas amplamente em muitas tarefas de reconhecimento, classificação, memória associativa, determinando padrões, prevendo etc.

Ao fim de trabalhar com redes neurais existem produtos matemáticos separados e módulos adicionais para os principais pacotes de software matemáticos que fornecem amplas capacidades de construção de redes de diferentes tipos e configurações.

Nós, por outro lado, tentamos criar nossa própria rede neural a partir do zero, por meio da NTL + linguagem e tentar ao mesmo tempo as suas capacidades de programação orientada a objetos.

Escolhendo uma tarefa

Neste artigo, vamos verificar a hipótese de que em base de barras passadas é possível prever com certa probabilidade, o tipo do seguinte barra: subindo ou caindo.

Esta tarefa está relacionada com os de classificação. Temos também uma vasta informação histórica sobre os instrumentos financeiros à nossa disposição, o que permite usar esses dados históricos para obter (especialista) saída desejada. Devido a isso, vamos criar uma rede baseada em percepção multi-camada .

Agora, vamos tentar criar uma rede que prevê, com base em preços de fechamento das k barras, o tipo do seguinte barra. Se o seu preço de fechamento for superior ao preço de fechamento da barra anterior, assumimos a saída desejada para ser 1 (o preço subiu). Em outros casos, vamos supor que a saída desejada é 0 (o preço não mudou ou caiu).

Construindo a rede

Em geral, um percepção multi-camada tem uma camada de entrada, uma ou várias camadas ocultas e uma camada de saída. Tendo uma única camada oculta é suficiente para transformar as entradas de tal forma a dividir linearmente a entrada. Usando mais camadas escondidas, muitas vezes provoca diminuição significativa da velocidade de formação de uma rede sem qualquer vantagem notável na qualidade da aprendizagem.

xVamos resolver em uma rede com uma camada de entrada, uma oculta e uma camada de saída. A figura a seguir mostra a arquitetura de nossa rede em termos gerais.1 - xn - inputs (valores de fechamento), wi,j -pesos das arestas vindo de i-node e vai j-node ; y1 - ym neurones de camadas escondidas, o1 - ok saidas de network.


Além disso, há entradas na rede de polarização. Uso desses insumos fornece a capacidade de nossa rede para mudar a função de ativação ao longo do eixo-x, assim, não só a rede mudar a inclinação da função de ativação, mas fornecer seu deslocamento linear.

1. Gráfico da função de ativação at = 1
2. Gráfico da função de ativação at =2 and = 1
3. Gráfico da função de ativação com a mudança at =2, = 1 and = 1

O valor para cada nó da rede será calculado de acordo com a fórmula:
o número de nódulos na camada anterior. , onde f(x) - função de ativação en

Funções de ativação

A activação da função calcula o sinal de saída, depois de passar recebida do acumulador. Neurónio artificial é geralmente representada como uma função não-linear de um único argumento. Na maioria das vezes são utilizadas as seguintes funções de ativação.

Função Fermi (sigmóide exponencial):


Sigmóide Racional:


Tangente Hiperbólica:


A fim de calcular as saídas de cada camada, sigmóide racional foi escolhido porque o seu cálculo leva menos tempo do processador.

Processo de treinamento da rede

Para treinar a nossa rede, vamos implementar o método de propagação de volta. Este método é um algoritmo iterativo que é usado para minimizar o erro de trabalho de um perceptron multi-camada. A ideia fundamental do algoritmo: depois de calcular os resultados da rede, os ajustamentos para cada nó e erro ω para cada aresta são calculadas, pelo que o cálculo de erro vai na direção de saídas de rede para suas entradas. Em seguida, a correção dos pesosω ocorre de acordo com os valores de erros calculados. Este algoritmo impõe a única exigência sobre a função de ativação - deve ser diferenciada. Sigmoids e tangente hiperbólica cumprem este requisito.

Agora, para realizar o processo de formação, temos a seguinte seqüência de passos:

  1. Inicialize os pesos de todas as arestas com valores aleatórios pequenos
  2. Calcule ajustes para todas as saídas da rede
    , onde oj - saída calculada da rede, tj - valor esperado (factual)
  3. Para cada nó, exceto para a última calculamos o ajuste de acordo com a fórmula
    , onde ωj,k pesos nas extremidades provenientes do nó para o qual é calculado o ajuste e ajustamentos calculados para os nodos situados mais perto da camada de saída.
  4. Calcule o ajuste para cada extremidade da rede:
    , onde oi saída calculada do nó a partir do qual a borda vem. O erro é calculado para este ponta e -ajuste calculado para o nó ao qual a borda especificada vem.
  5. Valores peso correto para todas as bordas:
  6. Repita os passos 2-5 para todos os exemplos de treinamento ou até que o critério conjunto de qualidade de aprendizagem é cumprida

Preparação dos dados de entrada

É necessário preparar os dados de entrada para executar processo de formação da rede, os dados de entrada de alta qualidade tem um impacto significativo sobre o trabalho da rede e a velocidade de estabilização seus coeficientes ω, i.e. no próprio processo de formação.

Todos os vectores de entrada são recomendados para ser normalizados, de modo a que os seus componentes se encontram no intervalo [0, 1] ou [-1, 1]. A normalização faz com que todos os vetores de entrada proporcionam no processo de formação da rede, portanto, procedimento de treinamento correto seja alcançado.

Nós vamos normalizar nossos vetores de entrada - transformar os valores de seus componentes para o intervalo [0, 1], para fazer isso, vamos aplicar a fórmula:

Preços de fechamentos das barras serão utilizados como componentes do vector. Aqueles com índices [n + k, n +1] devem ser alimentados como saídas, onde k - dimensão do vetor de entrada. Iremos determinar o valor desejado com base na barra de ordem n. Vamos formar o valor em razão da seguinte lógica: se o preço de fechamento para a barra de n-th é superior ao preço de fechamento do n +1 barra (o preço subiu), vamos definir a saída desejada a 1, em caso do preço caiu ou não mudar, vamos definir o valor como 0;

As barras envolvidas na formação de cada conjunto são destacadas em amarelo na figura, a barra que é usado para determinar o valor desejado é realçada em laranja.

A seqüência de dados fornecidos também afeta o processo de formação. O processo de treinamento acontece estável se todos os vetores de entrada correspondem a 1 e 0 são alimentados de maneira uniforme.

Além disso, vamos formar um conjunto separado de dados que são usados para a avaliação da eficácia de nossa rede. A rede não vai ser treinado sobre esses dados e só serão utilizados para o cálculo do erro com o método dos mínimos quadrados. Nós vamos adicionar 10% dos exemplos iniciais de um conjunto de dados de teste. Como resultado, usaremos 90% dos exemplos para a formação e 10% para o ensaio.

Função, calculando o erro com o método dos mínimos quadrados, fica assim:
,
onde -sinal de saída da rede e - valor desejado do sinal de saída.

Agora vamos examinar o código de script, preparando-se vetores de entrada para a nossa rede neural.

Vamos considerar classe DataSet - conjunto de dados. A classe inclui:.

  • Matriz de vetores de valores de entrada - entrada
  • Valor de saída Formado - Saída
  • 'Método Normalização '- Normalização dos dados
  • Método 'OutputDefine' - determinação do valor real sobre a relação de preços
  • Método 'AddData "- valores de gravação na matriz vetor de entrada e variável valor real
  • Método 'Arquivização' - a coleta de dados na matriz comum para a gravação posterior no arquivo
class DataSet { array <double> input(inputVectorSize); double output; //Normalization void Normalize() { double min = input[0]; double max = input[0]; //Finding minimum and maximum values for(uint i=0;i<input.length();i++) { if(input[i]>max) max=input[i]; if(input[i]<min) min=input[i]; } //Normalizing data for(uint i=0;i<input.length();i++) { //If min==max, setting all values to 0 if(max-min<0.000005) { input[i] = 0; } else { input[i]=(input[i]-min)/(max-min); } } } //Calculating the output void OutputDefine() { //If the price goes up, output is set to 1. if(input[inputVectorSize-1]<output) { output=1; } //If the price goes down or does not change, output is set to 0 else { output=0; } } //Splitting 'rawInput' array into two parts: input array and output value void AddData(array <double> rawInput) { //If the sizes of the arays don't match, we show a message. if(rawInput.length()!=uint(inputVectorSize+1)) { System.Print("Wrong input array size"); } //Writing to the 'input' array and 'output' variable for(int i=0;i<inputVectorSize;i++) { input[i]=rawInput[i]; } output=rawInput[inputVectorSize]; } // Merging the 'input' array and 'output' variable into one array array<double> To_file() { array<double> temp(inputVectorSize+1); for(int i=0;i<inputVectorSize;i++) { temp[i]=input[i]; } temp[inputVectorSize]=output; return temp; } }

Agora vamos examinar o código do programa, usado a função Run () e realizar a seguinte seqüência de ações:

  • Carregando todos os dados históricos que está disponível no terminal para uma matriz interior. O carregamento é realizado para o símbolo e os prazos para que o gráfico atual é exibida.
  • Corte a matriz bar para o tamanho que é n vezes do vetor de entrada + valor de saída
  • Formando as matrizes de vetores de entrada; normalizar estes vectores; determinar o valor desejado 0 ou 1
  • Formando a matriz de vectores de entrada, onde os vectores ordenados correspondentes a 0 e um alternativo, sucessivamente
  • Gravando a parte principal da matriz com os vectores de entrada ordenados no ficheiro com os dados de gravação e a parte restante dos dados na matriz para o teste e, subsequentemente, com o método de estimativa de mínimos quadrados.
int Run() { // The array that holds closing prices of all loaded bars array <double> data (Chart.Bars-1); // Writing data to array 'data' for(int i=1; i < Chart.Bars;i++) { data[i-1]=Close[i]; } // Truncating excessive data that can't form the whole set data.resize((data.length/(inputVectorSize+1))*(inputVectorSize+1)); int num=0; // The array is for holding all input vectors array<DataSet> sets(data.length/(inputVectorSize+1)); array <double> temp(inputVectorSize+1); // The array is for holding input vectors in the correct order array <DataSet> alternation; // Forming elements in array 'sets': normalizing each vector and calculating output (0 or 1) for(int i=data.length-1;i>=0;i-=(inputVectorSize+1)) { for(int j=0;j<inputVectorSize+1;j++) { temp[j]=data[i-j]; } sets[num].AddData(temp); sets[num].OutputDefine(); sets[num].Normalize(); num++; } // Forming 'alternation' array, where all the sets are sorted, so that they go 1,0,1,0 etc. uint len = sets.length; for(uint i=0;i<len;i++) { for(uint j=0;j<sets.length;j++) { if(sets[j].output==0 && state==1) { alternation.insertLast(sets[j]); sets.removeAt(j); state = 0; break; } if(sets[j].output==1 && state==0) { alternation.insertLast(sets[j]); sets.removeAt(j); state = 1; break; } } } // The file for writing data for training file f; f.Open("data.txt",fmWrite|fmText); // Calculating the number of sets with data for training and testing data uint datasets = int(alternation.length()*0.9); uint testsets = alternation.length() - datasets; System.Print("datasets SETS = "+datasets); // Writing data for training to the file for(uint i=0;i<datasets;i++) { for(int j=0;j<inputVectorSize+1;j++) { f.WriteDouble(alternation[i].To_file()[j]); } } f.Close(); System.Print("testsets SETS = "+testsets); // Data for testing // Writing to the file file t; t.Open("test.txt",fmWrite|fmText); for(uint i=0;i<testsets;i++) { for(int j=0;j<inputVectorSize+1;j++) { t.WriteDouble(alternation[i+datasets].To_file()[j]); } } t.Close(); return(0); }

Você também precisa declarar a variável int estado = 0 global neste arquivo, a variável é necessária para a alternância de vetores de entrada.

Criação de classes de rede

Vamos precisar para a nossa rede:

  • uma instância da classe "camada" para conexão de entrada e as camadas ocultas da rede
  • uma instância da classe "camada" para conectar as camadas ocultas e de saída da rede
  • uma instância da classe 'net' para as camadas de ligação da nossa rede

Criando a classe "camada"

Agora, vamos precisar da classe, contendo as seguintes propriedades e métodos:

  • array 'input'para armazenar as entradas da rede
  • array 'output'para armazenar as saídas da rede
  • array 'delta' para armazenar ajustes
  • array dois dimensionais 'weights' for edges' weights
  • Metodo 'LoadInputs' para atribuir os valores especificados na matriz de entrada de insumos da camada
  • Metodo 'LoadWeights'para carregar os valores de peso da camada do disco rígido
  • Metodo 'SaveWeights' para salvar os valores de peso da camada para o disco rígido
  • construtor aloca o volume de memória necessária para as matrizes utilizadas
  • Metodo 'RandomizeWeights' - preenchendo os pesos com valores aleatórios
  • Metodo 'OutputCalculation' -calcula os valores de saída
  • Metodo 'CalculatingDeltaLast' e 'CalculatingDeltaPrevious' - calcula os valores de saída
  • Metodo 'WeightsCorrection' - corrigindo os valores de peso
  • metodo adicional de diagnostico (diagnostico) métodos para exibir informações na tela:
    • PrintInputs() - imprimir as entradas de uma camada
    • PrintOutputs() - imprimindo a saída de uma camada (é chamado após o cálculo de saída por meio de 'OutputCalculation')
    • PrintDelta() - ajustes de impressão de uma camada (deve ser chamado depois de calcular os ajustes por meio de 'CalculatingDeltaLast' ou 'CalculatingDeltaPrevious')
    • PrintWeights() - impressão de pesos ω da camada

    Vamos remover a classe criada para um arquivo separado. Além disso, este arquivo conterá também a configuração de rede: número de nós de entrada, escondida e camadas de saída. Estas variáveis foram colocados fora da classe, a fim de que possam ser utilizadas no script para a preparação de dados de entrada.

    extern int inputVectorSize = 8; // input vector extern int L1_Innersize = 8; // number of nodes in the hidden layer without bias extern int L2_Innersize= 1; // number of nodes in the output layer without bias extern double nu = 0.1; //training rate for the backpropagation method class layer { // input values array<double> input; // output values array<double> output; // output array size int outputSize=0; // weights array<array <double>> weights; // adjustments array<double> delta; // default constructor layer() { } // loading input values from array 'inp'. bool LoadInputs(array <double> inp) { if(inp.length()+1 != input.length()) { System.Print("Loading is not possible. Array sizes do not match"); return false; } for(uint i=0;i<inp.length();i++) { input[i]=inp[i]; } return true; } // loading weights from a specifies file bool LoadWeights(string filename) { file f; if(!f.Open(filename,fmRead|fmText)) { return false; } for(uint i=0;i<weights.length();i++) { for(uint j=0;j<weights[0].length();j++) { weights[i][j]=f.ReadDouble(); } } f.Close(); return true; } // loading weights to a specified file bool SaveWeights(file f) { for(uint i=0;i<weights.length();i++) { for(uint j=0;j<weights[0].length();j++) { if(!f.WriteDouble(weights[i][j])) { f.Close(); return false; } } } return true; } // constructor // inp - array of values // size - size of output array layer(array<double> inp, int size) { input = inp; input.insertLast(1); // Bias outputSize = size; //weigths array array<array<double>> temp_weights(size, array<double>(inp.length()+1)); array<double> temp_output(size); output = temp_output; weights = temp_weights; array<double> delta_temp(size); delta = delta_temp; } //randomizing weights void RandomizeWeights() { for(uint i=0;i<weights.length();i++) { for(uint j=0;j<weights[0].length;j++) { weights[i][j]=(-0.5+double(Math.Rand())/32767)*0.1; } } } // printing weights void PrintWeights() { string line; for(uint i=0;i<weights.length();i++) { line = "weights"; for(uint j=0;j<weights[0].length;j++) { line += " ["+i+"]["+j+"]="+weights[i][j]; } System.Print(line); } } // printing input values void PrintInputs() { for(uint i=0;i<input.length;i++) { System.Print("inputs["+i+"]="+input[i]); } } // print output values void PrintOutputs() { for(uint i=0;i<output.length;i++) { System.Print("outputs["+i+"]="+output[i]); } } // printing delta values void PrintDelta() { for(uint i=0;i<delta.length();i++) { System.Print("delta ["+i+"]="+delta[i]); } } // output calculation void OutputCalculation() { // temporary array to store output values array<double> a(outputSize,0); for(int k=0;k<outputSize;k++) { for(uint i=0;i<input.length();i++) { a[k]+=weights[k][i]*input[i]; } a[k]=Activation(a[k]); } output = a; } //Changing weights of the last layer void CalculatingDeltaLast(array <double> realValues) { //System.Print("delta.length()="+delta.length); if(realValues.length()!=delta.length()) { System.Print("Mismatch between array sizes"); return; } for(uint i=0;i<realValues.length();i++) { delta[i]=-output[i]*(1-output[i])*(realValues[i] - output[i]); } } //Changing weights for any layers except for the last. void CalculatingDeltaPrevious(layer &inout LayerLast) { for(uint j=0;j<LayerLast.input.length()-1;j++) { double sum = 0; for(uint k=0;k<LayerLast.output.length();k++) { sum += LayerLast.delta[k]*LayerLast.weights[k][j]; } delta[j]=output[j]*(1-output[j])*sum; } } //Changed weights void WeightsCorrection() { for(uint i=0;i<weights.length();i++) { for(uint j=0;j<weights[0].length();j++) { weights[i][j] = weights[i][j] - nu*delta[i]*input[j]; } } } }

    Precisaremos também de funções adicionais que vamos colocar fora das aulas. Estas são duas funções: normalização de um vetor de entrada e função de ativação.

    void Normalize(array<double> &inout input) { double min = input[0]; double max = input[0]; //finding minimum and maximun for(uint i=0;i<input.length();i++) { if(input[i]>max) max=input[i]; if(input[i]<min) min=input[i]; } for(uint i=0;i<input.length();i++) { if(max-min<0.000005) { input[i] = 0.0; } else { input[i]=(input[i]-min)/(max-min); } } } // Activation function double Activation(double x) { return x/(Math.Abs(x)+1); }

    Criando a classe 'net'

    Vamos precisar da classe combinando nossas camadas em uma rede conjunta, portanto tal classe deve ter:

    • Metodo 'Calculador' - ligação de nossas camadas para o cálculo da saída de rede. Este método será utilizado mais tarde para o trabalho com a rede treinada
    • Metodo 'Calcule e Aprenda ' -saídas de computação, ajustes e erros. Vamos chamar o método anterior para calcular as saídas, e para ajustes e erros que irá chamar os métodos correspondentes de cada camada
    • Metodo 'SaveNetwork' -Economizando coeficientes (pesos) da rede .
    • Method 'LoadNetwork' - Coeficientes de carga (pesos) da rede.
    class net { array <double> x(inputVectorSize); array <double> y(L1_Innersize); layer L1(x,L1_Innersize); array<double> L1_outputs(L1_Innersize); layer L2(y,L2_Innersize); //Calculating output using current weights array<double> Calculate(array <double> data, bool randomWeights) { if(data.length()!=x.length()) { System.Print("Array sizes do not match"); } x = data; Normalize(x); L1.LoadInputs(x); if(randomWeights) { L1.RandomizeWeights(); L2.RandomizeWeights(); } L1.OutputCalculation(); L2.LoadInputs(L1.output); L2.OutputCalculation(); return L2.output; } //Calculating output and changing weights void CalculateAndLearn(array <double> data, array <double> realValues, bool randomWeights) { Calculate(data, randomWeights); L2.CalculatingDeltaLast(realValues); L1.CalculatingDeltaPrevious(L2); L2.WeightsCorrection(); L1.WeightsCorrection(); } //Saving the weights of the whole network bool SaveNetwork(string filename) { file f; if(!f.Open(filename,fmWrite|fmRead|fmText)) { f.Open(filename,fmWrite|fmText); } L1.SaveWeights(f); L2.SaveWeights(f); f.Close(); return true; } //Loading all weights bool LoadNetwork(string filename) { file fn; if(fn.Open(filename,fmRead|fmText)==false) { return false; } for(uint i=0;i<L1.weights.length();i++) { for(uint j=0;j<L1.weights[0].length();j++) { L1.weights[i][j]=fn.ReadDouble(); } } for(uint i=0;i<L2.weights.length();i++) { for(uint j=0;j<L2.weights[0].length();j++) { L2.weights[i][j]=fn.ReadDouble(); } } return true; } }

    Verificamos o trabalho da rede

    Nesta subseção, vamos verificar o trabalho de nossa rede em um exemplo elementar que será usado para determinar a exatidão de classificação de vetores de entrada. Para este fim, irá usar uma rede com duas entradas, dois nós da camada oculta e uma saída. Vamos definir o parâmetro nu para 1. Os dados de entrada será representada como conjuntos alternados com os conteúdos seguintes:
    input 1,2 e o valor esperado deve ser 1
    input 2,1 e o valor esperado deve ser 0
    Eles vão ser especificados no arquivo desta forma:

    1.00000000 2.00000000 1.00000000 2.00000000 1.00000000 0.00000000

    Alimentando número diferente de conjuntos de treinamento para a entrada, podemos observar como o processo de formação da nossa rede está avançando.


    A linha vermelha no gráfico mostra os conjuntos de treinamento correspondentes a 1. A linha azul - corresponde a 0. O número de exemplos de treinamento é demitido ao longo do eixo x, eo valor calculado de rede - ao longo do eixo-y. É óbvio que, quando há alguns barras (25 ou menos) a rede não reconhece diferentes vectores de entrada, quando há mais de um entre eles - a divisão em duas classes é aparente.

    Avaliação do funcionamento da rede

    Para avaliar a eficácia do treinamento, vamos usar a função de calcular o erro com o método dos mínimos quadrados. Para isso, vamos criar o utilitário com o seguinte código e executá-lo. Vamos precisar de dois arquivos para o seu trabalho: "test.txt" - dados e valores desejados (outputs) que são utilizados na correção de erros e "NT.txt" - o arquivo com os coeficientes calculados (pesos) para o trabalho da rede .

    Este script executa a seguinte seqüência de ações:

    • cria objeto NT da classe 'net'
    • lê coeficientes (pesos) ω e possivel abri-los em NT
    • cria matrizes de entradas e saídas da rede
    • lê entradas em um loop e coloca-los em 'x' array, lê saídas e coloca-los em ordem de 'reais'
    • calcula a saída da rede, alimentando matriz 'x', como uma entrada
    • avalia errorcomo a soma dos quadrados das diferenças entre todos os valores calculados e os valores esperados (de facto)
    • quando o fim do arquivo é alcançado, exibimos o erro e terminar o trabalho do roteiro
    #include "Libraries\NN.ntl" int Run() { net NT; file f; int counter = 0; // Loading weights NT.LoadNetwork("NT.txt"); double error=0; // Declaring an array for storing culculated outputs array <double> CalculatedOutput (L2_Innersize); // Opening the file with test data if(f.Open("test.txt",fmRead|fmText)==false) { System.Print("Input data not found"); return -1; } // Array holds input values array <double> x(inputVectorSize); // Actual output array <double> reals(L2_Innersize); while(true) { for(int i=0;i<inputVectorSize;i++) { x[i]=f.ReadDouble(); if(f.IsEOF()) { System.Print("counter="+counter+"error="+0.5*error+"error/counter="+(0.5*error/counter)); return -1; } } //forming real examples for(int j=0;j<L2_Innersize;j++) { reals[j]=f.ReadDouble(); System.Print("Real exit = "+reals[j]); } CalculatedOutput = NT.Calculate(x,false); System.Print("Calculated exit = "+CalculatedOutput[0]); //calculating error for(uint i=0;i<reals.length();i++) { error+=(reals[i]-CalculatedOutput[i])*(reals[i]-CalculatedOutput[i]); } counter++; } return(0); }

    Criação de um indicador

    Vamos criar um indicador que mostra a decisão da rede sobre o próximo bar, por meio de um histograma. A lógica do trabalho do indicador é simples. O valor 0 corresponderá ao valor de queda do próximo bar, valor 1 - aumento do valor, e 0,5 - os eventos de diminuição e aumento de preço de fechamento são igualmente possíveis. Para mostrar o indicador em uma janela separada, vamos especificar #set_indicator_separate, também é necessário para determinar o arquivo onde a classe 'net' é definido, vamos incluir o arquivo na linha #include "Libraries\NN.ntl". Além disso, vamos precisar de uma variável para armazenar a saída computadorizada de rede para a entrada de dados, se houver apenas um valor de saída, então é suficiente para ter uma variável, mas a rede pode ter várias saídas, portanto, terá um array de valores: nós declará-la na linha de linhs Output Calculado(L2_Innersize);.Na função de inicialização do nosso indicador vamos especificar os parâmetros do indicador, o seu tipo, os valores de vinculação de histograma com dois buffers de valores. Também vai precisar para restaurar parâmetros da nossa rede, ou seja, carga nele todos os coeficientes de peso, calculado durante o processo de treinamento. Isso é feito por meio do método LoadNetwork (string s) de objeto NT, com o único parâmetro - o nome do arquivo que contém os coeficientes de peso. Na função Draw formamos vetor de entrada x correspondendo a preços de fechamento das barras com os índices [pos + inputVectorSize-1; pos], onde 'pos' - número do bar que calculamos o valor e dimensão "inputVectorSize" do vetor de entrada. No final, o método 'Calcular' do objeto NT é chamado. Ele retorna uma matriz de valores (se a nossa rede tem várias saídas), mas porque temos apenas uma saída, vamos usar o elemento do array com índice 0.

    #set_indicator_separate #include "Libraries\NN.ntl" double ExtMapBuffer1[]; double ExtMapBuffer2[]; int ExtCountedBars=0; net NT; array <double> CalculatedOutput (L2_Innersize); int Initialize() { Indicator.SetIndexCount(2); Indicator.SetIndexBuffer(0,ExtMapBuffer1); Indicator.SetIndexStyle(0,2,0,3,0xFF0000); Indicator.SetIndexBuffer(1,ExtMapBuffer2); Indicator.SetIndexStyle(1,2,0,3,0xFF0000); NT.LoadNetwork("NT.txt"); return(0); } int Run() { ExtCountedBars=Indicator.Calculated; if (ExtCountedBars<0) { System.Print("Error"); return(-1); } if (ExtCountedBars>0) ExtCountedBars--; Draw(); return(0); } void Draw() { int pos=Chart.Bars-ExtCountedBars-1; array <double> x(inputVectorSize); while(pos>=0) { ExtMapBuffer1[pos]=0; // forming input vector for(int i=pos+inputVectorSize-1; i>=pos; i--) { x[i-pos]=Close[i]; } ExtMapBuffer2[pos]=NT.Calculate(x,false)[0]; pos--; } }

    O diagrama acima mostra a previsão da rede da barra subseqüente. Valores 0,5-1 sugerem a maior possibilidade de que barra posterior subirá de queda. Valores 0-0,5 implicam maior possibilidade de cair em vez de subir. Valor 0,5 sugere o estado de ambivalência: o próximo barra pode ir para cima ou para baixo.

    Resumo

    As redes neurais são ferramentas poderosas para análise de dados. Este artigo abordou o processo de criação de uma rede neural, por meio de programação orientada a objetos no NTL + linguagem. O uso de programação orientada a objetos permitiu simplificar o código e tornou muito mais reutilizável nos scripts futuros. Na implementação apresentado que precisávamos para criar a camada de classe a definição de uma camada da rede neural ea classe net definição da rede em geral. Usamos a classe 'net' para o indicador, o cálculo de erros e cálculo dos pesos internos da rede. Além disso, foi apresentado como usar a rede treinada pelo exemplo do indicador de histograma que, desde a previsão da rede da mudança de preço.