Este artigo foi traduzido por máquina.

Execução de teste

Mergulhe nas redes neurais

James McCaffrey

Baixar o exemplo de código

James McCaffreyUma rede neural artificial (chamada geralmente apenas uma rede neural) é uma abstração vagamente modelada em sinapses e neurônios biológicos. Embora redes neurais têm sido estudados ao longo de décadas, muitas implementações de código de rede neural na Internet são não, na minha opinião, explicou muito bem. Na coluna deste mês, vou explicar o que são redes neurais artificiais e apresentar código c# que implementa uma rede neural.

A melhor maneira de ver onde eu estou cabeças é dar uma olhada em Figura 1 e Figura 2. Uma maneira de pensar sobre redes neurais é considerá-los mecanismos de entrada-saída numéricos. A rede neural no Figura 1 tem três entradas rotuladas 0 x, 1 x e x 2, com valores 1.0, 2.0 e 3.0, respectivamente. A rede neural tem duas saídas denominadas y0 e y1, com valores de 0,72 e 0.88, respectivamente. A rede neural no Figura 1 tem uma camada de neurônios ocultos chamados e pode ser descrita como uma rede feedforward três camadas, totalmente conectadas, com três entradas, duas saídas e quatro neurônios ocultos. Infelizmente, a terminologia de rede neural varia um pouco. Neste artigo, vou geralmente — mas não sempre — use a terminologia descrita na rede neural excelente FAQ em bit.ly/wfikTI.

Neural Network Structure
Figura 1 estrutura de rede Neural

Neural Network Demo Program

Figura 2 programa de demonstração de rede Neural

Figura 2 mostra a saída produzida pelo programa de demonstração apresentado neste artigo. A rede neural utiliza uma função sigmóide ativação e uma função de ativação tanh. Essas funções são sugeridas pelas duas equações com o phi letras gregas em Figura 1. As saídas produzidas por uma rede neural dependem dos valores de um conjunto de pesos numéricos e preconceitos. Neste exemplo, há um total de 26 pesos e preconceitos com valores 0,10, 0,20... -5.00. Depois que os valores de peso e preconceito são carregados na rede neural, o programa de demonstração carrega os três valores de entrada (1.0, 2.0, 3.0) e, em seguida, executa uma série de cálculos como sugerido por mensagens sobre as somas oculto para a saída e os montantes de entrada oculto. O programa de demonstração conclui exibindo os valores de dois saída (0,72, 0.88).

Vamos levá-lo através do programa que produziu a saída mostrada na Figura 2. Esta coluna supõe que você tem habilidades de programação intermediárias, mas não assuma que você sabe alguma coisa sobre redes neurais. O programa de demonstração é codificado usando a linguagem c#, mas você não deve ter problemas refatorar o código demo para outro idioma, como Visual Basic.NET ou Python. O programa apresentado neste artigo é essencialmente um tutorial e uma plataforma para experimentação; não diretamente resolve qualquer problema prático, por isso vou explicar como você pode expandir o código para resolver problemas significativos. Eu acho que você vai encontrar informações muito interessantes, e algumas das técnicas de programação podem ser adições valiosas para seu conjunto de habilidades de codificação.

Modelagem de uma rede Neural

Conceitualmente, redes neurais artificiais são modeladas sobre o comportamento das redes neurais biológicas reais. Em Figura 1 os círculos representam neurônios onde ocorre o processamento e as setas representam o fluxo de informações e valores numéricos chamados pesos. Em muitas situações, os valores de entrada são copiados diretamente em neurônios entrados sem qualquer ponderação e emitidos diretamente sem qualquer processamento, para a primeira ação real ocorre em neurônios do camada oculta. Suponha que valores de entrada 1.0, 2.0 e 3.0 são emitidos pelos neurônios entrados. Se você examinar Figura 1, você pode ver uma seta que representa um valor de peso entre cada um dos três neurônios entrados e cada um dos quatro neurônios ocultos. Suponha que os três peso setas apontando mostrado no topo neurônio oculto são nomeado w00, w10 e w20. Nessa notação o primeiro índice representa o índice do neurônio de entrada de fonte e o segundo índice representa o índice do neurônio destino ocultado. Neurônio processamento ocorre em três etapas. Na primeira etapa, uma soma ponderada é calculada. Suponha que w00 = 0.1, w10 = 0.5 e w20 = 0,9. É a soma ponderada para o neurônio oculto top (1.0)(0.1) + (2.0)(0.5) + (3.0)(0.9) = 3.8. A segunda etapa do processamento é adicionar um valor de diferença. Suponha que o valor de diferença é 2.0; então a soma ponderada ajustada se torna 3.8 + (2.0) = 1,8. O terceiro passo é aplicar uma função de ativação à soma ponderada ajustada. Suponha que a função de ativação é a função sigmóide definida por 1.0 / (1.0 * Exp(-x)), onde Exp representa a função exponencial. A saída do neurônio oculto se torna 1.0 / (1.0 * Exp(-1.8)) = 0,86. Essa saída, então, torna-se parte da soma ponderada de entrada em cada um dos neurônios da camada de saída. Em Figura 1, este processo de três etapas é sugerido pela equação com a letra grega phi: somas ponderadas (xw) são computadas, um viés (b) é adicionado e uma função de ativação (phi) é aplicada.

