JavaRush /Java-Blog /Random-DE /Maschinelles Lernen für Java-Entwickler, Teil 2

Maschinelles Lernen für Java-Entwickler, Teil 2

Veröffentlicht in der Gruppe Random-DE
Maschinelles Lernen für Java-Entwickler, Teil 1
Maschinelles Lernen für Java-Entwickler, Teil 2 – 1

Schätzung der Zielfunktion

Erinnern wir uns daran, dass die Zielfunktion , auch Vorhersagefunktion genannt, das Ergebnis des Vorbereitungs- oder Trainingsprozesses ist. Mathematisch gesehen besteht die Herausforderung darin, eine Funktion zu finden, die eine Variable als Eingabe verwendet хund den vorhergesagten Wert zurückgibt у.
Maschinelles Lernen für Java-Entwickler, Teil 2 - 2
Beim maschinellen Lernen wird eine Kostenfunktion (J(θ))verwendet, um den Fehlerwert oder „Kosten“ einer bestimmten Zielfunktion zu berechnen.
Maschinelles Lernen für Java-Entwickler, Teil 2–3
Die Kostenfunktion zeigt, wie gut das Modell zu den Trainingsdaten passt. Um die Kosten der oben gezeigten Zielfunktion zu bestimmen, muss der quadratische Fehler jedes Beispielhauses berechnet werden (i). Der Fehler ist der Abstand zwischen dem berechneten Wert уund dem tatsächlichen Wert ydes Hauses aus dem Beispiel i.
Maschinelles Lernen für Java-Entwickler, Teil 2–4
Beispielsweise beträgt der reale Preis eines Hauses mit einer Fläche von 1330 = 6.500.000 € . Und die Differenz zwischen dem prognostizierten Hauspreis und der trainierten Zielfunktion beträgt 7.032.478 € : Die Differenz (oder der Fehler) beträgt 532.478 € . Sie können diesen Unterschied auch in der Grafik oben sehen. Die Differenz (oder der Fehler) wird für jedes Preis-Bereichs-Trainingspaar als vertikale gestrichelte rote Linie angezeigt. Nachdem Sie die Kosten der trainierten Zielfunktion berechnet haben, müssen Sie den quadratischen Fehler für jedes Haus im Beispiel summieren und den Hauptwert berechnen. Je kleiner der Preiswert ist (J(θ)), desto genauer sind die Vorhersagen unserer Zielfunktion. Listing 3 zeigt eine einfache Java-Implementierung einer Kostenfunktion, die als Eingabe eine Zielfunktion, eine Liste von Trainingsdaten und damit verbundene Beschriftungen verwendet. Die Vorhersagewerte werden in einer Schleife berechnet und der Fehler wird durch Subtrahieren des tatsächlichen Preiswerts (aus dem Etikett entnommen) berechnet. Später wird das Quadrat der Fehler summiert und der Fehlerwert berechnet. Die Kosten werden als Wert vom Typ zurückgegeben double:

Auflistung-3

public static double cost(Function<ltDouble[], Double> targetFunction,
 List<ltDouble[]> dataset,
 List<ltDouble> labels) {
 int m = dataset.size();
 double sumSquaredErrors = 0;

 // рассчет квадрата ошибки («разницы») для каждого тренировочного примера и //добавление его к сумме
 for (int i = 0; i < m; i++) {
 // получаем вектор признаков из текущего примера
 Double[] featureVector = dataset.get(i);
 // предсказываем Bedeutung и вычисляем ошибку базируясь на реальном
 //значении (метка)
 double predicted = targetFunction.apply(featureVector);
 double label = labels.get(i);
 double gap = predicted - label;
 sumSquaredErrors += Math.pow(gap, 2);
 }

 // Вычисляем и возращаем Bedeutung ошибки (чем меньше тем лучше)
 return (1.0 / (2 * m)) * sumSquaredErrors;
}
Möchten Sie etwas über Java lesen? Treten Sie der Java-Entwicklergruppe bei !

