Este artigo foi traduzido por máquina.

Execução de teste

Treinamento em redes de função de base radial

James McCaffrey

Baixar o código de exemplo

James McCaffrey
Uma rede de função (RBF) de base radial é um sistema de software que pode classificar os dados e fazer previsões. Redes RBF têm algumas semelhanças superficiais às redes neurais, mas são realmente muito diferentes. Uma rede RBF aceita uma ou mais entradas numéricas e gera uma ou mais saídas numéricas. Os valores de saída são determinados pelos valores de entrada, além de um conjunto de parâmetros, chamado os centróides RBF, um conjunto chamado as larguras RBF, um conjunto chamado os pesos RBF e um conjunto chamado os enviesamentos RBF.

A simplicidade da terminologia, a combinação de pesos RBF e viés valores são às vezes coletivamente referidos como os pesos. O contexto em que os pesos do termo é usado geralmente torna o significado claro. Para obter mais informações, consulte o meu artigo, "Radial base função redes para programadores" na edição de outubro da MSDN Magazine (msdn.microsoft.com/magazine/dn451445).

Ao usar uma rede RBF para classificação e predição, o desafio é encontrar um conjunto de valores para os centróides, larguras, pesos e vícios para que calculado saídas melhor coincidir com um conjunto de saídas conhecidos. Isso é chamado de treinamento da rede RBF. Embora os investigadores estudaram as redes RBF desde sua introdução em 1988, não há uma orientação muito prática que explica como implementar a formação de rede RBF. Este artigo irá apresentar e descrever uma rede RBF demo completa.

Dê uma olhada no programa de demonstração em Figura 1. O programa cria um modelo RBF que prevê as espécies de uma flor de íris ("setosa," "versicolor" ou "virginica") de quatro valores numéricos para a flor comprimento da sepal e largura e comprimento de pétala e largura. Fonte de dados do programa de demonstração é composto por 30 itens que são um subconjunto de um conjunto de benchmark de 150-item conhecido chamado dados de Iris de Fisher. Os itens de 30 dados tem sido pré-processado. Os quatro valores de x numéricos têm sido normalizados para que valores inferiores a zero médio menor que a média de comprimento ou largura e valores maiores que zero significam mais do que a média comprimento ou largura. O valor de y para a espécie tem sido codificado como (0, 0,1), (0,1,0), ou (1,0,0) para setosa, versicolor e virginica, respectivamente.

A Radial Basis Function Network Demo Program
Figura 1 função de base Radial rede programa de demonstração

O demo divide o conjunto de dados de item de 30 em um conjunto de 24-item a ser usado para treinamento. Há também uma validação seis-item definido para teste/avaliação do modelo RBF resultante. Ele instancia um RBF rede com quatro nós de entrada (uma para cada valor de entrada de dados), nós de processamento escondidos cinco e três nós de saída (uma para cada valor de dados de saída). Determinar o melhor número de nós ocultos é principalmente uma questão de tentativa e erro. A escolha de cinco na demo foi arbitrária.

Em Figura 1 você pode ver que a formação de uma rede RBF consiste de três fases. A primeira fase determina os centróides. Você pode pensar de centróides como representante x-valores selecionados a partir dos dados de treinamento. Uma rede RBF requer um centróide para cada nó oculto, então o demo tem cinco centróides. O algoritmo de treinamento seleciona os valores de x da formação de itens de dados [9], [19], [21], [20] e [4]. Em outras palavras, o primeiro centróide é (-0.362,-2.019, 0.074, 0.112).

A segunda fase do treinamento determina as larguras. Você pode pensar de larguras como valores que descrevem a distância entre os centróides. Uma rede RBF requer uma largura para cada nó escondido. O demo calcula uma única largura comum com o valor 3.3318 para todos os cinco de nós ocultos, ao invés de cinco computação separa as larguras.

A terceira fase da formação determina a RBF pesos e valores de viés. Você pode pensar de pesos e valores viés como constantes numéricas. Se uma rede RBF tem NI número de nós de entrada, número de NH de nós ocultos e nenhum número de nós de saída e, em seguida, a rede exige (NH * não) valores e sem viés de peso. Assim, porque a rede RBF demo tem um 4-5-3 precisa de arquitetura, 5 * 3 = 15 pesos e mais três polarizações, para um total de 18 pesos e valores de viés. O programa de demonstração usa a otimização de enxame de partículas (PSO) para determinar os 18 pesos e vícios.

