Compartir a través de


Este artículo proviene de un motor de traducción automática.

Ejecución de pruebas

Redes de función de base radial para programadores

James McCaffrey

Descargar el código de ejemplo

James McCaffreyLas redes de función de base radial (RBF) son sistemas de software que se parecen en cierta medida a las redes neuronales. Una red RBF acepta uno o más datos numéricos valores, tales como (-2,0, 1.0, 3.0) y genera uno o más valores de salida numérica, tales como (4.6535, 9.4926). Redes RBF (a veces denominadas redes radiales) pueden utilizarse para clasificar los datos y realizar predicciones. Por ejemplo, una red RBF podría utilizarse para predecir las puntuaciones de los dos equipos de fútbol que están programados para jugar entre sí, basado en datos históricos como el porcentaje de victorias actual de cada equipo, ventaja (-1,0 o + 1,0) y así sucesivamente. O una red RBF podría ser utilizada para clasificar el riesgo del paciente de un hospital de cáncer (bajo = 0, alto = 1) basado en los valores de resultados de las pruebas médicas y otros factores como la edad y sexo.

En mi opinión, las redes RBF están entre las más fascinantes de todas las técnicas de aprendizaje máquina. Pero aunque hay muchos trabajos de investigación que explican las matemáticas complejas detrás de estas redes, hay muy pocos recursos que les explican desde punto de vista de un programador. Este artículo describirá exactamente qué redes RBF son, explicar cómo computan sus salidas e ilustran con un completo programa de demostración de entrada / salida de red RBF.

La mejor manera para que usted pueda ver hacia dónde se dirige este artículo es para echar un vistazo al programa de demostración en figura 1. La demo crea una red RBF, configura, envía un vector de entrada con valores de (-2,0, 1.0, 3.0) y muestra el vector de salida de (4.6535, 9.4926). La demostración comienza con la creación de un 3-4-2 red RBF. Los 3 indica que una entrada a la red radial tiene tres valores numéricos. Los 2 indica que hay dos salidas numéricas. Los 4 indica que la red radial tiene cuatro nodos de procesamiento interno, oculto.

Radial Basis Function Network Input-Output Demo
Figura 1 función de base Radial red Input-Output Demo

La red radial requiere cuatro juegos de configuración infor­mation, generalmente conocido como los parámetros del sistema. El primer parámetro es un conjunto de supuestos centroides. Los centroides a veces se llaman los medios. En la demo, los centroides son (-3,0, -3.5, 3,8), (-1,0, -1.5, 1.8), (2.0, 2.5, 2.8) y (4.0, 4.5, 4.8). Observe un centroide de cada nodo escondido y que cada centroide tiene el mismo número de valores como un vector de entrada. Porque el propósito de la demo es sólo para explicar cómo las redes RBF calcular su salida, más que resolver un problema realista, el número de nodos ocultos (cuatro) es pequeño artificialmente, y los valores de los cuatro centroides son arbitrarios.

El segundo conjunto de parámetros para la demo de red radial es cuatro desviaciones estándar. Desviaciones estándar se denominan a veces anchos RBF. Los valores de la demo son 2.22, 3.33 y 4.44 5.55. Hay una desviación estándar para cada unidad de procesamiento de nodos ocultos. Una vez más, los valores utilizados en la demo son valores y no corresponden a un problema real.

El tercer conjunto de parámetros de red RBF es los pesos. Aviso figura 1 que hay ocho pesos. Si una red RBF tiene nodos oculto j y k salida nodos, habrá j * pesos k. Aquí, los 4 * 2 = 8 pesos son 5.0, 5.1,-5.2, 5.3,-5.4, 5.5, 5.6 y-5.7. Como los otros conjuntos de parámetros, estos valores son puramente arbitrarios y solamente con fines de demostración.

El cuarto conjunto de parámetros de red radiales en la demo es dos valores de sesgo. El número de valores diagonales en una red RBF es igual al número de los valores de salida, dos en este caso. Los dos valores de sesgo maniquí son 7.0 y 7.1.