Lernen der Zielfunktion

Obwohl die Kostenfunktion dabei hilft, die Qualität der Zielfunktion und der Theta-Parameter zu bewerten, müssen Sie dennoch die am besten geeigneten Theta-Parameter finden. Sie können hierfür den Gradientenabstiegsalgorithmus verwenden.

Gradientenabstieg

Der Gradientenabstieg minimiert die Kostenfunktion. (J(θ))Dies bedeutet, dass es verwendet wird, um die Theta-Parameter zu finden, die basierend auf den Trainingsdaten die minimalen Kosten verursachen . Hier ist ein vereinfachter Algorithmus zur Berechnung neuer, besser geeigneter Theta-Werte:
Maschinelles Lernen für Java-Entwickler, Teil 2–5
Daher verbessern sich die Parameter des Theta-Vektors mit jeder Iteration des Algorithmus. Der Lernkoeffizient α gibt die Anzahl der Berechnungen bei jeder Iteration an. Diese Berechnungen können durchgeführt werden, bis „gute“ Theta-Werte gefunden werden. Die folgende lineare Regressionsfunktion hat beispielsweise drei Theta-Parameter:
Maschinelles Lernen für Java-Entwickler, Teil 2–6
Bei jeder Iteration wird ein neuer Wert für jeden der Theta-Parameter berechnet: , , und . Nach jeder Iteration kann mithilfe des neuen Theta-Vektors 0 , θ 1 , θ 2 } eine neue, geeignetere Implementierung erstellt werden . Listing -4 zeigt den Java-Code für den Gradient Decay-Algorithmus. Theta für die Regressionsfunktion wird mithilfe von Trainingsdaten, Markerdaten und Lernrate trainiert . Das Ergebnis wird eine verbesserte Zielfunktion unter Verwendung von Theta-Parametern sein. Die Methode wird immer wieder aufgerufen und übergibt dabei die neue Zielfunktion und die neuen Theta-Parameter aus früheren Berechnungen. Und diese Aufrufe werden wiederholt, bis die konfigurierte Zielfunktion ein Mindestplateau erreicht: θ0θ1θ2LinearRegressionFunction(α)train()

Auflistung-4