Depois que você treinou rede RBF demo usando o conjunto de dados de treinamento 24-item, você alimentar o conjunto de dados de teste de item de seis para a rede. Neste exemplo, a rede RBF prediz corretamente as espécies de cinco os seis itens de teste, para uma precisão de classificação de 0.8333 fora.

Este artigo pressupõe que você tem avançado conhecimento de programação com c# e uma familiaridade básica com o mecanismo de entrada-processo-saída de rede de função de base radial. Esse mecanismo discutido na minha coluna de outubro. O código-fonte para o programa de demonstração é muito longo para apresentar na íntegra este artigo, mas o download de código completo está disponível em archive.msdn.microsoft.com/mag201312TestRun.

Estrutura geral do programa

Para criar o programa de demonstração, lançou o Visual Studio 2012 e criou um aplicativo de console c# chamado RadialNetworkTrain. O demo não tem significativa .NET dependências para que qualquer versão do Visual Studio deve funcionar. Depois de carregado o código do modelo, no Solution Explorer janela que renomeei o arquivo Program.cs ao RadialTrainProgram.cs e Visual Studio automaticamente renomeado mais descritivo associado classe Program. Na parte superior do código-fonte, apaguei todas as referências desnecessárias para namespaces .NET, deixando apenas a referência ao namespace System.

A estrutura geral do programa, com algumas declarações de WriteLine removidas e algumas pequenas edições, é apresentada em Figura 2. Além da classe de programa que abriga o método Main, o demo tem uma RadialNetwork classe que encapsula a criação de redes RBF e treinamento, uma classe de partículas que define um objeto de partículas para uso com o algoritmo de treinamento RBF que determina pesos e valores viés e uma classe de ajudantes que contém o utilitário exibe métodos.

Figura 2 estrutura do programa global RBF rede Demo

using System;
namespace RadialNetworkTrain
{
  class RadialTrainProgram
  {
    static void Main(string[] args)
    {
      Console.WriteLine("Begin radial basis function (RBF) network training demo");
      double[][] allData = new double[30][];
      allData[0] = new double[] { -0.784, 1.255, -1.332, -1.306, 0, 0, 1 };
      allData[1] = new double[] { -0.995, -0.109, -1.332, -1.306, 0, 0, 1 };
      // Etc.
allData[28] = new double[] { 0.904, -1.473, 1.047, 0.756, 1, 0, 0 };
      allData[29] = new double[] { 1.431, 1.528, 1.209, 1.659, 1, 0, 0 };
      Console.WriteLine("First four and last line of normalized, encoded input data:");
      Helpers.ShowMatrix(allData, 4, 3, true, true);
      double[][] trainData = null;
      double[][] testData = null;
      int seed = 8; // Gives a good demo
      GetTrainTest(allData, seed, out trainData, out testData);
      Helpers.ShowMatrix(trainData, trainData.Length, 3, true, false);
      Helpers.ShowMatrix(testData, testData.Length, 3, true, false);
      int numInput = 4;
      int numHidden = 5;
      int numOutput = 3;
      RadialNetwork rn = new RadialNetwork(numInput, numHidden, numOutput);
      Console.WriteLine("Beginning RBF training");
      int maxIterations = 100; // Max for PSO
      double[] bestWeights = rn.Train(trainData, maxIterations);
      Console.WriteLine("Evaluating RBF accuracy on the test data");
      rn.SetWeights(bestWeights);
      double acc = rn.Accuracy(testData);
      Console.WriteLine("Classification accuracy = " + acc.ToString("F4"));
      Console.WriteLine("End RBF network training demo");
    }
    static void GetTrainTest(double[][] allData, int seed,
      out double[][] trainData, out double[][] testData) { .
.
}
  }
  public class RadialNetwork
  {
    private static Random rnd = null;
    private int numInput;
    private int numHidden;
    private int numOutput;
    private double[] inputs;
    private double[][] centroids;
    private double[] widths;
    private double[][] hoWeights;
    private double[] oBiases;
    private double[] outputs;
    public RadialNetwork(int numInput, int numHidden, int numOutput) { .
.
}
    private static double[][] MakeMatrix(int rows, int cols) { .
.
}
    public void SetWeights(double[] weights) { .
.
}
    public double[] GetWeights() { .
.
}
    private double MeanSquaredError(double[][] trainData,
      double[] weights) { .
.
}
    public double Accuracy(double[][] testData) { .
.
}
    private static int MaxIndex(double[] vector) { .
.
}
    public double[] ComputeOutputs(double[] xValues) { .
.
}
    private static double[] Softmax(double[] rawOutputs) { .
.
}
    public double[] Train(double[][] trainData, int maxIterations) { .
.
}
    private void DoCentroids(double[][] trainData) { .
.
}
    private static double AvgAbsDist(double[] v1, double[] v2,
      int numTerms) { .
.
}
    private int[] DistinctIndices(int n, int range) { .
.
}
    private void DoWidths(double[][] centroids) { .
.
}
    private double[] DoWeights(double[][] trainData, int maxIterations) { .
.
}
    private static double EuclideanDist(double[] v1, double[] v2,
      int numTerms) { .
.
}
    private static void Shuffle(int[] sequence) { .
.
}
  }
  public class Particle
  {
    // Implementation here
  }
  public class Helpers
  {
    // Implementation here
  }
}

