Dieser Artikel wurde maschinell übersetzt.

Testlauf

Radiale Basisfunktionsnetzwerke für Programmierer

James McCaffrey

James McCaffreyRadiale Basisfunktionsnetzwerke (RBF) sind Softwaresysteme, die eine gewisse Ähnlichkeit mit neuronalen Netzwerken aufweisen.Ein RBF-Netzwerk akzeptiert einen oder mehrere numerische Eingabe Werte, wie (1.0, 2.0, 3.0) und generiert einen oder mehrere numerische Output-Werte, wie z. B. (4.6535, 9.4926).RBF Netze (auch radial Netze genannt) können verwendet werden, um Daten klassifizieren und Vorhersagen.Beispielsweise könnte ein RBF-Netzwerk verwendet werden, die Resultate von zwei Fussballmannschaften vorherzusagen, die geplant sind, einander, basierend auf historischen Daten wie jedes Team aktuelle gewinnenden Prozentsatz, Heimvorteil (1,0 oder + 1,0) und so weiter zu spielen.Oder ein RBF Netz könnte verwendet werden, um ein Krankenhaus-Patienten Risiko von Krebs zu klassifizieren (low = 0, high = 1) basierend auf den Werten der medizinische Testergebnisse und andere Faktoren wie Alter und Geschlecht.

Meiner Meinung nach gehören RBF Netze zu den faszinierendsten aller Computerlernen Techniken.Aber obwohl es viele Studien, die die komplexe Mathematik hinter dieser Netzwerke zu erklären gibt, gibt es sehr wenige Ressourcen, die sie aus der Sicht eines Programmierers zu erklären.Dieser Artikel beschreibt genau was RBF Netze sind, erklären, wie sie ihre Ausgaben berechnen und veranschaulichen mit ein komplettes RBF Netzwerk-Ausgang Demo-Programm.

Der beste Weg für Sie zu sehen, wohin dieses Artikels ist es, einen Blick auf das Demoprogramm in Abbildung 1.Die Demo erstellt ein RBF-Netzwerk konfiguriert, sendet eine Eingabe Vektor mit den Werten (1.0, 2.0, 3.0) und zeigt den Ausgabe-Vektor der (4.6535, 9.4926).Die Demo beginnt mit dem Erstellen einer 3-4-2 RBF Netz.Die 3 gibt an, dass die Eingabe für die radiale Net drei numerischen Werte hat.Die 2 gibt an, gibt es zwei numerische Ausgänge.Die 4 bedeutet, dass das radiale Netz vier versteckte, interne Verarbeitung Knoten hat.

Radial Basis Function Network Input-Output Demo
Abbildung 1 Radial Basis Funktion Netzwerk Input-Output-Demo

Die radiale Net erfordert vier Sätze von Konfiguration Infor­Mation, normalerweise als die Parameter des Systems bezeichnet.Der erste Parameter ist eine Reihe von sogenannten Zentroide.Zentroide werden Mittel bezeichnet.In der Demo sind die Zentroide (3,0, 3,5, 3,8), (1,0, 1,5, 1,8), (2.0, 2.5, 2.8) und (4.0, 4.5, 4.8).Beachten Sie gibt es einen Schwerpunkt für jeden versteckten Knoten und jede Schwerpunkt hat die gleiche Anzahl von Werten wie eine Eingabe Vektor.Da die Demo dient nur zu erklären, wie RBF Netze ihre Produktion berechnen, sondern als ein realistisches Problem zu lösen, die Anzahl der versteckten Knoten (vier) ist künstlich klein und die Werte der vier Zentroide sind willkürlich.

Der zweite Satz von Parametern für die Demo ist radial Net vier Standardabweichungen.Standardabweichungen werden RBF breiten bezeichnet.Die Werte in der Demo sind 2.22, 3.33 und 4.44 5,55.Es gibt eine Standardabweichung für jede hidden-Node-Verarbeitungseinheit.Wieder, die in der Demo verwendeten Werte sind Dummy-Werte und kein echtes Problem entsprechen.

Die dritte Reihe von RBF Netzwerkparameter ist die Gewichte.Beachten Sie im Abbildung 1 gibt es acht Gewichte.Wenn ein RBF net j versteckte Knoten und k-Ausgabeknoten hat, gibt es j * k Gewichte.Hier, 4 * 2 = 8 Gewichte sind 5.0, 5,1 5,2, 5.3, 5,4, 5.5, 5.6 und 5,7.Wie die anderen Sets von Parametern diese Werte sind rein willkürlich und dienen nur zu Demonstrationszwecken.

Die vierte Gruppe von radial net Parametern in der Demo ist zwei Bias-Werte.Die Anzahl der Bias-Werte in einem RBF-Netzwerk ist gleich der Anzahl der Ausgabewerte, zwei in diesem Fall.Die zwei dummy-Bias-Werte sind 7.0 und 7.1.

