Partager via


Cet article a fait l'objet d'une traduction automatique.

Série de tests

Réseaux fonction radiale de base pour les programmeurs

James McCaffrey

Télécharger l'exemple de code

James McCaffreyRéseaux de fonction (RBF) base radiale sont des systèmes logiciels qui ont certaines similitudes avec les réseaux de neurones.Un réseau RBF accepte l'une ou plus d'entrée numérique des valeurs, telles que (1,0, 2,0, 3.0) et génère une ou plusieurs valeurs de sortie numérique, tels que (4.6535, 9.4926).Réseaux RBF (parfois appelés filets radiales) peuvent être utilisés pour classer les données et faire des prédictions.Par exemple, un réseau RBF pourrait être utilisé pour prédire les scores des deux équipes de football qui sont programmés pour jouer de l'autre, basé sur des données historiques comme pourcentage de victoires actuelle de chaque équipe, avantage du terrain maison (-1,0 ou + 1,0) et ainsi de suite.Ou un réseau RBF pourrait être utilisé pour classer le risque d'un patient l'hôpital du cancer (faible = 0, high = 1) basé sur les valeurs des résultats des tests médicaux et d'autres facteurs comme l'âge et le sexe.

À mon avis, les réseaux RBF sont parmi les plus fascinantes de toutes les techniques d'apprentissage automatique.Mais même s'il existe de nombreux documents de recherche qui expliquent les mathématiques complexes derrière ces réseaux, il y a très peu de ressources qui expliquent leur regard un programmeur.Cet article décrit exactement ce que les réseaux RBF sont, expliquer comment ils calculent leurs sorties et illustrent avec un programme complet de la démo d'entrées-sorties du réseau RBF.

La meilleure façon pour vous de voir où va cet article doit avoir un regard sur le programme de démonstration en Figure 1.La démo crée un réseau RBF, configure, envoie un vecteur d'entrée avec les valeurs de (1,0, 2,0, 3.0) et affiche le vecteur de sortie de (4.6535, 9.4926).La démo commence par créer un 3-4-2 réseau RBF.Les 3 indique une entrée au réseau radial a trois valeurs numériques.Le 2 indique il y a deux sorties numériques.Les 4 indique le net radial a quatre nœuds cachés un traitement interne.

Radial Basis Function Network Input-Output Demo
Figure 1 base radiale fonction réseau d'entrée-sortie démo

Le net radial utilise quatre jeux de configuration infor­mation, généralement dénommée les paramètres du système.Le premier paramètre est un ensemble de ce que l'on appelle centroïdes.Le centre de gravité est parfois appelés moyens.Dans la démo, le centre de gravité se (-3,0, -3,5, -3,8), (-1,0, -1.5, 1.8), (2.0, 2.5, 2.8) et (4.0, 4.5, 4.8).Remarquez il y a un centre de gravité pour chaque nœud caché et que chaque centre de gravité a le même nombre de valeurs comme vecteur d'entrée.Parce que le but de la démo est uniquement pour expliquer comment les réseaux RBF calculer leur sortie, plutôt que de résoudre un problème réaliste, le nombre de noeuds cachés (quatre) est artificiellement faible, et les valeurs des quatre centroïdes sont arbitraires.

Le deuxième ensemble de paramètres pour la démo radial net est quatre écarts-types.Écarts-types sont parfois appelés des largeurs RBF.Les valeurs dans la démo sont 2.22, 3.33, 4,44 et 5,55.Il y a un écart-type pour chaque unité de traitement des nœuds cachés.Encore une fois, les valeurs utilisées dans la démo sont des valeurs factices et ne correspondent pas à un réel problème.

Le troisième ensemble de paramètres de réseau RBF est les poids.Notez que dans Figure 1 qu'il y a huit caractères.Si un RBF net a j cachée et nœuds de sortie k, il y aura j * poids k.Ici, les 4 * 2 = 8 poids sont 5.0, -5,1, -5.2, 5.3, -5,4, 5.5, 5.6 et -5,7.Comme les autres jeux de paramètres, ces valeurs sont purement arbitraires et sont uniquement à des fins de démonstration.