RadialNetwork de classe não é completamente tão complexa como a estrutura do programa sugere, porque a maioria dos métodos de classe são ajudantes. Trem de método executa o processo de formação de três fases por ajudantes chamadas DoCentroids, DoWidths e DoWeights. Métodos privados, AvgAbsDist e DistinctIndices são auxiliares para DoCentroids. DoWeights método usa o método privado Shuffle para itens de dados de treinamento de processo em uma ordem diferente cada vez através do algoritmo de otimização de enxame de partícula iterativa.

O coração da demo é bastante simples. Primeiro, os dados normalizados e codificados estão constituídos:

double[][] allData = new double[30][];
allData[0] = new double[] { -0.784, 1.255, -1.332, -1.306, 0, 0, 1 };
allData[1] = new double[] { -0.995, -0.109, -1.332, -1.306, 0, 0, 1 };
// Etc.
allData[28] = new double[] { 0.904, -1.473, 1.047, 0.756, 1, 0, 0 };
allData[29] = new double[] { 1.431, 1.528, 1.209, 1.659, 1, 0, 0 };

Eis os dados codificados para a simplicidade. Na maioria dos cenários seus dados serão armazenados em um arquivo de texto ou uma tabela SQL. Em seguida, os dados são divididos em subconjuntos de treinamento e teste:

double[][] trainData = null;
double[][] testData = null;
int seed = 8;
GetTrainTest(allData, seed, out trainData, out testData);

A rede RBF é instanciada:

int numInput = 4;
int numHidden = 5;
int numOutput = 3;
RadialNetwork rn = new RadialNetwork(numInput,
   numHidden, numOutput);

Como mencionado na seção anterior, o número ideal de nós de processamento oculto deve ser determinado essencialmente por tentativa e erro. A rede está treinada:

int maxIterations = 100;
double[] bestWeights = rn.Train(trainData, maxIterations);

E, finalmente, o modelo resultante é avaliado:

rn.SetWeights(bestWeights);
double acc = rn.Accuracy(testData);
Console.WriteLine("Classification accuracy = " +
  acc.ToString("F4"));

A matriz de bestWeights contém a RBF pesos e valores viés, conforme determinado pelo método de trem. SetWeights método carrega esses pesos e valores de viés. Você não precisa ter os centróides e larguras explicitamente carregadas porque esses valores foram definidos pelo método de trem.

Função de base radial rede entrada-processo-saída

Para entender o processo de formação de rede RBF, você precisa entender a entrada de rede RBF -­mecanismo de saída do processo. O diagrama na Figura 3 mostra como a rede RBF demo calcula as saídas para o item de dados de teste [1] = (0.482, 0.709, 0.452, 0.498) depois que a rede foi treinada. Os x-valores de entrada são passados para cada nó escondido. Cada nó escondido calcula sua produção local utilizando seu próprio centróide e largura.