Nachdem laden die vier von Parameterwerte in das RBF-Netzwerk Sätze, das Netzwerk eine Eingabe (1.0, 2.0, 3.0) zugeführt.Mit dem Parameter-Werte, eine Leistung von (4.6535, 9.4926) wird berechnet.Das Demoprogramm zeigt einige Zwischenwerte der Berechnung — eine Distanz und Ausgabe für jeden versteckten Knoten — aber diese Zwischenwerte werden angezeigt, nur um Ihnen zu helfen den RBF-Eingabe-Ausgabe-Mechanismus zu verstehen und werden normalerweise nicht angezeigt.

Dieser Artikel setzt voraus, Sie haben mindestens Mittelstufe Programmierkenntnisse mit einer C-Familie-Sprache, aber nicht annehmen, dass Sie wissen nichts über radial Basis Funktion Netze.Das Demoprogramm ist codiert mit c# sollten, aber Sie keine Probleme meinen Code in eine andere Sprache wie Python oder Windows PowerShellUmgestaltung.Ich habe entfernt, die meisten normalen Fehlerüberprüfung um die wichtigsten Ideen klar zu halten.Der Tastencode für die Demo-Programm wird in diesem Artikel dargestellt, aber ich habe einige der Anzeige Hilfsmethoden weggelassen.Der vollständige Quellcode für die Demo ist verfügbar unter archive.msdn.microsoft.com/mag201310TestRun.

Der RBF-Input-Output-Mechanismus

Um den RBF-Eingabe-Ausgabe-Mechanismus zu verstehen, schauen Sie sich das Diagramm in Abbildung 2.Die Werte in der Diagramm-Corre­Spond zu den in der Demo-Programm.Die Verarbeitung erfolgt in zwei Hauptschritten.Zunächst eine Eingabe Vektor wird gesendet, um jede versteckte Knoten und jede versteckter Knoten unabhängig berechnet einen intermediate Ausgabewert.Zweitens werden die intermediate hidden-Node-Ausgabewerte kombiniert, um die endgültige System Ausgabewerte produzieren.

Radial Basis Function Network Architecture
Abbildung 2-Radial Basis-Funktion-Netzwerk-Architektur

Das Diagramm in Abbildung 2 verwendet nullbasierte Indizierung für alle Objekte.Mathematisch ausgedrückt, ist die Ausgabe von einer verborgenen Knoten j:

Diese Gleichung ist ein Beispiel der sogenannten Gauß-Funktion hat und grafisch dargestellt eine charakteristische glockenförmige Kurve hat.Das glockenförmigen Symbol am oberen Rand jeder versteckte Knoten bedeutet, dass die hidden-Node-Ausgänge eine Gauß-Funktion berechnet werden.

Die Gleichung ist einfacher, als es zunächst scheinen mag.Der griechische Buchstabe Phi stellt die Ausgabe eine verborgene Knoten j in diesem Fall.Das x steht für die Eingabe.Hier ist x ein Vektor (1.0, 2.0, 3.0), anstatt einen einzelnen skalaren Wert.Kleinbuchstaben e ist die Eulersche Konstante (2,71828...) und auf einen Wert von e entspricht die Exp-Funktion in den meisten Programmiersprachen zur Verfügung.Die griechische Buchstabe Mu ist die Jth Achsenschwerpunkt Vektor.Das Paar doppelbarrige Symbole, angewendet auf die Differenz zwischen zwei Vektoren entspricht eine Kurzform für die Euklidische Geometrie-Distanz-Funktion, die die Quadratwurzel aus der Summe der quadrierten Differenzen zwischen den Komponenten der beiden Vektoren ist.Die griechischen Buchstaben Sigma stellt die Standardabweichung des Knotens Jth versteckte.

Ich werde zeigen, wie die Mittelstufe Ausgabe der untersten verborgenen Knoten [3] ist mit den Werten der Demo-Programm berechnet.Die Eingabe X ist (1.0, 2.0, 3.0).Der Flächenschwerpunkt, Mu, ist (4.0, 4.5, 4.8).Die Standardabweichung, Sigma, ist 5,55.Daran erinnern Sie, dass diese Werte rein willkürlich und zu Demonstrationszwecken sind und kein echtes Problem entsprechen.

Der Abstand zwischen x und Mu ist Sqrt ((1.0-4.0) ^ 2 + (2,0-4,5) ^ 2 + (3.0-4.8) ^ 2) = Sqrt (42.25, 9.00 + 3.24) = 7.3817, wie in Abbildung 1.Kariert ist 54.49.Beachten Sie, dass die Quadrierung Operation die Quadratwurzel-Operation der Distanz-Formel macht was bedeutet, dass die Gleichung etwas vereinfacht haben könnte.