Afinal de contas oculto neurônio valores foram computados, saída camada neurônio valores são calculados da mesma forma. A função de ativação usada para calcular valores de neurônio de saída podem ser a mesma função usada ao calcular os valores de neurônio oculto, ou uma função de ativação diferente pode ser usada. O programa de demonstração mostrado em execução Figura 2 usa a função tangente hiperbólica como a função de ativação de oculto para a saída. Após todos os neurônio de camada de saída valores computados, na maioria das situações, esses valores não são ponderados ou processados, mas são simplesmente emitidos como os valores de saída final da rede neural.

Estrutura interna

A chave para entender a implementação de rede neural apresentada aqui, deve examinar atentamente Figura 3, que, à primeira vista, pode parecer extremamente complicado. Mas o urso com mim — a figura é não quase tão complexa como pode aparecer pela primeira vez. Figura 3 mostra um total de oito arrays e duas matrizes. A primeira matriz é denominada this.inputs. Esta matriz contém os valores de entrada de rede neural, 1.0, 2.0 e 3.0 neste exemplo. Em seguida vem o conjunto de valores que são usados para calcular valores em camada oculta chamada de peso. Estes pesos são armazenados em uma matriz de 3 x 4 rotulada i-h pesos onde a i-h significa entrada oculto. Observe na Figura 1 que a rede neural demo tem quatro neurônios ocultos. A matriz de pesos de i-h tem um número de linhas iguais ao número de entradas e um número de colunas iguais ao número de neurônios ocultos.


Neural Network Internal Structure

Figura 3 Rede Neural estrutura interna

A matriz identificado como somas de i-h é uma matriz zero usado para computação. Observe que o comprimento do i-h somas matriz será sempre o mesmo que o número de neurônios ocultos (quatro, neste exemplo). Em seguida vem uma matriz rotulada preconceitos i-h. Vieses de rede neural são pesos adicionais usados para calcular os neurônios da camada oculta e saída. O comprimento da matriz i-h preconceitos será o mesmo que o comprimento da matriz somas i-h, que por sua vez é o mesmo que o número de neurônios ocultos.

A matriz identificado como saídas i-h é um resultado intermediário e os valores de nessa matriz são usados como entradas para a próxima camada. A matriz de somas i-h tem comprimento igual ao número de neurônios ocultos.

Em seguida vem uma matriz identificado como pesos de h-o que representa a h-o escondido para saída. Aqui a matriz de pesos de h-o tem tamanho 4 x 2 porque existem quatro neurônios ocultos e duas saídas. A matriz de somas de h-o, a matriz de vieses de h-o e a matriz de this.outputs têm comprimentos iguais ao número de saídas (dois, neste exemplo).

A matriz identificado como pesos na parte inferior da Figura 3 detém todos os pesos de entrada oculto e escondido para saída e preconceitos. Neste exemplo, o comprimento da matriz de pesos é (3 * 4) + 4 + (4 * 2) + 2 = 26. Em geral, se Ni é o número de valores de entrada, Nh é o número de neurônios ocultos e não é o número de saídas, então o comprimento da matriz de pesos será Nw = (Ni * Nh) + Nh + (Nh * não) + n.

As saídas de computação

Depois foram criados os oito conjuntos e duas matrizes descritos na seção anterior, uma rede neural pode calcular sua saída com base em suas entradas, pesos e preconceitos. O primeiro passo é copiar valores de entrada para a matriz de this.inputs. O próximo passo é atribuir valores para a matriz de pesos. Para efeitos de uma demonstração que você pode usar qualquer valores de peso que você gosta. Em seguida, valores da matriz de pesos são copiados para a matriz de pesos de i-h, a matriz de preconceitos i-h, a matriz de pesos de h-o e a matriz de vieses de h-o. Figura 3 deve esclarecer esta relação.