Después de cargar los cuatro conjuntos de valores de los parámetros en la red RBF, una entrada de (-2,0, 1.0, 3.0) es alimentada a la red. Mediante el parámetro valores, una salida de (4.6535, 9.4926) se computa. El programa de demostración muestra algunos valores intermedios de la computación — una distancia y una salida para cada nodo escondido — pero estos valores intermedios se muestran sólo para ayudarle a comprender el mecanismo de entrada y salida RBF y normalmente no se mostrarán.

Este artículo asume que usted tiene habilidades de programación de nivel intermedio por lo menos con un lenguaje C-familia, pero no asume que sabes algo acerca de las redes de la función de base radial. El programa de demostración está codificado usando C#, pero no debería tener problemas para refactorización de código a otro idioma como Python o Windows PowerShell. He eliminado comprobación de errores más normal para mantener las principales ideas claras. La clave para el programa de demostración se presenta en este artículo, pero he omitido algunos de los métodos de visualización de ayudante. El código fuente completo para el demo está disponible en archive.msdn.microsoft.com/mag201310TestRun.

El mecanismo de entrada y salida RBF

Para entender el mecanismo de entrada y salida RBF, echa un vistazo al diagrama de la figura 2. Los valores en el diagrama corre­decae a los que están en el programa de demostración. Procesamiento se produce en dos pasos principales. En primer lugar, un vector de entrada es enviado a cada nodo escondido y cada nodo escondido independientemente calcula un valor de salida intermedia. En segundo lugar, los valores ocultos-nodo intermedio se combinan para producir los valores de salida final del sistema.

Radial Basis Function Network Architecture
Arquitectura de red de función de base Radial Figura 2

El diagrama de la figura 2 utiliza índice basado en cero para todos los objetos. Expresado matemáticamente, la salida de un nodo escondido j es:

Esta ecuación es un ejemplo de lo que llama la función gaussiana y al graficar una curva característica en forma de campana. El icono en forma de campana en la parte superior de cada nodo escondido indica que las salidas de nodos ocultos son calculadas usando una función gaussiana.

La ecuación es más sencilla que puede parecer inicialmente. El PI de la letra griega representa la salida de un nodo escondido, j en este caso. La x representa la entrada. Aquí x es un vector (1,0, -2,0 y 3,0) en lugar de un valor escalar. E minúscula es constante de Euler (2.71828...) y e elevado a algún valor corresponde a la función Exp disponible en la mayoría de lenguajes de programación. La letra griega mu es el vector del centroide jth. El par de símbolos de doble barra, cuando se aplica a la diferencia entre dos vectores, es equivalente a una notación abreviada para la función de distancia de la geometría euclidiana, que es la raíz cuadrada de la suma de las diferencias al cuadrado entre los componentes de los dos vectores. La sigma Letra griega representa la desviación estándar de los nodos ocultos jth.

Voy a demostrar cómo la salida intermedia del nodo oculto inferior [3] es calculado usando los valores del programa de demostración. La entrada x es (-2,0, 1.0, 3.0). El centroide, mu, es (4.0, 4.5, 4.8). La desviación estándar, sigma, es 5,55. Recordar que estos valores son puramente arbitrarios y para propósitos de demostración y no corresponden a un problema real.

La distancia entre x y mu es Sqrt ((1.0-4.0) ^ 2 + (-2,0-4.5) ^ 2 + (3.0-4.8) ^ 2) = Sqrt (9.00 + 42.25 + 3,24) = 7.3817 como se muestra en la figura 1. La distancia al cuadrado es 54.49. Tenga en cuenta que la escuadra operación se cancela la operación de la raíz cuadrada de la fórmula de distancia, lo que significa que la ecuación podría haber sido simplificada un poco.

Reuniendo todos los valores, la salida para el nodo escondido 3 es Exp (-54.49 / (2 * (5,55) ^ 2)) = Exp(-0.88451) = 0.4129, que es el valor se muestra en la figura 1.

Los valores de salida para los nodos ocultos 0, 1 y 2 se calculan de la misma manera y son 0,0014, 0.2921 y 0.5828, respectivamente.

Ahora te voy a mostrar cómo las salidas de nodos ocultos se combinan para producir las salidas de red RBF finales. La salida de una red RBF es la suma ponderada de los productos de todas las salidas de nodos ocultos veces un peso asociado, además de un valor de sesgo final. Expresado en una ecuación, el valor de salida nodo k es:

Aquí, k es el índice de un nodo de salida (0, 1 en la demo); j es el índice de un nodo escondido (0, 1, 2, 3); y M es el número de nodos ocultos. El término w(jk) es el peso de nodo escondido j k nodo de salida. El término k es el valor de sesgo asociado con salida k.

Por ejemplo, si h0, h1, h2, y h3 (usando la letra más fácil-a-tipo h en vez de phi de la letra griega) son las salidas de los nodos ocultos de 0 a 3, resultado final 0 se calcula como (w00 * h0) + (w10 * h1) + (w20 * h2) + (w30 * h3) + b0 = (5.0 * 0,0014) + (-5.2 * 0.2921) + (-5.4 * 0.5828) + (5.6 * 0.4129) + 7.0 = 0.0070 +-1.5189 +-3.1471 + 2.3122 + 7.0 = 4.6535 (redondeado), como se muestra en la figura 1.

Estructura del programa demo

La estructura general del programa de demostración, con mayoría WriteLine declaraciones quitados y menores ediciones, se presenta en figura 3. La funcionalidad de red RBF está contenida en la clase RadialNet. Ayudantes de clase contiene tres métodos de visualización.

Estructura del programa figura 3 RBF red Demo

using System;
namespace RadialNetworksInputOutput
{
  class RadialNetIOProgram
  {
    static void Main(string[] args)
    {
      Console.WriteLine("\nBegin Radial Basis Function (RBF) network demo\n");
      int numInput = 3;
      int numHidden = 4;
      int numOutput = 2;
      Console.WriteLine("\nCreating a 3-4-2 radial net");
      RadialNet rn = new RadialNet(numInput, numHidden, numOutput);
      double[][] centroids = new double[4][];
      centroids[0] = new double[] { -3.0, -3.5, -3.8 };
      centroids[1] = new double[] { -1.0, -1.5, -1.8 };
      centroids[2] = new double[] { 2.0, 2.5, 2.8 };
      centroids[3] = new double[] { 4.0, 4.5, 4.8 };
      rn.SetCentroids(centroids);
      double[] stdDevs = new double[4] { 2.22, 3.33, 4.44, 5.55 };
      rn.SetStdDevs(stdDevs);
      double[][] hoWeights = new double[4][];
      hoWeights[0] = new double[2] { 5.0, -5.1 };
      hoWeights[1] = new double[2] { -5.2, 5.3 };
      hoWeights[2] = new double[2] { -5.4, 5.5 };
      hoWeights[3] = new double[2] { 5.6, -5.7 };
      rn.SetWeights(hoWeights);
      double[] oBiases = new double[2] { 7.0, 7.1 };
      rn.SetBiases(oBiases);
      double[] xValues = new double[3] { 1.0, -2.0, 3.0 };
      Console.WriteLine("\nSetting x-input to:");
      Helpers.ShowVector(xValues, 1, 4, true);
      Console.WriteLine("\nComputing the output of the radial net\n");
      double[] yValues = rn.ComputeOutputs(xValues);
      Console.WriteLine("\nThe output of the RBF network is:");
      Helpers.ShowVector(yValues, 4, 4, true);
      Console.WriteLine("\nEnd RBF network demo\n");
      Console.ReadLine();
    } // Main
  } // Program
  public class RadialNet { ...
}
  public class Helpers { ...
}
} // ns

Para crear el programa de demostración, he lanzado Visual Studio 2012. La demo no tiene significativa .NET dependencias, para que funcione cualquier versión de Visual Studio . He creado un nuevo artefacto de consola de C#­proyecto de catión denominado RadialNetworksInputOutput. Después de carga el código de la plantilla, cambió el nombre a NetIOProgram.cs Radial archivo Program.cs y Visual Studio automáticamente retitulado clase programa en consecuencia. Borré todo innecesario usar comandos en la parte superior del código fuente.

Usted debe ser capaz de entender las declaraciones en el método Main sin dificultad. La afirmación de que crea una instancia del objeto de red RBF es:

RadialNet rn = new RadialNet(numInput, numHidden, numOutput);

Las cuatro declaraciones que cargan los valores de parámetros de red RBF son:

rn.SetCentroids(centroids);
rn.SetStdDevs(stdDevs);
rn.SetWeights(hoWeights);
rn.SetBiases(oBiases);