Radial Basis Function Network ArchitectureArquitetura de rede de função de base Radial Figura 3

Por exemplo, centróide do nó escondido mais alto é (-0.362,-2.019, 0.074, 0.112) e sua largura é 3.3318. As saídas locais em cada nó oculto são usadas para determinar os valores de saída preliminar calculando uma soma ponderada das entradas, além de um valor de bias. Por exemplo, se bateriaOutput [0] representa a saída local do nó escondido 0, então a saída preliminar para o nó de saída superior é (bateriaOutput [0] * w[0][0]) + (bateriaOutput [1] * w[1][0]) + (bateriaOutput [2] * w[2][0]) + (bateriaOutput [3] * w[3][0]) + (bateriaOutput [4] * w[4][0]) + viés [0] =-12.7999.

Depois que os três valores de saída preliminar tem sido calculados, eles são convertidos para valores de saída final usando uma função softmax. A idéia é modificar os valores de saída preliminar para que os valores de saída final são entre 0.0 e 1.0 e somam a 1.0. Isso permite que os valores de saída ser vagamente interpretado como probabilidades.

Em Figura 3, os resultados finais são (0.2897, 0.6865, 0.0237). Porque o nó central tem o valor mais alto, ele é interpretado como um 1, e os outros dois valores são interpretados como 0, dando uma saída inferida de (0, 1, 0). Lembre-se os dados de teste são (0.482, 0.709, 0.452, 0.498, 0.000, 1.000, 0.000), onde os quatro primeiros valores são as entradas e os três últimos valores são os valores-alvo, assim a rede RBF faz uma previsão correta das espécies (Iris versicolor, neste caso). A pergunta agora é: Donde sim os valores para a rede RBF centróides, larguras, pesos e vícios?

Determinação de centróides de rede RBF

O método de trem da classe RadialNetwork é essencialmente um invólucro ao redor de três métodos auxiliares que fazem todo o trabalho real:

public double[] Train(double[][] trainData, int maxIterations)
{
  DoCentroids(trainData);
  DoWidths(this.centroids);
  double[] bestWeights = DoWeights(trainData, maxIterations);
  return bestWeights;
}

DoCentroids método determina x-valores representativos de entrada. Existem muitas possibilidades aqui. Uma abordagem comum é usar um algoritmo de clustering k-means ou k-medoids que iterativamente atribui e reatribui a itens de dados para que os itens de dados semelhantes são agrupados. Quando terminou, cada cluster tem um membro de dados representativos. Você pode usar estes como centróides RBF.

Uma abordagem diferente é extrair os valores de x de itens de dados de treinamento selecionados aleatoriamente. Isso é simples, mas tem o risco que mau centróides podem ser selecionados por acaso.

O programa de demonstração usa o que pode ser denominado uma leve abordagem sugerida por esse pseudocódigo de clustering:

initialize maxDistance
intialize bestIndices
loop
  select numHidden random indices into train data
  compute an estimated distance between selected data items
  if estimated distance > maxDistance then
    set maxDistance = curr distance
    set bestIndices = curr indices
  end if
end loop
fetch the x-values in train data at bestIndices
store x-values into RBF centroids

A idéia é melhor ilustrada pelo exemplo. Suponha que os dados de treinamento consistem em 24 itens mostrados em Figura 1. Mais acho que a primeira vez através do processamento de loop quatro selecionados aleatoriamente os índices são [0], [1], [2] e [3]. Estas correspondem a:

0: ( 1.537, -0.382,  1.317,  0.756)
  1: (-0.468,  2.346, -1.170, -1.048)
  2: ( 1.115,  0.164,  0.560,  0.370)
  3: ( 1.220,  0.436,  0.452,  0.241)