Le quatrième ensemble de paramètres de nets radiales dans la démo est deux valeurs de biais.Le nombre de valeurs de biais dans un réseau RBF est égal au nombre de valeurs de sortie, deux dans cette affaire.Les deux valeurs de biais factices sont 7.0 et 7.1.

Après que chargement les quatre ensembles de valeurs de paramètre dans le réseau RBF, une entrée de (1,0, 2,0, 3.0) est alimentée au réseau.En utilisant le paramètre valeurs, une sortie de (4.6535, 9.4926) est calculé.Le programme de démonstration affiche certaines valeurs intermédiaires du calcul — une distance et une sortie pour chaque nœud caché — mais ces valeurs intermédiaires sont indiquées uniquement pour vous aider à comprendre le mécanisme d'entrée-sortie RBF et ne s'affichent pas normalement.

Cet article suppose que vous avez au moins au niveau intermédiaire de compétences en programmation avec un langage C-famille, mais ne suppose que vous savez quelque chose sur les réseaux de fonction radiale de base.Le programme de démonstration est codé à l'aide de c#, mais vous ne devriez avoir aucun mal à mon code dans une autre langue comme Python ou Windows PowerShellde refactorisation.J'ai enlevé la vérification des erreurs plus normale pour garder les idées claires.Tout le code clé pour le programme de démonstration est présenté dans cet article, mais j'ai omis certaines des méthodes d'assistance affichage.Le code source complet pour la démo est disponible à archive.msdn.microsoft.com/mag201310TestRun.

Le mécanisme d'entrée-sortie RBF

Afin de comprendre le mécanisme d'entrée-sortie RBF, jetez un oeil sur le schéma de Figure 2.Les valeurs dans le diagramme corre­repond à ceux dans le programme de démonstration.Traitement a lieu en deux étapes principales.Tout d'abord, un vecteur d'entrée est envoyé à chaque nœud caché et chaque nœud caché indépendamment calcule une valeur de sortie intermédiaire.Deuxièmement, les valeurs intermédiaires cachés-nœud sortie sont combinés pour produire les valeurs de sortie du système final.

Radial Basis Function Network Architecture
Figure 2 Architecture de Microsoft base radiale fonction réseau

Le schéma de Figure 2 utilise l'indexation de base zéro pour tous les objets.La sortie d'un nœud caché j exprime mathématiquement, est :

Cette équation est un exemple de ce qu'on appelle la fonction gaussienne et lorsque sous forme graphique a une courbe caractéristique en forme de cloche.L'icône en forme de cloche en haut de chaque nœud caché indique que les sorties de nœuds masqués sont calculées à l'aide d'une fonction gaussienne.

L'équation est plus simple qu'il peut sembler au départ.La lettre grecque phi représente la sortie d'un nœud caché, j dans le cas présent.Le x représente l'entrée.Ici x est un vecteur (1,0, 2,0, 3.0) plutôt qu'une valeur scalaire unique.E minuscule est la constante d'Euler (2,71828...) et e élevé à une certaine valeur correspond à la fonction Exp disponible dans la plupart des langages de programmation.La lettre grecque mu est le vecteur de centroïde jth.La paire de symboles double barre, lorsqu'il est appliqué à la différence entre deux vecteurs, équivaut à une notation sténographique pour la fonction de distance de la géométrie euclidienne, qui est la racine carrée de la somme des différences quadratiques entre les composants des deux vecteurs.La lettre grecque sigma représente l'écart type du nœud caché jth.

Je démontrerai comment la sortie intermédiaire du nœud caché plus basse [3] est calculé en utilisant les valeurs du programme démo.L'entrée x est (1,0, 2,0, 3.0).Le centre de gravité, mu, est (4.0, 4.5, 4.8).L'écart-type, sigma, est 5.55.Rappelons que ces valeurs sont purement arbitraires et à des fins de démonstration et ne correspondent pas à un réel problème.

La distance entre x et mu est 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, comme le montre Figure 1.La distance au carré est 54,49.Notez que l'opération équerrage annule l'opération de la racine carrée de la formule de la distance, ce qui signifie que l'équation pourrait avoir été simplifiée un peu.

Rassembler toutes les valeurs, la sortie pour le nœud caché 3 est Exp (-54.49 / (2 * (5,55) ^ 2)) = Exp(-0.88451) = 0.4129, qui est la valeur indiquée dans Figure 1.