La afirmación de que la entrada de las cargas y calcula y devuelve la salida de red RBF es:

double[] yValues = rn.ComputeOutputs(xValues);

La clase RadialNet

La definición de la clase de red RBF comienza con:

public class RadialNet
{
  private int numInput;
  private int numHidden;
  private int numOutput;
  private double[] inputs;
  private double[][] centroids; // Aka means
  private double[] stdDevs; // Aka widths
  private double[][] hoWeights;
  private double[] oBiases;
  private double[] outputs;
...

El propósito de cada uno de estos miembros de la clase debe ser claro, basada en la explicación de cómo una red RBF calcula su salida. Los pesos se almacenan como una matriz de matriz de matrices-estilo-donde el primer índice indica el nodo escondido y el segundo índice indica el nodo de salida. El lenguaje C#, a diferencia de la mayoría de los idiomas, es compatible con un tipo de datos matriz verdadera y desee utilizarlo en lugar de una matriz de matrices para la matriz de pesos.

El constructor de RadialNet se define como:

public RadialNet(int numInput, int numHidden, int numOutput)
{
  this.
numInput = numInput;
  this.
numHidden = numHidden;
  this.
numOutput = numOutput;
  this.inputs = new double[numInput];
  this.centroids = MakeMatrix(numHidden, numInput);
  this.stdDevs = new double[numHidden];
  this.hoWeights = MakeMatrix(numHidden, numOutput);
  this.oBiases = new double[numOutput];
  this.outputs = new double[numOutput];
}

Si te refieres al diagrama en figura 2, usted verá cómo el tamaño de cada clase matriz y matriz está relacionada con numInput, numHidden y numOutput. Un método de utilidad estático, MakeMatrix, es llamado por el constructor para mantener el código un poco más limpio. Método MakeMatrix se define como:

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

Clase RadialNet tiene cuatro métodos para establecer los valores de los centroides, desviaciones estándar, pesos y sesgos. Un diseño alternativo es sobrecargar el constructor para aceptar todos los valores de parámetro RBF, pero prefiero métodos set separados en la mayoría de las situaciones. Método de SetCentroids es:

public void SetCentroids(double[][] centroids)
{
  if (centroids.Length != numHidden)
    throw new Exception("Bad number of centroids");
  if (centroids[0].Length != numInput)
    throw new Exception("Bad centroid size");
  for (int i = 0; i < numHidden; ++i)
    for (int j = 0; j < numInput; ++j)
      this.centroids[i][j] = centroids[i][j];
}

Método de SetStdDevs es:

public void SetStdDevs(double[] stdDevs)
{
  if (stdDevs.Length != numHidden)
    throw new Exception("Bad number of stdDevs");
  Array.Copy(stdDevs, this.stdDevs, stdDevs.Length);
}

Método de SetWeights es:

public void SetWeights(double[][] hoWeights)
{
  if (hoWeights.Length != numHidden)
    throw new Exception("Bad number of weights");
  if (hoWeights[0].Length != numOutput)
    throw new Exception("Bad number of weights");
  for (int i = 0; i < numHidden; ++i)
    for (int j = 0; j < numOutput; ++j)
      this.hoWeights[i][j] = hoWeights[i][j];
}

Método de SetBiases es:

public void SetBiases(double[] oBiases)
{
  if (oBiases.Length != numOutput)
    throw new Exception("Bad number of hoBiases");
  Array.Copy(oBiases, this.oBiases, oBiases.Length);
}

El método de ComputeOutputs

El corazón de la clase RadialNet es el método ComputeOutputs. Definición del método comienza:

public double[] ComputeOutputs(double[] xValues)
{
  Array.Copy(xValues, inputs, xValues.Length);
  double[] hOutputs = new double[numHidden];
...

Aquí, los valores de entrada x simplemente se copian en entradas de la matriz de miembros. Porque el método ComputeOutputs utiliza pero no cambia los valores de x de entrada, entradas de matriz miembro realmente no es necesario. Sin embargo, en algunos casos deberías realizar algún procesamiento preliminar de la entrada de x. Y siento que mediante una matriz de insumos clase explícita es un diseño más limpio y vale más el trabajo de copiar en valores. El conjunto local hOutputs tiene las salidas de cada nodo escondido. Un diseño alternativo es definir hOutputs como un miembro de clase.

A continuación, ComputeOutputs calcula las salidas para cada nodo escondido:

for (int j = 0; j < numHidden; ++j)
{
  double d = Distance(inputs, centroids[j]);
  // Display distance here if you wish
  double r = -1.0 * (d * d) / (2 * stdDevs[j] * stdDevs[j]);
  double g = Math.Exp(r);
  // Display hidden output here if you wish
  hOutputs[j] = g;
}
...

La distancia se calcula por el método de utilidad estática, distancia, que se define:

public static double Distance(double[] x, double[] c)
{
  double sum = 0.0;
  for (int i = 0; i < x.Length; ++i)
    sum += (x[i] - c[i]) * (x[i] - c[i]);
  return Math.Sqrt(sum);
}

Observe que distancia realiza una operación de raíz cuadrada y que este valor se almacena en la variable d, la cual es luego al cuadrado. Una alternativa es definir un método DistanceSquared, que es igual a la distancia con excepción de la llamada a la función raíz cuadrada y entonces no cuadrados el valor de d. Aunque este enfoque es más eficiente, hace el código fuera de sintonía con las definiciones matemáticas estándar usadas en literatura RBF.

El código en ComputeOutputs que calcula las salidas finales es:

for (int k = 0; k < numOutput; ++k)
  outputs[k] = 0.0;
for (int k = 0; k < numOutput; ++k)
  for (int j = 0; j < numHidden; ++j)
    outputs[k] += (hOutputs[j] * hoWeights[j][k]);
for (int k = 0; k < numOutput; ++k)
  outputs[k] += oBiases[k];
...

Método ComputeOutputs termina por copiar los valores de la matriz de salidas de miembros a un valor devuelto:

...
double[] result = new double[numOutput];
  Array.Copy(outputs, result, outputs.Length);
  return result;
}

Un diseño alternativo consiste en definir ComputeOutputs utilizando un tipo de valor devuelto void y definir un método independiente de GetOutputs.

En resumen

El código y la explicación presentada en este artículo deberían a empezar si quieres explorar redes de función de base radial. Hay muchos tipos diferentes de redes RBF. El RBF neto en este artículo utiliza una función gaussiana para calcular la salida de nodos ocultos. Redes RBF pueden utilizar muchas otras funciones, con nombres como spline multi cuadrática y placa delgada. La función particular utilizada por una red RBF se llama el núcleo de la red.

Usted puede estarse preguntando exactamente dónde viene la arquitectura de redes RBF bastante exótica. Redes RBF fueron el resultado de la investigación académica sobre la teoría de la aproximación de la función. Se puede probar, con unos supuestos y habla libremente, redes RBF pueden replicar cualquier función matemática. Esto significa en teoría al menos, las redes RBF pueden utilizarse para hacer predicciones sobre datos que sigue cualquier modelo subyacente. Redes neuronales comparten esta característica universal-función. En mi opinión, no es claro si las redes RBF son más o menos eficaces que las redes neuronales, o más o menos lo mismo, cuando se trata de aprendizaje máquina clasificación y predicción. Sin embargo, hay buena evidencia de que las redes RBF pueden ser entrenadas mucho más rápidamente que las redes neuronales, y a diferencia de las redes neuronales, que típicamente requieren grandes cantidades de datos de entrenamiento, redes de RBF pueden trabajar incluso con pequeñas cantidades de datos de entrenamiento.

Para poder utilizar una red RBF hacer predicciones para un problema realista, la red debe ser entrenada. Esto significa utilizar datos históricos existentes y encontrar el mejor conjunto de centroides, desviaciones estándar, pesas y sesgos valores — es decir, el conjunto de valores de los parámetros que genera salidas de red RBF que más se asemejen los datos históricos. Formación de una red RBF también implica encontrar el número óptimo de nodos ocultos. Formación de redes de RBF es un problema interesante que se explicará en un próximo artículo.

Dr.James McCaffrey trabajos de investigación de Microsoft en Redmond, Washington Ha trabajado en varios productos de Microsoft Internet Explorer y Bing. Puede ser contactado en jammc@microsoft.com.

Gracias al siguiente experto técnico por su ayuda en la revisión de este artículo: Dan Liebling (Microsoft Research)