public static LinearRegressionFunction train(LinearRegressionFunction targetFunction,
 List<ltDouble[]> dataset,
 List<ltDouble> labels,
 double alpha) {
 int m = dataset.size();
 double[] thetaVector = targetFunction.getThetas();
 double[] newThetaVector = new double[thetaVector.length];

 // вычисление нового значения тета для каждого Element тета массива
 for (int j = 0; j < thetaVector.length; j++) {
 // сумируем разницу ошибки * признак
 double sumErrors = 0;
 for (int i = 0; i < m; i++) {
 Double[] featureVector = dataset.get(i);
 double error = targetFunction.apply(featureVector) - labels.get(i);
 sumErrors += error * featureVector[j];
 }

 //вычисляем новые значения тета
 double gradient = (1.0 / m) * sumErrors;
 newThetaVector[j] = thetaVector[j] - alpha * gradient;
 }

 return new LinearRegressionFunction(newThetaVector);
}
Um sicherzustellen, dass die Kosten kontinuierlich sinken, können Sie die Kostenfunktion J(θ)nach jedem Trainingsschritt ausführen. Nach jeder Iteration sollten die Kosten sinken. Geschieht dies nicht, bedeutet dies, dass der Wert des Lernkoeffizienten zu groß ist und der Algorithmus einfach den Mindestwert verfehlt hat. In einem solchen Fall schlägt der Gradientenabfallalgorithmus fehl. Die Diagramme unten zeigen die Zielfunktion unter Verwendung der neuen, berechneten Theta-Parameter, beginnend mit dem Start-Theta-Vektor {1.0, 1.0}. Die linke Spalte zeigt die Darstellung der Vorhersagefunktion nach 50 Iterationen; mittlere Spalte nach 200 Wiederholungen; und die rechte Spalte nach 1000 Wiederholungen. Daraus können wir erkennen, dass der Preis nach jeder Iteration sinkt und die neue Zielfunktion immer besser passt. Nach 500-600 Wiederholungen ändern sich die Theta-Parameter nicht mehr wesentlich und der Preis erreicht ein stabiles Plateau. Danach kann die Genauigkeit der Zielfunktion auf diese Weise nicht verbessert werden.
Maschinelles Lernen für Java-Entwickler, Teil 2–7
Auch wenn in diesem Fall die Kosten nach 500–600 Iterationen nicht mehr wesentlich sinken, ist die Zielfunktion immer noch nicht optimal. Dies deutet auf eine Diskrepanz hin . Beim maschinellen Lernen wird der Begriff „Inkonsistenz“ verwendet, um darauf hinzuweisen, dass der Lernalgorithmus keine zugrunde liegenden Trends in den Daten findet. Bei größeren Immobilien ist aufgrund der Praxiserfahrung mit einer Reduzierung des Quadratmeterpreises zu rechnen. Daraus können wir schließen, dass das für den Lernprozess der Zielfunktion verwendete Modell nicht gut genug zu den Daten passt. Die Diskrepanz ist häufig auf eine zu starke Vereinfachung des Modells zurückzuführen. Dies ist in unserem Fall passiert, die Zielfunktion ist zu einfach und verwendet für die Analyse einen einzigen Parameter – die Fläche des Hauses. Diese Informationen reichen jedoch nicht aus, um den Preis eines Hauses genau vorherzusagen.

Funktionen hinzufügen und skalieren

Wenn Sie feststellen, dass Ihre Zielfunktion nicht dem Problem entspricht, das Sie lösen möchten, muss sie angepasst werden. Eine übliche Methode zur Korrektur von Inkonsistenzen besteht darin, dem Merkmalsvektor zusätzliche Merkmale hinzuzufügen. Am Beispiel des Preises eines Hauses können Sie Merkmale wie die Anzahl der Zimmer oder das Alter des Hauses hinzufügen. Das heißt, anstatt einen Vektor mit einem Merkmalswert {size}zur Beschreibung eines Hauses zu verwenden, können Sie beispielsweise einen Vektor mit mehreren Werten verwenden. {size, number-of-rooms, age}. In einigen Fällen reicht die Anzahl der Merkmale in den verfügbaren Trainingsdaten nicht aus. Dann lohnt es sich, den Versuch zu unternehmen, Polynommerkmale zu verwenden, die anhand vorhandener Merkmale berechnet werden. Sie haben beispielsweise die Möglichkeit, die Zielfunktion zur Ermittlung des Preises eines Hauses um ein berechnetes Merkmal Quadratmeter (x2) zu erweitern:
Maschinelles Lernen für Java-Entwickler, Teil 2–8
Die Verwendung mehrerer Features erfordert eine Feature-Skalierung , die zur Standardisierung des Bereichs über verschiedene Features hinweg verwendet wird. Somit ist der Wertebereich für das Attribut „Größe 2“ deutlich größer als der Wertebereich für das Attribut „Größe“. Ohne Feature-Skalierung wird Größe 2 die Kostenfunktion übermäßig beeinflussen. Der durch das Attribut „Größe 2“ verursachte Fehler ist deutlich größer als der durch das Attribut „Größe“ verursachte Fehler. Ein einfacher Feature-Skalierungsalgorithmus ist unten angegeben:
Maschinelles Lernen für Java-Entwickler, Teil 2–9
Dieser Algorithmus ist in der Klasse FeaturesScalingim folgenden Beispielcode implementiert. Die Klasse FeaturesScalingstellt eine kommerzielle Methode zum Erstellen einer Skalierungsfunktion dar, die auf Trainingsdaten abgestimmt ist. Intern werden die Trainingsdateninstanzen zur Berechnung der Durchschnitts-, Minimal- und Maximalwerte verwendet. Die resultierende Funktion nimmt den Merkmalsvektor und erzeugt einen neuen mit den skalierten Merkmalen. Die Funktionsskalierung ist sowohl für den Lernprozess als auch für den Vorhersageprozess erforderlich, wie unten gezeigt:
// создание массива данных
List<ltDouble[]> dataset = new ArrayList<>();
dataset.add(new Double[] { 1.0, 90.0, 8100.0 }); // feature vector of house#1
dataset.add(new Double[] { 1.0, 101.0, 10201.0 }); // feature vector of house#2
dataset.add(new Double[] { 1.0, 103.0, 10609.0 }); // ...
//...