Les valeurs de sortie pour les noeuds cachés 0, 1 et 2 sont calculées de la même manière et sont 0,0014, 0.2921 et 0.5828, respectivement.

Maintenant, je vais montrer comment les sorties de nœuds masqués sont combinés pour produire les produits réseau RBF.Sortie d'un réseau RBF est la somme pondérée des produits de toutes les sorties de nœuds masqués fois un poids associé, ainsi qu'une valeur de biais finale.Exprimé sous forme d'une équation, la valeur de k de nœud de sortie est :

Ici, k est l'indice d'un nœud de sortie (0, 1 dans la démo) ; j est l'index d'un noeud caché (0, 1, 2, 3) ; et M est le nombre de noeuds cachés.Le terme w(jk) est le poids du nœud caché j à k de nœud de sortie.Le terme b(k) est la valeur de décalage associée à sortie k.

Par exemple, si h0, h1, h2, et h3 (en utilisant la lettre plus facile-à-type h au lieu de la lettre grecque phi) sont les sorties des nœuds cachés entre 0 et 3, puis la sortie finale 0 est calculée ainsi: (w00 * h0) + (w10 * h1) + (w20 * h2) + (w30 * h3) + b0 = (5.0 * 0,0014) + (-5,2 * 0.1874) + (-5,4 * 0.5828) + (5,6 * 0.4129) + 7,0 = 0,0070 +-1.5189 +-3.1471 + 2.3122 + 7,0 = 4.6535 (arrondis), comme le montre Figure 1.

Structure de programme démo

La structure générale du programme de démonstration, avec plupart WriteLine Instructions retirées et quelques petites modifications, est présentée dans Figure 3.La fonctionnalité de réseau RBF est contenue dans la classe RadialNet.Assistants de classe contient trois méthodes d'affichage.

Structure du programme figure 3 RBF réseau démo

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

Pour créer le programme de démonstration, j'ai lancé Visual Studio 2012. La démo n'a aucune dépendance significative de .NET, donc n'importe quelle version de Visual Studio devrait fonctionner. J'ai créé une application de console c# nouvelle­projet de cation nommé RadialNetworksInputOutput. Une fois le code du modèle chargé, j'ai renommé le fichier Program.cs à NetIOProgram.cs Radial et Visual Studio renommé automatiquement classe programme en conséquence. J'ai supprimé tous les inutiles instructions using en haut du code source.

Vous devriez être en mesure de comprendre les instructions de la méthode Main sans difficulté. L'instruction qui instancie l'objet réseau RBF est :

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

Les quatre États qui se chargent des valeurs de paramètre de réseau RBF sont :

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

L'instruction qui charge l'entrée et calcule et retourne la sortie de réseau RBF est :

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

La classe RadialNet

La définition de la classe de réseau RBF commence par :

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;
...

Le but de chacun de ces membres de la classe doit être clair, basé sur l'explication de comment un réseau RBF calcule sa sortie. Les graisses sont stockées sous forme d'une matrice de tableau de tableaux-style-où le premier index indique le nœud caché et le second indice indique le nœud de sortie. Le langage c#, contrairement à la plupart des langues, prend en charge un type de données de matrice vrai, et vous pouvez l'utiliser au lieu d'un tableau de tableaux pour la matrice de poids.

Le constructeur RadialNet est défini comme :

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 vous faites référence au diagramme Figure 2, vous verrez comment la taille de chaque classe de tableau et de matrice est liée à numInput, numHidden et numOutput. Une méthode utilitaire statique, MakeMatrix, est appelée par le constructeur juste pour garder le code un peu plus propre. MakeMatrix de la méthode est définie comme :

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;
}

RadialNet classe a quatre méthodes pour définir les valeurs des le centre de gravité, les écarts-types, les poids et les préjugés. Une autre conception est de surcharger le constructeur pour accepter toutes les valeurs de paramètre RBF, mais je préfère les méthodes set séparés dans la plupart des situations. Méthode SetCentroids est :

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éthode SetStdDevs est :

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

Méthode SetWeights est :

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éthode SetBiases est :

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

La méthode ComputeOutputs

Le cœur de la classe RadialNet est la méthode ComputeOutputs. Début de la définition de la méthode :

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

