März 2019

Band 34, Nummer 3

[C#]

Support Vector Machines mit C#

Von James McCaffrey

Eine Support Vector Machine (SVM) ist ein Softwaresystem, das mithilfe von Daten Vorhersagen treffen kann. Der ursprüngliche Typ der SVM wurde entwickelt, um eine binäre Klassifizierung durchzuführen, z.B. um basierend auf Größe, Gewicht und Jahreseinkommen vorherzusagen, ob eine Person männlich oder weiblich ist. Es gibt auch Variationen von SVMs, die eine Mehrklassenklassifizierung (Vorhersage einer von mindestens drei Klassen) und eine Regression (Vorhersage eines numerischen Werts) durchführen können.

In diesem Artikel stelle ich ein vollständiges, funktionsfähiges Beispiel für eine SVM vor, die nur mit reinem C# ohne externe Bibliotheken implementiert wird. Die Zielrichtung dieses Artikels lässt sich gut anhand des Demoprogramms aus Abbildung 1 nachvollziehen.

SVM-Demoprogramm in Aktion
Abbildung 1: SVM-Demoprogramm in Aktion

Das Demoprogramm beginnt mit dem Einrichten von acht Dummy-Trainingsdatenelementen. Jedes Element verfügt über drei Prädiktorwerte, gefolgt von der vorherzusagenden Klasse, die als -1 oder +1 codiert ist. Die Dummydaten stellen kein echtes Problem dar, daher besitzen die Prädiktorwerte keine besondere Bedeutung. In einem realistischen SVM-Problem ist es wichtig, die Prädiktorwerte zu normalisieren, in der Regel durch Anwenden der Min-Max-Normalisierung, sodass alle Werte zwischen 0,0 und 1,0 skaliert sind.

Das Demoprogramm erstellt einen SVM-Klassifizierer, der eine polynomische Kernelfunktion verwendet. (Ich werde Kernelfunktionen gleich näher erläutern.) Das Training des SVM-Modells hat drei Stützvektoren (Support Vectors) generiert: (4, 5, 7), (7, 4, 2) und (9, 7, 5). Diese sind die Trainingsdatenelemente [0], [1] und [4]. Jedem Stützvektor ist ein Gewichtungswert zugeordnet: (-0,000098, -0,000162, 0,000260). Zusätzlich weist ein SVM-Modell einen einzelnen Wert auf, der als Bias bezeichnet wird. Für die Demodaten lautet dieser Wert -2,505727.

Die Stützvektoren, Gewichtungen und Biaswerte definieren das trainierte SVM-Modell. Das Demoprogramm generiert aus dem Modell prognostizierte Klassenwerte für jedes der acht Trainingselemente. Ein negativer Entscheidungswert entspricht einer vorhergesagten Klassenbezeichnung von -1, ein positiver Entscheidungswert einer vorhergesagten Klasse von +1. Das trainierte Modell sagt daher alle acht Trainingselemente richtig voraus. Dies ist nicht sonderlich überraschend, weil das Problem so einfach ist.

Die Demo schließt mit der Vorhersage der Klasse für ein neues, bisher unbekanntes Element mit Prädiktorwerten (3, 5, 7) ab. Der berechnete Entscheidungswert ist -1,274, und damit ist die vorhergesagte Klassenbezeichnung -1. Die Berechnung des Entscheidungswerts wird weiter unten in diesem Artikel erläutert.

Dieser Artikel geht davon aus, dass Sie über mittlere bis fortgeschrittene Programmierkenntnisse mit C# verfügen, er setzt aber nicht voraus, dass Sie mit SVMs vertraut sind. Das Demoprogramm wurde mit C# programmiert, und obwohl es kompliziert ist, sollten Sie auf Wunsch in der Lage sein, ein Refactoring in eine andere Sprache (z.B. Java oder Python) durchzuführen.

Der Code für das Demoprogramm ist zu lang, um ihn in diesem Artikel in seiner Gesamtheit darzustellen. Der vollständige Quellcode ist jedoch im begleitenden Dateidownload enthalten. Die gesamte normale Fehlerprüfung wurde entfernt, um die Hauptideen so klar wie möglich darzustellen.

Allgemeine Programmstruktur

Abbildung 2 zeigt die Struktur des Demoprogramms. Die gesamte Steuerungslogik ist in einer einzigen Main-Methode enthalten. Die vom Programm definierte Klasse SupportVectorMachine deklariert alle Memberfelder als öffentlich, damit Sie sie einfacher programmgesteuert untersuchen können.

Ich habe Visual Studio 2017 verwendet, um das Demoprogramm zu erstellen, aber es gibt keine wesentlichen Abhängigkeiten von .NET Framework, sodass jede Version von Visual Studio gut funktionieren sollte. Ich habe eine neue C#-Konsolenanwendung erstellt und ihr den Namen „SVM_CSharp“ gegeben. Nachdem der Vorlagencode in das Editor-Fenster geladen wurde, habe ich alle nicht benötigten using-Anweisungen entfernt und dann einen Verweis auf die Collections.Generic-Assembly hinzugefügt. Ich habe im Fenster des Projektmappen-Explorers mit der rechten Maustaste auf „Program.cs“ geklickt, die Datei in „SVM_Program.cs“ umbenannt und Visual Studio die automatische Umbenennung der Klasse „Program“ gestattet.

Abbildung 2: Struktur des Demoprogramms

using System;
using System.Collections.Generic;
namespace SVM_CSharp
{
  class SVM_Program
  {
    static void Main(string[] args)
    {
      // Set up training data
      // Create SVM object, set parameters
      // Train the SVM
      // Display SVM properties
      // Use trained SVM to make a prediction
    }
  }
  public class SupportVectorMachine
  {
    // All member fields are declared public
    public SupportVectorMachine(string kernelType,
      int seed) . .
    public double PolyKernel(double[] v1, double[] v2) . .
    public double ComputeDecision(double[] input) . .
    public int Train(double[][] X_matrix,
      int[] y_vector, int maxIter) . .
    public double Accuracy(double[][] X_matrix,
      int[] y_vector) . .
    private bool TakeStep(int i1, int i2,
      double[][] X_matrix, int[] y_vector) . .
    private int ExamineExample(int i2, double[][] X_matrix,
      int[] y_vector) . .
    private double ComputeAll(double[] vector,
      double[][] X_matrix, int[] y_vector) . .
  }
}

Verwenden der SVM

Das Demoprogramm richtet acht hartcodierte Trainingselemente ein:

double[][] train_X = new double[8][] {
  new double[] { 4,5,7 },
  ...
  new double[] { 8,9,10 }  };
int[] train_y = new int[8]{ -1, -1, -1, -1, 1, 1, 1, 1 };

In einem Nicht-Demoszenario sollten Sie die Prädiktorwerte normalisieren, und Sie würden Ihre Daten wahrscheinlich außerdem in einer Textdatei speichern. Der SVM-Klassifizierer wird wie folgt erstellt:

var svm = new SupportVectorMachine("poly", 0);
svm.gamma = 1.0;
svm.coef = 0.0;
svm.degree = 2;

Das Argument „poly“ ist wirklich ein Dummywert, da die SVM für die Verwendung einer polynomischen Kernelfunktion hartcodiert ist. Das Argument „0“ ist ein Ausgangswert für die zufällige Komponente des Trainingsalgorithmus. Die Argumente „gamma“, „coef“ (auch als „constant“ bezeichnet) und „degree“ sind Parameter für die polynomische Kernelfunktion. Im nächsten Schritt werden Parameter für den Trainingsalgorithmus angegeben:

svm.complexity = 1.0;
svm.epsilon = 0.001;
svm.tolerance = 0.001;
int maxIter = 1000;

Alle diese Werte sind Hyperparameter, die durch Versuch und Irrtum ermittelt werden müssen. Die größte Herausforderung bei der Verwendung einer SVM-Implementierung ist das Verständnis des zu verwendenden Kernels, der Kernelparameter und der Trainingsparameter. Das Training wird durch eine einzelne Anweisung ausgeführt:

int iter = svm.Train(train_X, train_y, maxIter);

Das Training eines SVM-Klassifizierers ist ein iterativer Prozess, und die Train-Methode gibt die tatsächliche Anzahl der ausgeführten Iterationen als Hilfe beim Debuggen zurück, wenn etwas schief geht. Nach dem Training enthält das SVM-Objekt eine List<double[]>-Sammlung der Stützvektoren, ein Array, das die Modellgewichtungen (eine pro Stützvektor) enthält, sowie einen einzelnen Biaswert. Diese werden wie folgt angezeigt:

foreach (double[] vec in svm.supportVectors) {
  for (int i = 0; i < vec.Length; ++i)
    Console.Write(vec[i].ToString("F1") + "  ");
  Console.WriteLine("");
}
for (int i = 0; i < svm.weights.Length; ++i)
  Console.Write(svm.weights[i].ToString("F6") + " ");
Console.WriteLine("");
Console.WriteLine("Bias = " + svm.bias.ToString("F6") + "\n");

Die Demo schließt mit dem Treffen einer Vorhersage ab:

double[] unknown = new double[] { 3, 5, 7 };
double predDecVal = svm.ComputeDecision(unknown);
Console.WriteLine("Predicted value for (3.0 5.0 7.0) = " +
  predDecVal.ToString("F3"));
int predLabel = Math.Sign(predDecVal);
Console.WriteLine("Predicted label for (3.0 5.0 7.0) = " +
  predLabel);

Der Entscheidungswert ist vom Typ „double“. Wenn der Entscheidungswert negativ ist, ist die vorhergesagte Klasse -1, wenn er positiv ist, ist die vorhergesagte Klasse +1.

Grundlegendes zu SVMs

SVMs sind ziemlich schwer zu verstehen und extrem schwierig zu implementieren. Sehen Sie sich das Diagramm in Abbildung 3 an. Das Ziel besteht darin, eine Regel zu erstellen, die zwischen den roten und den türkisfarbenen Daten unterscheidet. Die Grafik zeigt ein Problem, bei dem die Daten nur zwei Dimensionen (Anzahl der Prädiktorvariablen) aufweisen, damit das Problem visualisiert werden kann, aber SVMs können mit Daten mit drei oder mehr Dimensionen arbeiten.

Grundlegende SVM-Konzepte
Abbildung 3: Grundlegende SVM-Konzepte

Eine SVM ermittelt die breitestmögliche Trennfläche zwischen den beiden Klassen und identifiziert dann mindestens einen Punkt aus jeder Klasse, der dem Rand der Trennfläche am nächsten liegt.

Um einen neuen, bisher unbekannten Datenpunkt zu klassifizieren, müssen Sie nur feststellen, auf welche Seite der Mitte der Trennfläche der neue Punkt fällt. In Abbildung 3 werden der eingekreiste rote Punkt bei (0,3, 0,65) und die eingekreisten türkisfarbenen Punkte bei (0,5, 0,75) und (0,65, 0,6) als „Stützvektoren“ bezeichnet. In meinen Gedanken stelle ich sie mir jedoch als „Stützpunkte“ vor, weil ich Vektoren normalerweise als Linien betrachte.

Es gibt drei große Herausforderungen, die gelöst werden müssen, um eine funktionsfähige SVM zu implementieren. Erstens: Wie gehen Sie vor, wenn die Daten nicht so wie in Abbildung 3 linear trennbar sind? Zweitens: Wie ermitteln Sie die Werte der Stützvektoren, Gewichtungen und Bias? Drittens: Wie gehen Sie mit Trainingsdatenpunkten um, die anormal sind und sich auf der falschen Seite der Trennfläche befinden?

Wie dieser Artikel zeigt, können Sie mit nichtlinear trennbaren Daten arbeiten, indem Sie eine so genannte Kernelfunktion verwenden. Sie können die Stützvektoren, Gewichtungen und Bias mit einem Algorithmus namens „Sequenzielle Minimaloptimierung“ (SMO) bestimmen. Und Sie können auf inkonsistente Trainingsdaten ein Konzept anwenden, das als „Komplexität“ bezeichnet wird. Dabei werden anormale Daten mit einer Strafe belegt.

Kernelfunktionen

Es gibt viele verschiedene Arten von Kernelfunktionen. Kurz gesagt, nimmt eine Kernelfunktion zwei Vektoren an und kombiniert sie in irgendeiner Weise zu einem einzigen Skalarwert. Obwohl es nicht offensichtlich ist, können Sie durch die Verwendung einer Kernelfunktion einer SVM ermöglichen, Daten zu verarbeiten, die nicht linear trennbar sind. Dies wird als „der Kerneltrick“ bezeichnet.

Angenommen, Sie haben einen Vektor v1 = (3, 5, 2) und einem zweiten Vektor v2 = (4, 1, 0). Ein sehr einfacher Kernel wird als linearer Kernel bezeichnet und gibt die Summe der Produkte der Vektorelemente zurück:

K(v1, v2) = (3 * 4) + (5 * 1) + (2 * 0) = 17.0

Viele Kernelfunktionen verfügen über einen optionalen Skalierungsfaktor, der oft als „Gamma“ bezeichnet wird. Für das vorherige Beispiel gilt Folgendes, wenn Gamma auf 0,5 festgelegt ist:

K(v1, v2) = 0.5 * [(3 * 4) + (5 * 1) + (2 * 0)] = 8.5

Das Demoprogramm verwendet einen polynomischen Kernel mit degree = 2, gamma = 1.0 und constant = 0. Das heißt, Sie berechnen die Summe der Produkte, multiplizieren dann mit Gamma, addieren die Konstante und potenzieren dann auf „degree“. Beispiele:

K(v1, v2) = [1.0 * ((3*4) + (5*1) + (2*0)) + 0]^2 = (1 * 17 + 0)^2 = 289.0

Der polynomische Kernel wird durch das Demoprogramm wie folgt implementiert:

public double PolyKernel(double[] v1, double[] v2)
{
  double sum = 0.0;
  for (int i = 0; i < v1.Length; ++i)
    sum += v1[i] * v2[i];
  double z = this.gamma * sum + this.coef;
  return Math.Pow(z, this.degree);
}

Die Werte von „gamma“, „degree“ und „constant“ (als „coef“ bezeichnet, um einen Namenskonflikt mit einem Sprachschlüsselwort zu vermeiden) sind Klassenmember, und ihre Werte werden an anderer Stelle angegeben. Das Demoprogramm verwendet eine hartcodierte Kernelfunktion. Wenn Sie also mit einer anderen Funktion experimentieren möchten, müssen Sie sie selbst implementieren.

Eine gängige Alternative zum polynomischen Kernel ist der RBF-Kernel (Radiale Basisfunktion). Das heißt, Sie addieren die quadrierten Differenzen zwischen den Elementen, multiplizieren mit negativem Gamma und potenzieren dann auf e (Eulersche Zahl, etwa 2,718). Als Code könnte der RBF-Kernel folgendermaßen aussehen:

public double RbfKernel(double[] v1, double[] v2)
{
  double sum = 0.0;
  for (int i = 0; i < v1.Length; ++i)
    sum += (v1[i] - v2[i]) * (v1[i] - v2[i]);
    return Math.Exp(-this.gamma * sum);
}

Beachten Sie, dass verschiedene Kernelfunktionen über unterschiedliche Parameter verfügen. Die linearen und RBF-Kernel erfordern nur Gamma, der polynomische Kernel erfordert jedoch Gamma, „degree“ und Konstante. Die Auswahl der zu verwendenden Kernelfunktion und die Werte der Parameter, die für die verwendete Kernelfunktion gelten, sind freie wählbare Parameter und müssen durch Versuch und Irrtum bestimmt werden. Alle Klassifizierungstechniken für maschinelles Lernen weisen Hyperparameter auf, aber SVMs neigen dazu, besonders empfindlich auf ihre Hyperparameterwerte zu reagieren.

Der sequenzielle minimale Optimierungsalgorithmus

Es gibt viele Algorithmen, die verwendet werden können, um die Stützvektoren für ein SVM-Problem zu bestimmen. Der SMO-Algorithmus wird zu diesem Zweck am häufigsten verwendet. Das Demoprogramm folgt der ursprünglichen Beschreibung von SMO in der Forschungsarbeit aus dem Jahr 1998 „Sequential Minimal Optimization: A Fast Algorithm for Training Support Vector Machines“ (Sequenzielle minimale Optimierung: Ein schneller Algorithmus für das Training von Support Vector Machines), die Sie im Internet problemlos finden können.

Der SMO-Algorithmus ist sehr komplex, und eine vollständige Erläuterung würde etwa 200 Seiten umfassen (ich weiß das, weil ich einmal ein ganzes Buch rezensiert habe, das sich ausschließlich mit SMO beschäftigt). SMO verfügt über drei Schlüsselfunktionen: eine übergeordnete Train-Funktion, die eine ExamineExample-Hilfsfunktion aufruft, die eine TakeStep-Hilfsfunktion aufruft.

Dies ist die Signatur von TakeStep: private bool TakeStep(int i1, int i2, double[][] X_matrix, int[] y_vector). Der Parameter X_matrix enthält die Prädiktorwerte der Trainingsdaten. Parameter y_vector enthält die Zielwerte der Trainingsdaten, die entweder-1 oder + 1 lauten. Die i1- und i2-Parameter sind ein erster Index und ein zweiter Index, der auf die Trainingsdaten verweist. Bei jedem Aufruf von TakeStep versucht der Algorithmus, eine bessere Lösung zu finden und gibt TRUE zurück, wenn eine Verbesserung anhand der beiden Trainingsdatenelemente gefunden wird, andernfalls wird FALSE zurückgegeben.

Dies ist die Signatur von ExamineExample: private int Examine­Example(nt i2, double[][] X_matrix, int[] y_vector). Die Funktion gibt die Anzahl der Änderungen zurück, die aufgetreten sind, damit TakeStep ermitteln kann, ob ein Fortschritt erzielt wurde.

Sowohl TakeStep als auch ExamineExample verwenden eine Variable namens „complexity“ mit Klassengültigkeitsbereich. Größere Komplexitätswerte belegen Ausreißertrainingsdaten zunehmend mit einer Strafe und zwingen den SMO-Algorithmus (auf Kosten der Modellüberanpassung), eine Lösung zu finden, die diese behandelt. Da „complexity“ ein von SMO verwendeter Parameter ist, ist er im Gegensatz zu Parametern, die mit der verwendeten Kernelfunktion verbunden sind und die vorhanden oder nicht vorhanden sein können, immer vorhanden.

Die TakeStep-Funktion verwendet eine Variable namens „epsilon“ mit Klassengültigkeitsbereich, und die ExamineExample-Funktion verwendet eine Variable namens „tolerance“ mit Klassengültigkeitsbereich. Beide Variablen sind kleine Werte, die in der Demo standardmäßig auf 0,001 festgelegt sind. Epsilon wird intern verwendet, um zu bestimmen, wann die Iteration beendet werden soll, was wiederum die Anzahl der gefundenen Stützvektoren beeinflusst. Tolerance wird bei Berechnungsfehlern verwendet. Die Werte von „epsilon“ und „tolerance“ sind frei wählbare Parameter, und die Auswirkungen einer Änderung variieren stark (von einer sehr kleinen bis zu einer sehr großen Auswirkung), je nach dem speziellen Problem, das Sie gerade untersuchen.

Der Code für die Train-Methode wird in Abbildung 4 gezeigt. Die Methode ist iterativ und gibt die Anzahl der Iterationen zurück, die ausgeführt wurden. Die Methode akzeptiert einen maxIter-Parameter, um einen festen Grenzwert für die Anzahl der ausgeführten Iterationen festzulegen. Theoretisch wird der SMO-Algorithmus immer konvergieren und die Iteration beenden, aber die Theorie stimmt bei einem so komplexen Algorithmus wie SMO nicht immer mit der Praxis überein.

Abbildung 4: Die Trainingsmethode

public int Train(double[][] X_matrix, int[] y_vector, int maxIter)
{
  int N = X_matrix.Length;
  this.alpha = new double[N];
  this.errors = new double[N];
  int numChanged = 0;
  bool examineAll = true;
  int iter = 0;
  while (iter < maxIter && numChanged > 0 || examineAll == true) {
    ++iter;
    numChanged = 0;
    if (examineAll == true) {
      for (int i = 0; i < N; ++i)
        numChanged += ExamineExample(i, X_matrix, y_vector);
    }
    else {
      for (int i = 0; i < N; ++i)
        if (this.alpha[i] != 0 && this.alpha[i] !=
          this.complexity)
          numChanged += ExamineExample(i, X_matrix, y_vector);
    }
    if (examineAll == true)
      examineAll = false;
    else if (numChanged == 0)
      examineAll = true;
  } // While
  List<int> indices = new List<int>();  // support vectors
  for (int i = 0; i < N; ++i) {
    // Only store vectors with Lagrange multipliers > 0
    if (this.alpha[i] > 0) indices.Add(i);
  }
  int num_supp_vectors = indices.Count;
  this.weights = new double[num_supp_vectors];
  for (int i = 0; i < num_supp_vectors; ++i) {
    int j = indices[i];
    this.supportVectors.Add(X_matrix[j]);
    this.weights[i] = this.alpha[j] * y_vector[j];
  }
  this.bias = -1 * this.bias;
  return iter;
}

Zusätzlich zur expliziten Rückgabe der Anzahl der ausgeführten Iterationen findet und speichert Train die Indizes der Trainingsdatenelemente, die Stützvektoren sind. Nachdem die Anzahl der Stützvektoren bekannt ist, kann das Array, das die Werte der Gewichtungen enthält, zugeordnet werden. Die Gewichtungswerte sind Alphawerte ungleich NULL.

Die Train-Methode verfügt über viele mögliche Anpassungsmöglichkeiten. Beispielsweise speichert der Democode Stützvektoren als eine List<double[]>-Sammlung. Eine Alternative besteht darin, nur die Indizes der Stützvektoren in einer List<int>-Sammlung oder in einem int[]-Arrayobjekt zu speichern. Eine sorgfältige Untersuchung der Train-Methode ist der beste Weg, um SVMs und den SMO-Algorithmus zu verstehen.

Grundlegendes zum SVM-Mechanismus

Wenn Sie sich Abbildung 1 ansehen, erkennen Sie, dass die trainierte SVM über drei Stützvektoren verfügt: (4, 5, 7), (7, 4, 2) und (9, 7, 5). Und das Modell verfügt über drei Gewichtungswerte = (-0,000098, -0,000162, 0,000260) und ein Bias = -2,506. Der Entscheidungswert für die Eingabe (3, 5, 7) wird berechnet, indem der Wert der Kernelfunktion mit jedem der drei Stützvektoren berechnet wird, dann jeder Kernelwert mit seiner entsprechenden Gewichtung multipliziert, addiert und dann das Bias addiert wird:

x = (3, 5, 7)
sv1 = (4, 5, 7)
sv2 = (7, 4, 2)
sv3 = (9, 7, 5)
K(x, sv1) * wt1 = 7396.0 * -0.000098 = -0.725
K(x, sv2) * wt2 = 3025.0 * -0.000162 = -0.490
K(x, sv3) * wt3 = 9409.0 * 0.000260 = 2.446
decision = -0.725 + -0.490 + 2.446 + -2.506 = -1.274
prediction = Sign(decision) = -1

Beachten Sie Folgendes: Wenn die Prädiktorwerte nicht normalisiert sind (wie in der Demo), können die Werte der Kernel sehr groß werden, was bewirkt, dass die Werte der Gewichtungen sehr klein werden. Dies kann möglicherweise zu arithmetischen Fehlern führen.

Der SVM-Mechanismus zeigt die Stärken und Schwächen der Technik auf. SVM konzentriert sich nur auf die wichtigsten Stützvektoren und ist daher in der Regel widerstandsfähig gegen schlechte Trainingsdaten. Wenn die Anzahl der Stützvektoren klein ist, ist eine SVM in einem gewissen Maß interpretierbar. Dies ist im Vergleich zu vielen anderen Techniken ein Vorteil. Im Vergleich zu vielen anderen Klassifizierungstechniken (insbesondere neuronalen Netzen) können SVMs oft gut mit begrenzten Trainingsdaten arbeiten. Die Verarbeitung sehr großer Trainingsdatasets kann hingegen problematisch sein. Der größte Nachteil von SVMs besteht darin, dass SVMs sehr komplex sind und Sie den Wert zahlreicher Hyperparameter angeben müssen.

Zusammenfassung

Wie dieser Artikel zeigt, ist das Implementieren einer Support Vector Machine recht komplex und schwierig. Aus diesem Grund stehen nur sehr wenige Implementierungen einer SVM-Bibliothek zur Verfügung. Die meisten SVM-Bibliotheken basieren auf einer C++-Implementierung namens LibSVM, die von einer Gruppe von Forschern erstellt wurde. Da der Aufruf von C++ oft schwierig ist, gibt es mehrere Bibliotheken, die Wrapper um LibSVM bereitstellen, die in Python, Java, C# und anderen Sprachen geschrieben sind.

Durch das Experimentieren mit dem in diesem Artikel vorgestellten Code gewinnen Sie ein gutes Verständnis dafür, wie SVMs genau funktionieren. Außerdem können Sie eine Bibliotheksimplementierung effektiver nutzen. Da der Code in diesem Artikel in sich geschlossen und vereinfacht ist, können Sie alternative Kernelfunktionen und deren Parameter sowie die Parameter des SMO-Trainingsalgorithmus („epsilon“, „tolerance“ und „complexity“) untersuchen.


Dr. James McCaffreyist in Redmond (Washington, USA) für Microsoft Research tätig. Er hat an verschiedenen wichtigen Microsoft-Produkten mitgearbeitet, unter anderem an Internet Explorer und Bing. Dr. McCaffrey erreichen Sie unter jamccaff@microsoft.com.

Unser Dank gilt den folgenden technischen Experten von Microsoft für die Durchsicht dieses Artikels: Yihe Dong, Chris Lee