Zusammenstellung aller Werte, ist die Ausgabe für den versteckten Knoten 3 Exp (-54.49 / (2 * (5,55) ^ 2)) = Exp(-0.88451) = 0.4129, der Wert angezeigt, die Abbildung 1.

Die Ausgabewerte für versteckte Knoten 0, 1 und 2 werden auf die gleiche Weise berechnet und sind 0,0014, 0.2921 und 0.5828, beziehungsweise.

Jetzt werde ich zeigen, wie die hidden-Node-Ausgänge kombiniert werden, um die endgültige RBF Netz-Ausgänge zu erzielen.Ein RBF Netz-Ausgang ist die gewichtete Summe der Produkte aller hidden-Node-Ausgänge Zeiten eine zugehörige Gewichtung sowie einen endgültigen Bias-Wert.Ausgedrückt als eine Gleichung, ist der Wert des Output Knoten k:

K ist der Index des ein Ausgabeknoten (0, 1 in der Demo); j ist der Index des einen versteckten Knoten (0, 1, 2, 3); und M ist die Anzahl der versteckten Knoten.Der Begriff w(jk) ist das Gewicht von verborgenen Knoten j Knoten k ausgeben.Der Begriff b(k) ist der Bias Wert Ausgabe k zugeordnet.

Beispielsweise wenn h0, h1, h2, und h3 (unter Verwendung der einfacher Typ Buchstabe h statt dem griechischen Buchstaben Phi) sind die Ausgänge der versteckten Knoten 0 bis 3, dann als Endausgabe 0 berechnet wird (w00 * h0) + (w10 * h1) + (K20 * 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 (gerundet), wie in Abbildung 1.

Demo-Programm-Struktur

Die allgemeine Struktur des Demo-Programm mit den meisten WriteLine-Anweisungen entfernt und einige kleinere Änderungen, präsentiert sich in Abbildung 3.Die RBF-Netzwerk-Funktionalität ist in Klasse RadialNet enthalten.Klasse Helfer enthält drei Display-Methoden.

Abbildung 3 RBF Netzwerkstruktur Demo Programm

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

Um das Demoprogramm zu erstellen, startete ich Visual Studio 2012. Die Demo hat keine signifikanten .NET-Abhängigkeiten, so dass beliebige Version von Visual Studio arbeiten sollte. Ich habe eine neue C#-Konsole-Appli­kation-Projekt mit dem Namen RadialNetworksInputOutput. Nachdem der Template-Code geladen, ich Datei Program.cs in Radial NetIOProgram.cs umbenannt und Visual Studio Klasse Program automatisch entsprechend umbenannt. Ich löschte alle unnötigen using-Anweisungen am Anfang des Quellcodes.

Sie sollten die Anweisungen in der Main-Methode problemlos verstehen können. Die Anweisung, die das RBF-Netzwerk-Objekt instanziiert ist:

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

Die vier Anweisungen, die RBF-Netzwerk-Parameter-Werte zu laden sind:

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

Die Anweisung, die lädt die Eingabe und berechnet und gibt die RBF Netz-Ausgabe ist:

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

Klasse RadialNet

Die Definition der RBF-Netzwerk-Klasse beginnt mit:

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

Der Zweck dieser Klasse-Mitglieder sollte klar sein, auf der Grundlage der Erklärung der wie ein RBF-Netzwerk die Ausgabe berechnet. Die Gewichte werden als Array von Arrays Prägung-Matrix gespeichert, wobei der erste Index gibt den versteckten Knoten und der zweite Index verweist auf den Ausgabeknoten. Die C#-Sprache, im Gegensatz zu den meisten Sprachen unterstützt einen echte Matrix-Datentyp, und vielleicht möchten es anstelle eines Arrays von Arrays für die Gewichte-Matrix zu verwenden.

Der RadialNet-Konstruktor wird wie folgt definiert:

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

Wenn Sie das Diagramm in folgender Abbildung 2, du wirst sehen, wie die Größe der einzelnen Klasse Array und Matrix ist verwandt mit NumInput, NumHidden und NumOutput. Eine statische Hilfsmethode, MakeMatrix, wird durch den Konstruktor nur, um den Code ein bisschen sauberer aufgerufen. Methode MakeMatrix wird folgendermaßen definiert:

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

Klasse RadialNet hat vier Methoden, um die Werte der Zentroide, Standardabweichungen, Gewichte und Voreingenommenheit. Neuartiger Bauweise, den Konstruktor, um alle RBF-Parameterwerte annehmen zu überladen ist, aber ich bevorzuge separate Set-Methoden in den meisten Situationen. Methode SetCentroids ist:

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

Methode SetStdDevs ist:

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

Methode SetWeights ist:

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

Methode SetBiases ist:

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

Die ComputeOutputs-Methode

Das Herz der Klasse RadialNet ist die Methode ComputeOutputs. Die Methodendefinition beginnt:

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

Hier werden X-Eingang Werte in Mitglied Array Eingänge einfach kopiert. Da die Methode ComputeOutputs verwendet, jedoch ändert sich nicht die Werte der X-Eingang, Mitglied Array Eingänge ist nicht wirklich erforderlich. In einigen Fällen möchten Sie jedoch einige vorläufige Verarbeitung der X-Eingang durchzuführen. Und ich glaube, dass mit einem expliziten Klasse Eingänge Array ist ein sauberer Design und Wert die zusätzlichen Werte kopieren. Das lokale hOutputs-Array enthält die Ausgaben der einzelnen versteckte Knoten. Neuartiger Bauweise ist hOutputs als ein Klassenmember definiert.

Als nächstes berechnet ComputeOutputs die Ausgänge für jeden versteckten Knoten:

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

Der Abstand wird durch eine statische Hilfsmethode, Entfernung berechnet, die definiert ist:

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

Beachten Sie, dass Distanz eine Quadratwurzel-Operation führt und dass dieser Wert in Variable d gespeichert sind, die dann quadriert wird. Alternativ kann eine Methode DistanceSquared, die Distanz identisch mit Ausnahme der Aufruf der Quadratwurzel-Funktion ist, und dann nicht quadratisch den Wert von d. Obwohl dieser Ansatz effizienter ist, macht es den Code synchron mit den standard-Mathematik-Definitionen verwendet in der RBF-Literatur.

Der Code in ComputeOutputs, die die endgültigen Ausgaben berechnet wird:

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

Methode ComputeOutputs endet oben durch Kopieren der Werte im Array Mitglied Ausgänge auf einen Rückgabewert:

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

Neuartiger Bauweise soll ComputeOutputs mit einem void-Rückgabetyp, und definieren eine separate GetOutputs-Methode.

总结

Sowie die Erklärung, die in diesem Artikel vorgestellten sollten erhalten Sie gestartet, wenn Sie radial Basis Funktion Netze erkunden wollen. Es gibt viele verschiedene Arten von RBF Netze. Die RBF net in diesem Artikel wird eine Gauß-Funktion zum hidden-Node-Ausgabe verwendet. RBF Netze können viele andere Funktionen, mit Namen wie Multi-quadratische und thin-Plate-Splines. Die bestimmte Funktion, die von einem RBF-Netzwerk verwendet wird den Kernel des Netzes bezeichnet.

Sie wundern sich vielleicht, genau wo die eher exotische Architektur des RBF Netze kommt. RBF Netze waren ein Ergebnis der akademischen Forschung in die Theorie der Funktion Angleichung. Es kann nachgewiesen, dass mit ein paar Annahmen und lose sprechend, RBF Netze jede mathematische Funktion replizieren können. Dies bedeutet in der Theorie zumindest, RBF Netze verwendet werden können, um Vorhersagen auf Daten zu erstellen, die zugrunde liegende Modell folgt. Neuronale Netze teilen diese Universal-Funktion-Eigenschaft. Meiner Meinung nach ist es nicht klar, ob RBF Netze sind mehr oder weniger wirksam als neuronale Netze oder ungefähr dasselbe, wenn es Computerlernen Einstufung und Vorhersage darum. Allerdings gibt es gute Hinweise, dass RBF Netze viel schneller als neuronale Netze ausgebildet werden können, und im Gegensatz zu neuronalen Netzen, die in der Regel sehr große Mengen von Trainingsdaten erfordern, RBF Netze auch mit kleinen Mengen von Trainingsdaten arbeiten.

Um ein RBF-Netzwerk verwenden, um Vorhersagen für ein realistisches Problem zu machen, muss das Netzwerk ausgebildet werden. Dies bedeutet, mit vorhandenen historische Daten und Suche nach den besten Satz von Zentroide, Standardabweichungen, Gewichte und Bias-Werte – das heißt, der Satz von Parameterwerten, die RBF Netz Ausgänge generiert, die die historischen Daten am ehesten entsprechen. Training ein RBF Netz gehört auch die optimale Anzahl von versteckten Knoten zu finden. RBF Netze Training ist ein interessantes Problem, das in einem späteren Artikel erklärt wird.

Dr. James McCaffrey* arbeitet für Microsoft Research in Redmond, Washington Er arbeitete an verschiedenen Microsoft-Produkten, einschließlich Internet Explorer und Bing. Er kann erreicht werden unter jammc@microsoft.com.*

Unser Dank gilt dem folgenden technischen Experten für die Durchsicht dieses Artikels: Dan Liebling (Microsoft Research)