// создание меток
List<ltDouble> labels = new ArrayList<>();
labels.add(249.0); // price label of house#1
labels.add(338.0); // price label of house#2
labels.add(304.0); // ...
//...

// создание расширенного списка признаков
Function<ltDouble[], Double[]> scalingFunc = FeaturesScaling.createFunction(dataset);
List<ltDouble[]> scaledDataset = dataset.stream().map(scalingFunc).collect(Collectors.toList());

// создаем функцию которая инициализирует теты и осуществляет обучение //используя коэффициент обучения 0.1

LinearRegressionFunction targetFunction = new LinearRegressionFunction(new double[] { 1.0, 1.0, 1.0 });
for (int i = 0; i < 10000; i++) {
 targetFunction = Learner.train(targetFunction, scaledDataset, labels, 0.1);
}

// делаем предсказание стоимости дома с площадью 600 m2
Double[] scaledFeatureVector = scalingFunc.apply(new Double[] { 1.0, 600.0, 360000.0 });
double predictedPrice = targetFunction.apply(scaledFeatureVector);
Da immer mehr Funktionen hinzugefügt werden, erhöht sich die Anpassung an die Zielfunktion, aber seien Sie vorsichtig. Wenn Sie zu weit gehen und zu viele Funktionen hinzufügen, lernen Sie möglicherweise eine Zielfunktion kennen, die übergeeignet ist.

Überübereinstimmung und Kreuzvalidierung

Überanpassung tritt auf, wenn die Zielfunktion oder das Zielmodell zu gut zu den Trainingsdaten passt, sodass Rauschen oder zufällige Variationen in den Trainingsdaten erfasst werden. Ein Beispiel für eine Überanpassung ist in der Grafik ganz rechts unten dargestellt:
Maschinelles Lernen für Java-Entwickler, Teil 2–10
Allerdings schneidet ein Überanpassungsmodell bei Trainingsdaten sehr gut ab, bei realen unbekannten Daten jedoch schlecht. Es gibt mehrere Möglichkeiten, eine Überanpassung zu vermeiden.
  • Verwenden Sie für das Training einen größeren Datensatz.
  • Verwenden Sie weniger Funktionen, wie in den Grafiken oben gezeigt.
  • Verwenden Sie einen verbesserten Algorithmus für maschinelles Lernen, der die Regularisierung berücksichtigt.
Wenn ein Vorhersagealgorithmus die Trainingsdaten überpasst, müssen Merkmale eliminiert werden, die seiner Genauigkeit nicht zugute kommen. Die Schwierigkeit besteht darin, Merkmale zu finden, die einen größeren Einfluss auf die Genauigkeit der Vorhersage haben als andere. Wie in den Diagrammen dargestellt, kann die Überanpassung visuell anhand von Diagrammen ermittelt werden. Dies funktioniert gut für Diagramme mit 2 oder 3 Koordinaten. Es wird jedoch schwierig, das Diagramm zu zeichnen und auszuwerten, wenn Sie mehr als zwei Features verwenden. Bei der Kreuzvalidierung testen Sie Modelle nach dem Training erneut mit Daten, die dem Algorithmus nach Abschluss des Trainingsprozesses unbekannt sind. Die verfügbaren gekennzeichneten Daten sollten in drei Sätze unterteilt werden:
  • Trainingsdaten;
  • Verifizierungsdaten;
  • Testdaten.