Os valores na matriz i-h somas são computados em duas etapas. O primeiro passo é calcular os montantes ponderados pela multiplicação dos valores na matriz de entradas pelos valores na coluna apropriada da matriz de pesos de i-h. Por exemplo, a soma ponderada de neurônio oculto [3] (onde eu estou usando a indexação baseado em zero) usa cada entrada de valor e os valores na coluna [3] da matriz de pesos de i-h: (1.0)(0.4) + (2.0)(0.8) + (3.0)(1.2) = 5.6. A segunda etapa quando computação i-h somar valores é adicionar cada valor de diferença para o atual valor de soma de i-h. Por exemplo, porque i-h vieses [3] tem valor -7.0, o valor das somas i-h [3] se torna 5.6 + (-7.0) = 1,4.

Depois que todos os valores na matriz i-h montantes foram calculados, a função de ativação entrada oculto é aplicada a esses montantes para produzir os valores de saída entrada oculto. Há várias funções de ativação possíveis. A função de ativação mais simples é chamada a função de passo, que simplesmente retorna 1.0 para qualquer valor de entrada maior que zero e retorna 0,0 para qualquer entrada valor menor ou igual a zero. Outra função de ativação comum e a utilizada neste artigo, é a função sigmóide, que é definida como f (x) = 1.0 / (1.0 * Exp(-x)). O gráfico da função sigmóide é mostrado na Figura 4.

The Sigmoid Function
Figura 4 A função sigmóide

Observe que a função sigmóide retorna um valor no intervalo estritamente maior que zero e estritamente menor que um. Neste exemplo, se o valor de i-h soma [3] após foi adicionado o valor de diferença é 1,4, em seguida, o valor de i-h saídas [3] se torna 1.0 / (1.0 * Exp(-(-1.4))) = 0,20.

Depois de tem sido computados todos os valores de neurônio de saída entrada oculto, esses valores servem como as entradas para os cálculos de neurônio de camada oculta para saída. Estes cálculos funcionam da mesma maneira como os cálculos de entrada oculto: são calculados montantes ponderados preliminares, preconceitos são adicionados e, em seguida, é aplicada a uma função de ativação. Neste exemplo, utilizo a função tangente hiperbólica, abreviada como tanh, para a função de ativação de oculto para a saída. Função tanh está intimamente relacionada com a função sigmóide. O gráfico da função tanh tem uma curva em forma de s semelhante à função sigmóide, mas tanh retorna um valor no intervalo (-1,1) em vez de no intervalo (0,1).

Combinação de pesos e preconceitos

Todas as implementações de rede neural que vi na Internet não mantêm peso separado e matrizes de ajuste, mas em vez disso, combinar pesos e preconceitos na matriz de pesos. Como isso é possível? Recordar que o cálculo do valor da entrada oculto neurônio [3] se assemelhava (i0 * w03) + (i1 * PE12) + (i2 * w23) + b3, onde i0 é o valor de entrada [0], w03 é o peso para a entrada [0] e neurônio [3] e b3 é o valor de diferença para neurônio oculto [3]. Se você cria uma entrada adicional, falsa [4] que tem um valor fictício de 1.0, e se torna uma linha adicional de pesos que mantêm os valores de ajuste e, em seguida, o cálculo descrito anteriormente: (i0 * w03) + (i1 * PE12) + (i2 * w23) + (i3 * w33), onde i3 é o valor de entrada 1.0 fictício e w33 é o viés. O argumento é que essa abordagem simplifica o modelo de rede neural. Eu discordo. Na minha opinião, combinar pesos e preconceitos faz um modelo de rede neural, mais difícil de compreender e mais propenso a implementar. No entanto, aparentemente eu sou o único autor que parece ter esta opinião, assim você deve fazer sua própria decisão de design.

Implementação

Implementei a rede neural mostrada na figuras 1, 2 e 3 usando o Visual Studio 2010. Criei um aplicativo de console c# chamado NeuralNetworks. Na janela Solution Explorer I direito-estalou no arquivo Program. CS e rebatizou a NeuralNetworksProgram.cs, que também mudou o nome de classe de modelo-gerado para NeuralNetworksProgram. A estrutura geral do programa, com a maioria das declarações de WriteLine removidas, é mostrada na Figura 5.