Ici, les valeurs de x-entrée sont simplement copiés dans entrées de tableau de membres. Parce que la méthode ComputeOutputs utilise, mais ne change pas les valeurs de x-entrée, entrées de tableau de membre n'est pas vraiment nécessaire. Toutefois, dans certains cas, vous pourriez vouloir effectuer un traitement préliminaire de l'entrée x. Et je pense qu'à l'aide d'un tableau d'entrées de classe explicite est une conception plus propre et une valeur supplémentaire fonctionne copier dans les valeurs de. Le tableau de hOutputs local contient les sorties de chaque nœud caché. Une autre conception est de définir hOutputs comme un membre de la classe.

Ensuite, ComputeOutputs calcule les sorties pour chaque nœud caché :

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 distance est calculée par une méthode utilitaire statique, Distance, qui est défini :

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);
}

Notez que la Distance effectue une opération de racine carrée et que cette valeur est stockée dans la variable d, qui est ensuite élevé au carré. Une alternative consiste à définir une méthode DistanceSquared, qui est la même que la Distance à l'exception de l'appel à la fonction racine carrée et puis pas carré la valeur de d. Bien que cette approche est plus efficace, il rend le code en décalage avec les définitions mathématiques standard utilisées dans la littérature RBF.

Le code dans ComputeOutputs qui calcule le produit final est :

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];
...

ComputeOutputs de la méthode se termine en copiant les valeurs dans le tableau de sorties des membres à une valeur de retour :

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

Une autre conception consiste à définir les ComputeOutputs à l'aide d'un type de retour void et définir une méthode distincte de la GetOutputs.

Pour résumer

Le code et les explications présentées dans cet article devraient vous aider à démarrer si vous souhaitez explorer les réseaux de fonction radiale de base. Il y a beaucoup de différents types de réseaux RBF. Le RBF net dans cet article utilise une fonction gaussienne pour calculer les nœuds cachés sortie. Les réseaux RBF peuvent utiliser beaucoup d'autres fonctions, telles que les splines quadratiques multiples et plaque mince. La fonction particulière utilisée par un réseau RBF est appelée le noyau du réseau.

Vous mai se demander exactement où l'architecture plutôt exotique des réseaux RBF provenance. Les réseaux RBF ont été le résultat de la recherche universitaire dans la théorie de l'approximation de la fonction. Il peut être prouvé que, avec quelques hypothèses et lâchement parlant, les réseaux RBF peuvent reproduire n'importe quelle fonction mathématique. Cela signifie en théorie au moins, les réseaux RBF peuvent être utilisés pour faire des prédictions sur les données qui suit un modèle sous-jacent. Réseaux de neurones partagent cette caractéristique de l'universel-fonction. À mon avis, il n'est pas clair si les réseaux RBF sont plus ou moins efficaces que les réseaux de neurones, ou à peu près la même chose, quand il s'agit de la classification de l'apprentissage automatique et de prédiction. Cependant, il y a des preuves suffisantes que les réseaux RBF peuvent être formés beaucoup plus rapidement que les réseaux de neurones, et contrairement aux réseaux de neurones, qui exigent généralement de très grandes quantités de données d'apprentissage, les réseaux RBF peuvent travailler bien, même avec de petites quantités de données d'apprentissage.

Afin d'utiliser un réseau RBF pour effectuer des prédictions pour un problème réaliste, le réseau doit être formé. Cela signifie que l'utilisation de données historiques existantes et de trouver le meilleur jeu de centroïdes, les écarts-types, les poids et les valeurs biais — c'est-à-dire l'ensemble des valeurs de paramètre qui génère des sorties de réseau RBF qui correspondent plus étroitement les données historiques. Formation d'un réseau RBF consiste également à trouver le nombre optimal de noeuds cachés. Formation des réseaux RBF est un problème intéressant que nous l'expliquerons dans un prochain article.

Dr. James McCaffrey travaille pour Microsoft Research à Redmond, Washington Il a travaillé sur plusieurs produits Microsoft, y compris Internet Explorer et Bing. Il peut être contacté à jammc@microsoft.com.

Merci aux experts techniques suivants d'avoir relu cet article : Dan Liebling (Microsoft Research)