In diesem Fall sollten 60 Prozent der gekennzeichneten Datensätze, die die Häuser charakterisieren, im Prozess des Trainings von Varianten des Zielalgorithmus verwendet werden. Nach dem Trainingsprozess sollte die Hälfte der verbleibenden Daten (die zuvor nicht verwendet wurden) verwendet werden, um zu überprüfen, ob der trainierte Zielalgorithmus bei den unbekannten Daten gut funktioniert. Typischerweise wird der Algorithmus zur Verwendung ausgewählt, der eine bessere Leistung als andere aufweist. Die verbleibenden Daten werden zur Berechnung des Fehlerwerts für das endgültig ausgewählte Modell verwendet. Es gibt andere Kreuzvalidierungstechniken, wie zum Beispiel k-fold . Ich werde sie in diesem Artikel jedoch nicht beschreiben.

Tools für maschinelles Lernen und Weka-Framework

Die meisten Frameworks und Bibliotheken bieten eine umfangreiche Sammlung von Algorithmen für maschinelles Lernen. Darüber hinaus bieten sie eine praktische High-Level-Schnittstelle zum Trainieren, Testen und Verarbeiten von Datenmodellen. Weka ist eines der beliebtesten Frameworks für die JVM. Weka ist eine praktische Java-Bibliothek, die grafische Tests zur Validierung von Modellen enthält. Das folgende Beispiel verwendet die Weka-Bibliothek, um einen Trainingsdatensatz zu erstellen, der Features und Beschriftungen enthält. Methode setClassIndex()- zum Markieren. In Weka wird ein Label als Klasse definiert:
// определяем атрибуты для признаков и меток
ArrayList<ltAttribute> attributes = new ArrayList<>();
Attribute sizeAttribute = new Attribute("sizeFeature");
attributes.add(sizeAttribute);
Attribute squaredSizeAttribute = new Attribute("squaredSizeFeature");
attributes.add(squaredSizeAttribute);
Attribute priceAttribute = new Attribute("priceLabel");
attributes.add(priceAttribute);


// создаем и заполняем список признаков 5000 примеров
Instances trainingDataset = new Instances("trainData", attributes, 5000);
trainingDataset.setClassIndex(trainingSet.numAttributes() - 1);
Instance instance = new DenseInstance(3);

instance.setValue(sizeAttribute, 90.0);
instance.setValue(squaredSizeAttribute, Math.pow(90.0, 2));
instance.setValue(priceAttribute, 249.0);
trainingDataset.add(instance);
Instance instance = new DenseInstance(3);
instance.setValue(sizeAttribute, 101.0);
...
Der Datensatz und das Beispielobjekt können aus einer Datei gespeichert und geladen werden. Weka verwendet ARFF (Attribute Relation File Format), das von den Grafik-Benchmarks von Weka unterstützt wird. Dieser Datensatz wird verwendet, um eine Zielfunktion zu trainieren, die in Weka als Klassifikator bekannt ist. Zunächst müssen Sie die Zielfunktion definieren. Der folgende Code LinearRegressionerstellt eine Instanz des Klassifikators. Dieser Klassifikator wird mit dem trainiert buildClassifier(). Die Methode buildClassifier()wählt Theta-Parameter basierend auf Trainingsdaten auf der Suche nach dem besten Zielmodell aus. Mit Weka müssen Sie sich keine Gedanken über die Festlegung der Lernrate oder der Anzahl der Iterationen machen. Weka führt auch die Feature-Skalierung unabhängig durch.
Classifier targetFunction = new LinearRegression();
targetFunction.buildClassifier(trainingDataset);
Sobald diese Einstellungen vorgenommen wurden, kann die Zielfunktion verwendet werden, um den Preis des Hauses vorherzusagen, wie unten gezeigt:
Instances unlabeledInstances = new Instances("predictionset", attributes, 1);
unlabeledInstances.setClassIndex(trainingSet.numAttributes() - 1);
Instance unlabeled = new DenseInstance(3);
unlabeled.setValue(sizeAttribute, 1330.0);
unlabeled.setValue(squaredSizeAttribute, Math.pow(1330.0, 2));
unlabeledInstances.add(unlabeled);