Estas são centróides de candidato. A idéia é obter x-valores representativos, que significa que você não quer os valores que estão próximos um do outro. Então, você calcular uma medida de distância entre estes centróides de candidato. Aqui, existem muitas abordagens possíveis. O demo estima uma distância média entre todos os pares possíveis de centróides candidato calculando uma distância média entre pares adjacentes de candidatos, em vez de computar a uma distância média entre todos os pares possíveis. Para este exemplo, ele calcula as distâncias entre candidatos [0] e [1], entre [1] e [2] e entre [2] e [3].

Uma abordagem comum a uma distância de computação é usar a distância euclidiana, que é a raiz quadrada da soma das diferenças ao quadrado entre valores. Observação: A rede RBF demo usa um kernel gaussiano, que usa a distância euclidiana para computar valores de saída local do nó escondido). No entanto, o programa de demonstração usa uma variação da distância de Manhattan, onde a distância é uma média da diferença de valores absolutos. Então, é a distância entre candidatos [0] e [1]:

d = abs(1.537 - (-0.468)) + .
.
.
+ abs(0.756 - (-1.048)) / 4
  = 2.256

O processo de gerar um conjunto de centróides de candidato e computação uma distância média estimada para o conjunto de candidatos é repetido um número especificado de vezes e o conjunto de candidatos com a maior distância média estimada é selecionado como o conjunto de centróide RBF.

Observe que a determinação de centróides de rede RBF pode ser considerada uma técnica de treino sem supervisão porque os valores de destino (por exemplo, 0, 1, 0) nos dados de treinamento não são necessários ou utilizados. Isto significa centróides podem ser determinados rapidamente. Também, o viés valores, pesos e larguras de rede RBF podem — em teoria pelo menos — muito mais rapidamente do que os pesos da rede neural equivalente e viés valores calculados. Isto dá uma vantagem potencial sobre redes neurais-redes RBF (mas, como você verá, há mais para a história).

Durante o processo de determinação de centróides de rede RBF, determinar os índices de candidato é uma subproblema interessante. O programa de demonstração usa um algoritmo inteligente chamado amostragem de reservatório. A ideia é escolher os índices n possíveis primeiros, em seguida, substituir probabilisticamente os índices iniciais com os restantes índices possíveis:

private int[] DistinctIndices(int n, int range)
{
  // Reservoir sampling.
assumes rnd exists
  int[] result = new int[n];
  for (int i = 0; i < n; ++i)
    result[i] = i;
  for (int t = n; t < range; ++t) {
    int m = rnd.Next(0, t + 1);
    if (m < n) result[m] = t;
  }
  return result;
}

Embora o método seja curto, é sutil. Alternativas incluem o uso de uma abordagem de força bruta, onde os índices aleatórios são gerados e em seguida verificados para ver se há qualquer duplicados.

Determinar as larguras de rede RBF

O mecanismo de entrada-processo-saída de rede RBF requer um valor de largura para cada nó escondido. Existem muitas possibilidades para determinar os valores de largura. A abordagem mais simples e usada pelo programa de demonstração, é para calcular uma largura comum, que podem usar processamento tudo escondido de nós. Pesquisa nessa área tende a ser confuso e conclusões são, por vezes, contraditórias. O programa de demonstração calcula uma largura comum como a média distância euclidiana entre todos os pares possíveis de centróides. Em pseudocódigo:

sumOfDists = 0.0
for each pair of centroids
  accumulate Euclidean distance between curr pair
end loop
return accumulated sumOfDists / number of pairs

Baseado na minha experiência, a eficácia das redes RBF é extremamente sensível aos valores utilizados para larguras de nó escondido. A pesquisa mostra uma largura que é muito pequena tende a excesso ajustar os dados de treinamento, levando a precisão de classificação pobre. Uma largura que seja demasiado grande tende a ajuste sob os dados, que também leva à má classificação. Se você experimentar com o código de demonstração definindo manualmente os valores das larguras rede RBF, você pode ver este efeito em ação.

Além de usar a distância média entre centróides, davg, para um valor de largura comum nós ocultos, pesquisa também sugere o uso de (2 * davg), ou (davg / sqrt(2 * numHidden)) e muitos outros valores. E em vez de usar uma largura comum, existem muitas possibilidades para calcular os valores de largura diferente para cada nó escondido. Na minha opinião, a alta sensibilidade das redes RBF para valores de largura, juntamente com a falta de relacionados de convencer os resultados da investigação em como a computação melhor valores de largura, são os principais inconvenientes do uso de redes RBF comparado a alternativas, tais como redes neurais e máquinas de vector de suporte.

Determinação de preconceitos e pesos de rede RBF

Após a determinação de centróides e larguras, o passo final na formação de uma rede RBF é determinar os valores para os pesos e vícios. Teoricamente, você pode calcular pesos de rede RBF facilmente e rapidamente porque, vagamente falando, existem n equações com n valores desconhecidos. Assim, técnicas numéricas padrão podem, em teoria, ser usadas para resolver para os valores de peso.

Infelizmente, na prática, usar técnicas padrão executa em muitos problemas práticos. Por exemplo, muitas técnicas padrão para a resolução de sistemas de equações envolvem o uso da inversão de matriz. Inversão de matriz pode falhar por várias razões.

Ao invés de usar uma técnica numérica determinística, mas possivelmente frágeis para resolver exatamente para pesos de rede RBF, o programa de demonstração usa otimização de enxame de partículas para estimar os melhores valores. PSO é um comportamento de grupo coordenado baseado em meta-heurísticas, como bandos de pássaros ou cardumes de peixes. Em PSO, uma partícula tem uma posição que representa uma solução em potencial (o melhor conjunto de valores de peso neste caso). Cada partícula tem uma velocidade que determina a posição da partícula próxima.

PSO, é criado um conjunto de partículas. Em cada tique do tempo simulado, cada partícula move-se para uma nova posição com base na atual posição da partícula e velocidade, a posição histórica mais conhecida da partícula e a posição de histórica mais conhecida de qualquer das partículas. Aqui é o PSO em pseudocódigo de alto nível:

set number of particles
set maxIterations
initialize all particles to random positions
loop maxIterations times
  for each particle
    update curr particle's velocity
    use new velocity to compute new position
    compute error for new position
    check if new particle best position
    check if new best position for all particles
  end for
end loop
return best position found by any particle

PSO é um tópico fascinante em sua própria direita. Você pode aprender mais sobre ele lendo meu artigo de agosto de 2011, "Particle Swarm Optimization" (msdn.microsoft.com/magazine/hh335067). PSO requer a especificação de vários param livre­tros, incluindo constantes de peso que controlam a influência relativa da atual posição de uma partícula, melhor posição histórica e melhor posição histórica global. PSO requer também especificando o número de partículas, o número máximo de iterações e, opcionalmente, um limite de erro para a saída precoce do algoritmo. Você pode experimentar com estes fatores, usando o código de demonstração.

Além de PSO e técnicas numéricas tradicionais, existem muitas alternativas para encontrar pesos de rede RBF, incluindo simples descida gradiente e algoritmos genéticos reais. Embora a teoria das redes RBF tem sido estudada bastante exten­progressivamente, há relativamente poucos resultados convincentes de investigação sobre a eficácia comparativa de técnicas de treinamento diferentes.

Conclusão

O código de programa demo juntamente com a explicação apresentada aqui deve dar-lhe uma base sólida para investigar redes RBF. Embora as redes RBF são bem conhecidas na Comunidade de pesquisa, eles não parecem ser usado muito frequentemente na Comunidade de desenvolvedores de software em comparação com alternativas tais como naïve Bayes classificadores, classificadores de redes neurais e regressão logística. Uma possível razão para isso pode ser a escassez de exemplos de aplicação prática. Uma outra razão possível é a incerteza em torno RBF rede fatores fundamentais, especialmente aqueles relacionados com o cálculo das larguras de rede RBF. Na minha opinião, não há provas de pesquisas sólidas para responder à pergunta de se as redes RBF são mais eficazes, menos eficazes ou aproximadamente equivalente a técnicas alternativas de aprendizado de máquina.

Dr. James McCaffrey funciona para Microsoft Research em Redmond, Wash. Ele trabalhou em vários produtos Microsoft, incluindo o Internet Explorer e Bing. Ele pode ser contatado em jammc@microsoft.com.

Agradecemos ao seguinte especialista técnico pela revisão deste artigo: Kirk Olynyk (Microsoft Research)