Figura 5 estrutura de programa de rede Neural

using System;
namespace NeuralNetworks
{
  class NeuralNetworksProgram
  {
    static void Main(string[] args)
    {
      try
      {
        Console.WriteLine("\nBegin Neural Network demo\n");
        NeuralNetwork nn = new NeuralNetwork(3, 4, 2);
        double[] weights = new double[] {
          0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2,
          -2.0, -6.0, -1.0, -7.0,
          1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0,
          -2.5, -5.0 };
        nn.SetWeights(weights);
        double[] xValues = new double[] { 1.0, 2.0, 3.0 };
        double[] yValues = nn.ComputeOutputs(xValues);
        Helpers.ShowVector(yValues);
        Console.WriteLine("End Neural Network demo\n");
      }
      catch (Exception ex)
      {
        Console.WriteLine("Fatal: " + ex.Message);
      }
    }
  }
  class NeuralNetwork
  {
    // Class members here
    public NeuralNetwork(int numInput, int numHidden, int numOutput) { ...
}
    public void SetWeights(double[] weights) { ...
}
    public double[] ComputeOutputs(double[] xValues) { ...
}
    private static double SigmoidFunction(double x) { ...
}
    private static double HyperTanFunction(double x) { ...
}
  }
  public class Helpers
  {
    public static double[][] MakeMatrix(int rows, int cols) { ...
}
    public static void ShowVector(double[] vector) { ...
}
    public static void ShowMatrix(double[][] matrix, int numRows) { ...
}
  }
} // ns

Eliminei todos os gerados pelo modelo usando instruções exceto para aquele referenciar o namespace System. Na função Main, depois de exibir uma mensagem de início, eu instanciar um objeto de NeuralNetwork chamado nn com três entradas, quatro neurônios ocultos e duas saídas. Em seguida, atribuir 26 pesos arbitrários e propensões a uma matriz chamada pesos. Eu carregar os pesos para o objeto de rede neural usando um método chamado SetWeights. Atribuir valores 1.0, 2.0 e 3.0 a uma matriz chamada xValues. Eu uso o método ComputeOutputs para carregar os valores de entrada para a rede neural e determinar as saídas resultantes, que eu buscar em uma matriz chamada yValues. O demo conclui exibindo os valores de saída.

A classe NeuralNetwork

Inicia a definição da classe NeuralNetwork:

class NeuralNetwork
{
  private int numInput;
  private int numHidden;
  private int numOutput;
...

Conforme explicado nas seções anteriores, a estrutura de uma rede neural é determinada pelo número de valores de entrada, o número de neurônios da camada oculta e o número de valores de saída. A definição de classe continua como:

private double[] inputs;
private double[][] ihWeights; // input-to-hidden
private double[] ihSums;
private double[] ihBiases;
private double[] ihOutputs;
private double[][] hoWeights;  // hidden-to-output
private double[] hoSums;
private double[] hoBiases;
private double[] outputs;
...

Estes sete matrizes e duas matrizes correspondem as mostradas na Figura 3. Posso usar um prefixo de ih para dados de entrada para o oculto e um ho do prefixo para dados ocultos para a saída. Lembre-se que os valores na matriz ihOutputs servem as entradas para os cálculos de camada de saída, assim nomear esta matriz precisamente é um pouco problemático.

Figura 6 mostra como o Construtor da classe NeuralNetwork é definido.

Figura 6 O construtor da classe NeuralNetwork

public NeuralNetwork(int numInput, int numHidden, int numOutput)
{
  this.
numInput = numInput;
  this.
numHidden = numHidden;
  this.
numOutput = numOutput;
  inputs = new double[numInput];
  ihWeights = Helpers.MakeMatrix(numInput, numHidden);
  ihSums = new double[numHidden];
  ihBiases = new double[numHidden];
  ihOutputs = new double[numHidden];
  hoWeights = Helpers.MakeMatrix(numHidden, numOutput);
  hoSums = new double[numOutput];
  hoBiases = new double[numOutput];
  outputs = new double[numOutput];
}

Depois de copiar o parâmetro de entrada valores numInput, numHidden e numOutput em seus campos de classe respectivos, cada uma das matrizes de nove membros e matrizes são alocados com os tamanhos que eu expliquei anteriormente. Eu implementar matrizes como matrizes de matrizes, em vez de usar o tipo de matriz multidimensional do c# para que você possa mais facilmente Refatorar meu código para uma linguagem que não oferece suporte a tipos de matriz multidimensional. Porque cada linha do meus matrizes deve ser alocada, é conveniente utilizar um método de auxiliar tais como MakeMatrix.

O método SetWeights aceita uma matriz de pesos e bias valores e preenche ihWeights, ihBiases, hoWeights e hoBiases. O método começa assim:

public void SetWeights(double[] weights)
{
  int numWeights = (numInput * numHidden) +
    (numHidden * numOutput) + numHidden + numOutput;
  if (weights.Length != numWeights)
    throw new Exception("xxxxxx");
  int k = 0;
...

Como explicado anteriormente, o número total de pesos e preconceitos, Nw, em um totalmente conectado feedforward rede neural é (Ni * Nh) + (Nh * não) + Nh + n. Devo fazer uma verificação simple para ver se o parâmetro de matriz de pesos tem o comprimento correto. Aqui, "xxxxxx" é um substituto de uma mensagem de erro descritiva. A seguir, inicializo um índice variável k para o início do parâmetro de matriz de pesos. Método SetWeights conclui:

for (int i = 0; i < numInput; ++i)
  for (int j = 0; j < numHidden; ++j)
    ihWeights[i][j] = weights[k++];
for (int i = 0; i < numHidden; ++i)
  ihBiases[i] = weights[k++];
for (int i = 0; i < numHidden; ++i)
  for (int j = 0; j < numOutput; ++j)
    hoWeights[i][j] = weights[k++];
for (int i = 0; i < numOutput; ++i)
  hoBiases[i] = weights[k++]
}

Cada valor no parâmetro de matriz de pesos é copiado em seqüência para ihWeights, ihBiases, hoWeights e hoBiases. Observe que valores não é copiado no ihSums ou hoSums porque essas duas matrizes de rascunho são usadas para cálculo.

As saídas de computação

O coração da classe NeuralNetwork é Método ComputeOutputs. O método é surpreendentemente simples e curto e começa:

public double[] ComputeOutputs(double[] xValues)
{
  if (xValues.Length != numInput)
    throw new Exception("xxxxxx");
  for (int i = 0; i < numHidden; ++i)
    ihSums[i] = 0.0;
  for (int i = 0; i < numOutput; ++i)
    hoSums[i] = 0.0;
...

Primeiro eu verificar para ver se o comprimento da matriz de entrada de valores de x é o tamanho correto para o objeto NeuralNetwork. Então eu zerar as matrizes de ihSums e hoSums. Se ComputeOutputs é chamado somente uma vez, então essa inicialização explícita não é necessária, mas se ComputeOutputs é chamado mais de uma vez — porque ihSums e hoSums são valores acumulados — a inicialização explícita é absolutamente necessária. É uma abordagem de design alternativo a não declarar e alocar ihSums e hoSums como membros de classe, mas em vez disso torná-los locais para o método ComputeOutputs. Método ComputeOutputs continua:

for (int i = 0; i < xValues.Length; ++i)
  this.inputs[i] = xValues[i];
for (int j = 0; j < numHidden; ++j)
  for (int i = 0; i < numInput; ++i)
    ihSums[j] += this.inputs[i] * ihWeights[i][j];
...

Os valores no parâmetro array xValues são copiados para o membro de matriz de entradas de classe. Em alguns cenários de rede neural, valores de parâmetro de entrada são normalizados, por exemplo, executando uma transformação linear para que todas as entradas são dimensionadas entre -1,0 e + 1.0, mas aqui não há normalização é executada. Em seguida, um loop aninhado calcula os montantes ponderados, conforme mostrado na figuras 1 e 3. Observe que para ihWeights de índice no modelo de formulário onde índice i é o índice de linha e índice j é o índice de coluna, é necessário ter j em loop externo. Método ComputeOutputs continua:

for (int i = 0; i < numHidden; ++i)
  ihSums[i] += ihBiases[i];
for (int i = 0; i < numHidden; ++i)
  ihOutputs[i] = SigmoidFunction(ihSums[i]);
...

Cada soma ponderada é modificada, adicionando o apropriado valor de diferença. Neste ponto, para produzir a saída mostrada na Figura 2, eu usei o método Helpers.ShowVector para exibir os valores atuais na matriz ihSums. Em seguida, aplicar a função sigmóide para cada um dos valores de ihSums e atribuir os resultados a matriz ihOutputs. Apresentarei o código para o método SigmoidFunction em breve. Método ComputeOutputs continua:

for (int j = 0; j < numOutput; ++j)
  for (int i = 0; i < numHidden; ++i)
    hoSums[j] += ihOutputs[i] * hoWeights[i][j];
for (int i = 0; i < numOutput; ++i)
  hoSums[i] += hoBiases[i];
...

Eu uso os valores computados apenas no ihOutputs e os pesos no hoWeights para calcular valores em hoSums e, em seguida, adicionar os valores apropriados de preconceito oculto para a saída. Mais uma vez, para produzir a saída mostrada na Figura 2, liguei para Helpers.ShowVector. Acabamentos de método ComputeOutputs:

for (int i = 0; i < numOutput; ++i)
    this.outputs[i] = HyperTanFunction(hoSums[i]);
  double[] result = new double[numOutput];
  this.outputs.CopyTo(result, 0);
  return result;
}

Aplico o método HyperTanFunction para o hoSums para gerar as saídas finais em classe matriz membro privado saídas. Eu copiar essas saídas para uma matriz de resultado local e usar essa matriz como um valor de retorno. Uma escolha de concepção alternativa seria implementar ComputeOutputs sem um valor de retorno, mas implementar um método público GetOutputs para que as saídas do objeto rede neural poderiam ser recuperadas.

As funções de ativação e os métodos de auxiliar

Aqui está o código para a função sigmóide utilizado para calcular as saídas de entrada oculto:

private static double SigmoidFunction(double x)
{
  if (x < -45.0) return 0.0;
  else if (x > 45.0) return 1.0;
  else return 1.0 / (1.0 + Math.Exp(-x));
}

Porque algumas implementações da função Math podem produzir estouro aritmético, verificando o valor do parâmetro de entrada é geralmente realizada. O código para a função tanh usado para computar os resultados oculto para a saída é:

private static double HyperTanFunction(double x)
{
  if (x < -10.0) return -1.0;
  else if (x > 10.0) return 1.0;
  else return Math.Tanh(x);
}

A função tangente hiperbólica retorna valores entre -1 e + 1, portanto, estouro aritmético não é um problema. Aqui o valor de entrada é verificado apenas para melhorar o desempenho.

Os métodos de utilitário estático em auxiliares de classe são apenas codificação conveniências. O método de MakeMatrix usado para alocar matrizes no Construtor NeuralNetwork aloca cada linha de uma matriz implementada como uma matriz de matrizes:

public static double[][] MakeMatrix(int rows, int cols)
{
  double[][] result = new double[rows][];
  for (int i = 0; i < rows; ++i)
    result[i] = new double[cols];
  return result;
}

Métodos ShowVector e ShowMatrix exibem os valores em uma matriz ou uma matriz para o console.Você pode ver o código para esses dois métodos no código para download que acompanha este artigo (disponível em archive.msdn.microsoft.com/mag201205TestRun).

Próximas etapas

O código apresentado aqui deve dar-lhe uma base sólida para a compreensão e experimentando com redes neurais.Você pode querer examinar os efeitos do uso de funções de ativação diferente e variar o número de entradas, saídas e neurônios da camada oculta.Você pode modificar a rede neural, tornando-o parcialmente conectado, onde alguns neurônios não estão conectados logicamente aos neurônios da camada seguinte.A rede neural apresentada neste artigo tem uma camada oculta.É possível criar mais complexas redes neurais que têm duas ou mais camadas ocultas, e você pode querer estender o código apresentado aqui para implementar essa rede neural.

Redes neurais podem ser usados para resolver uma variedade de problemas práticos, incluindo problemas de classificação.Para resolver tais problemas lá são vários desafios.Por exemplo, você deve saber como codificar dados não-numéricos e como treinar uma rede neural para encontrar o melhor conjunto de pesos e preconceitos.Vou apresentar um exemplo do uso de redes neurais para a classificação em um artigo futuro.

Dr. James McCaffrey trabalha para a Volt Information Sciences Inc., onde gerencia o treinamento técnico para engenheiros de software que trabalham no campus de Redmond, Washington, da Microsoft. Ele trabalhou em vários produtos Microsoft, incluindo o Internet Explorer e o MSN Busca. Ele é o autor de ".NET Test Automation Recipes"(Apress, 2006) e pode ser alcançado em jammc@microsoft.com.

Obrigado aos seguintes especialistas técnicos da Microsoft para revisão deste artigo: Dan Liebling e Anne Loomis Thompson