double prediction = targetFunction.classifyInstance(unlabeledInstances.get(0));
Weka bietet eine Klasse Evaluationzum Testen eines trainierten Klassifikators oder Modells. Im folgenden Code wird ein ausgewähltes Array von Validierungsdaten verwendet, um falsche Ergebnisse zu vermeiden. Die Messergebnisse (Fehlerkosten) werden auf der Konsole angezeigt. Typischerweise werden Bewertungsergebnisse verwendet, um Modelle zu vergleichen, die mit unterschiedlichen maschinellen Lernalgorithmen oder Variationen davon trainiert wurden:
Evaluation evaluation = new Evaluation(trainingDataset);
evaluation.evaluateModel(targetFunction, validationDataset);
System.out.println(evaluation.toSummaryString("Results", false));
Das obige Beispiel verwendet eine lineare Regression, die numerische Werte, beispielsweise den Preis eines Hauses, basierend auf Eingabewerten vorhersagt. Die lineare Regression unterstützt die Vorhersage kontinuierlicher numerischer Werte. Um Binärwerte („Ja“ und „Nein“) vorherzusagen, müssen Sie andere Algorithmen für maschinelles Lernen verwenden. Zum Beispiel Entscheidungsbaum, neuronale Netze oder logistische Regression.
// использование логистической регрессии
Classifier targetFunction = new Logistic();
targetFunction.buildClassifier(trainingSet);
Mit einem dieser Algorithmen können Sie beispielsweise vorhersagen, ob es sich bei einer E-Mail-Nachricht um Spam handelt, oder um das Wetter vorherzusagen oder um vorherzusagen, ob sich ein Haus gut verkaufen lässt. Wenn Sie Ihrem Algorithmus beibringen möchten, das Wetter oder die Verkaufsgeschwindigkeit eines Hauses vorherzusagen, benötigen Sie einen anderen Datensatz, z. B.topseller:
// использование атрибута маркера topseller anstatt атрибута маркера цена
ArrayList<string> classVal = new ArrayList<>();
classVal.add("true");
classVal.add("false");

Attribute topsellerAttribute = new Attribute("topsellerLabel", classVal);
attributes.add(topsellerAttribute);
Dieser Datensatz wird zum Trainieren eines neuen Klassifikators verwendet topseller. Nach dem Training sollte der Vorhersageaufruf einen Token-Klassenindex zurückgeben, der zum Erhalten des vorhergesagten Werts verwendet werden kann.
int idx = (int) targetFunction.classifyInstance(unlabeledInstances.get(0));
String prediction = classVal.get(idx);

Abschluss

Obwohl maschinelles Lernen eng mit Statistiken verbunden ist und viele mathematische Konzepte verwendet, können Sie mit dem Toolkit für maschinelles Lernen mit der Integration von maschinellem Lernen in Ihre Programme beginnen, ohne tiefgreifende Kenntnisse in Mathematik zu benötigen. Je besser Sie jedoch die zugrunde liegenden Algorithmen für maschinelles Lernen verstehen, wie z. B. den linearen Regressionsalgorithmus, den wir in diesem Artikel untersucht haben, desto besser können Sie den richtigen Algorithmus auswählen und ihn für eine optimale Leistung optimieren. Übersetzung aus dem Englischen. Autor: Gregor Roth, Softwarearchitekt, JavaWorld.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION