RSVP für Ihr lokales TensorFlow Everywhere-Event noch heute!
Diese Seite wurde von der Cloud Translation API übersetzt.
Switch to English

Exemplarische Vorgehensweise für das Modelltraining

Ansicht auf TensorFlow.org Quelle auf GitHub anzeigen

In diesem Handbuch wird Swift for TensorFlow vorgestellt, indem ein Modell für maschinelles Lernen erstellt wird, das Irisblumen nach Arten kategorisiert. Es verwendet Swift für TensorFlow, um:

  1. Ein Modell bauen,
  2. Trainieren Sie dieses Modell anhand von Beispieldaten und
  3. Verwenden Sie das Modell, um Vorhersagen über unbekannte Daten zu treffen.

TensorFlow-Programmierung

In diesem Handbuch werden diese allgemeinen Swift for TensorFlow-Konzepte verwendet:

  • Importieren Sie Daten mit der Epochs-API.
  • Erstellen Sie Modelle mit Swift-Abstraktionen.
  • Verwenden Sie Python-Bibliotheken mit der Python-Interoperabilität von Swift, wenn keine reinen Swift-Bibliotheken verfügbar sind.

Dieses Tutorial ist wie viele TensorFlow-Programme aufgebaut:

  1. Importieren und analysieren Sie die Datensätze.
  2. Wählen Sie den Modelltyp.
  3. Trainiere das Modell.
  4. Bewerten Sie die Wirksamkeit des Modells.
  5. Verwenden Sie das trainierte Modell, um Vorhersagen zu treffen.

Setup-Programm

Importe konfigurieren

Importieren Sie TensorFlow und einige nützliche Python-Module.

import TensorFlow
import PythonKit
// This cell is here to display the plots in a Jupyter Notebook.
// Do not copy it into another environment.
%include "EnableIPythonDisplay.swift"
print(IPythonDisplay.shell.enable_matplotlib("inline"))
('inline', 'module://ipykernel.pylab.backend_inline')

let plt = Python.import("matplotlib.pyplot")
import Foundation
import FoundationNetworking
func download(from sourceString: String, to destinationString: String) {
    let source = URL(string: sourceString)!
    let destination = URL(fileURLWithPath: destinationString)
    let data = try! Data.init(contentsOf: source)
    try! data.write(to: destination)
}

Das Problem der Irisklassifizierung

Stellen Sie sich vor, Sie sind Botaniker und suchen nach einer automatisierten Methode, um jede gefundene Irisblume zu kategorisieren. Maschinelles Lernen bietet viele Algorithmen, um Blumen statistisch zu klassifizieren. Zum Beispiel könnte ein ausgeklügeltes maschinelles Lernprogramm Blumen anhand von Fotografien klassifizieren. Unsere Ambitionen sind bescheidener - wir werden Irisblüten anhand der Längen- und Breitenmaße ihrer Kelchblätter und Blütenblätter klassifizieren.

Die Gattung Iris umfasst etwa 300 Arten, aber unser Programm wird nur die folgenden drei Arten klassifizieren:

  • Iris setosa
  • Iris virginica
  • Iris versicolor
Blütenblattgeometrie im Vergleich zu drei Irisarten: Iris setosa, Iris virginica und Iris versicolor
Abbildung 1. Iris setosa (von Radomil , CC BY-SA 3.0), Iris versicolor (von Dlanglois , CC BY-SA 3.0) und Iris virginica (von Frank Mayfield , CC BY-SA 2.0).

Glücklicherweise hat bereits jemand einen Datensatz mit 120 Irisblüten mit den Kelchblatt- und Blütenblattmaßen erstellt. Dies ist ein klassischer Datensatz, der bei Klassifizierungsproblemen für maschinelles Lernen für Anfänger beliebt ist.

Importieren und analysieren Sie den Trainingsdatensatz

Laden Sie die Dataset-Datei herunter und konvertieren Sie sie in eine Struktur, die von diesem Swift-Programm verwendet werden kann.

Laden Sie den Datensatz herunter

Laden Sie die Trainingsdatensatzdatei von http://download.tensorflow.org/data/iris_training.csv herunter

let trainDataFilename = "iris_training.csv"
download(from: "http://download.tensorflow.org/data/iris_training.csv", to: trainDataFilename)

Überprüfen Sie die Daten

Dieses Dataset, iris_training.csv , ist eine iris_training.csv Text-Datei, in der tabellarische Daten gespeichert werden, die als durch Kommas getrennte Werte (CSV) formatiert sind. Schauen wir uns die ersten 5 Einträge an.

let f = Python.open(trainDataFilename)
for _ in 0..<5 {
    print(Python.next(f).strip())
}
print(f.close())
120,4,setosa,versicolor,virginica
6.4,2.8,5.6,2.2,2
5.0,2.3,3.3,1.0,1
4.9,2.5,4.5,1.7,2
4.9,3.1,1.5,0.1,0
None

Beachten Sie in dieser Ansicht des Datensatzes Folgendes:

  1. Die erste Zeile ist eine Kopfzeile mit Informationen zum Datensatz:
    • Insgesamt gibt es 120 Beispiele. Jedes Beispiel verfügt über vier Funktionen und einen von drei möglichen Markennamen.
  2. Nachfolgende Zeilen sind Datensätze, ein Beispiel pro Zeile, wobei:
    • Die ersten vier Felder sind Merkmale : Dies sind Merkmale eines Beispiels. Hier enthalten die Felder Float-Nummern, die Blumenmaße darstellen.
    • Die letzte Spalte ist die Bezeichnung : Dies ist der Wert, den wir vorhersagen möchten. Für diesen Datensatz ist es ein ganzzahliger Wert von 0, 1 oder 2, der einem Blumennamen entspricht.

Schreiben wir das in Code:

let featureNames = ["sepal_length", "sepal_width", "petal_length", "petal_width"]
let labelName = "species"
let columnNames = featureNames + [labelName]

print("Features: \(featureNames)")
print("Label: \(labelName)")
Features: ["sepal_length", "sepal_width", "petal_length", "petal_width"]
Label: species

Jedes Etikett ist mit einem Zeichenfolgennamen verknüpft (z. B. "setosa"), aber maschinelles Lernen basiert normalerweise auf numerischen Werten. Die Beschriftungsnummern werden einer benannten Darstellung zugeordnet, z. B.:

  • 0 : Iris setosa
  • 1 : Iris versicolor
  • 2 : Iris virginica

Weitere Informationen zu Funktionen und Beschriftungen finden Sie im Abschnitt ML-Terminologie des Crashkurses für maschinelles Lernen .

let classNames = ["Iris setosa", "Iris versicolor", "Iris virginica"]

Erstellen Sie ein Dataset mit der Epochs-API

Die Epochs-API von Swift for TensorFlow ist eine allgemeine API zum Lesen und Umwandeln von Daten in ein für das Training verwendetes Formular.

let batchSize = 32

/// A batch of examples from the iris dataset.
struct IrisBatch {
    /// [batchSize, featureCount] tensor of features.
    let features: Tensor<Float>

    /// [batchSize] tensor of labels.
    let labels: Tensor<Int32>
}

/// Conform `IrisBatch` to `Collatable` so that we can load it into a `TrainingEpoch`.
extension IrisBatch: Collatable {
    public init<BatchSamples: Collection>(collating samples: BatchSamples)
        where BatchSamples.Element == Self {
        /// `IrisBatch`es are collated by stacking their feature and label tensors
        /// along the batch axis to produce a single feature and label tensor
        features = Tensor<Float>(stacking: samples.map{$0.features})
        labels = Tensor<Int32>(stacking: samples.map{$0.labels})
    }
}

Da die von uns heruntergeladenen Datensätze im CSV-Format vorliegen, schreiben wir eine Funktion zum Laden in die Daten als Liste von IrisBatch-Objekten

/// Initialize an `IrisBatch` dataset from a CSV file.
func loadIrisDatasetFromCSV(
        contentsOf: String, hasHeader: Bool, featureColumns: [Int], labelColumns: [Int]) -> [IrisBatch] {
        let np = Python.import("numpy")

        let featuresNp = np.loadtxt(
            contentsOf,
            delimiter: ",",
            skiprows: hasHeader ? 1 : 0,
            usecols: featureColumns,
            dtype: Float.numpyScalarTypes.first!)
        guard let featuresTensor = Tensor<Float>(numpy: featuresNp) else {
            // This should never happen, because we construct featuresNp in such a
            // way that it should be convertible to tensor.
            fatalError("np.loadtxt result can't be converted to Tensor")
        }

        let labelsNp = np.loadtxt(
            contentsOf,
            delimiter: ",",
            skiprows: hasHeader ? 1 : 0,
            usecols: labelColumns,
            dtype: Int32.numpyScalarTypes.first!)
        guard let labelsTensor = Tensor<Int32>(numpy: labelsNp) else {
            // This should never happen, because we construct labelsNp in such a
            // way that it should be convertible to tensor.
            fatalError("np.loadtxt result can't be converted to Tensor")
        }

        return zip(featuresTensor.unstacked(), labelsTensor.unstacked()).map{IrisBatch(features: $0.0, labels: $0.1)}

    }

Wir können jetzt die CSV-Ladefunktion verwenden, um den Trainingsdatensatz zu laden und ein TrainingEpochs Objekt zu erstellen

let trainingDataset: [IrisBatch] = loadIrisDatasetFromCSV(contentsOf: trainDataFilename, 
                                                  hasHeader: true, 
                                                  featureColumns: [0, 1, 2, 3], 
                                                  labelColumns: [4])

let trainingEpochs: TrainingEpochs = TrainingEpochs(samples: trainingDataset, batchSize: batchSize)

Das TrainingEpochs Objekt ist eine unendliche Folge von Epochen. Jede Epoche enthält IrisBatch . Schauen wir uns das erste Element der ersten Epoche an.

let firstTrainEpoch = trainingEpochs.next()!
let firstTrainBatch = firstTrainEpoch.first!.collated
let firstTrainFeatures = firstTrainBatch.features
let firstTrainLabels = firstTrainBatch.labels

print("First batch of features: \(firstTrainFeatures)")
print("firstTrainFeatures.shape: \(firstTrainFeatures.shape)")
print("First batch of labels: \(firstTrainLabels)")
print("firstTrainLabels.shape: \(firstTrainLabels.shape)")
First batch of features: [[5.1, 2.5, 3.0, 1.1],
 [6.4, 3.2, 4.5, 1.5],
 [4.9, 3.1, 1.5, 0.1],
 [5.0, 2.0, 3.5, 1.0],
 [6.3, 2.5, 5.0, 1.9],
 [6.7, 3.1, 5.6, 2.4],
 [4.9, 3.1, 1.5, 0.1],
 [7.7, 2.8, 6.7, 2.0],
 [6.7, 3.0, 5.0, 1.7],
 [7.2, 3.6, 6.1, 2.5],
 [4.8, 3.0, 1.4, 0.1],
 [5.2, 3.4, 1.4, 0.2],
 [5.0, 3.5, 1.3, 0.3],
 [4.9, 3.1, 1.5, 0.1],
 [5.0, 3.5, 1.6, 0.6],
 [6.7, 3.3, 5.7, 2.1],
 [7.7, 3.8, 6.7, 2.2],
 [6.2, 3.4, 5.4, 2.3],
 [4.8, 3.4, 1.6, 0.2],
 [6.0, 2.9, 4.5, 1.5],
 [5.0, 3.0, 1.6, 0.2],
 [6.3, 3.4, 5.6, 2.4],
 [5.1, 3.8, 1.9, 0.4],
 [4.8, 3.1, 1.6, 0.2],
 [7.6, 3.0, 6.6, 2.1],
 [5.7, 3.0, 4.2, 1.2],
 [6.3, 3.3, 6.0, 2.5],
 [5.6, 2.5, 3.9, 1.1],
 [5.0, 3.4, 1.6, 0.4],
 [6.1, 3.0, 4.9, 1.8],
 [5.0, 3.3, 1.4, 0.2],
 [6.3, 3.3, 4.7, 1.6]]
firstTrainFeatures.shape: [32, 4]
First batch of labels: [1, 1, 0, 1, 2, 2, 0, 2, 1, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 1, 0, 2, 0, 0, 2, 1, 2, 1, 0, 2, 0, 1]
firstTrainLabels.shape: [32]

Beachten Sie, dass die Funktionen für die ersten batchSize Beispiele in firstTrainFeatures zusammengefasst (oder gestapelt ) sind und dass die Beschriftungen für die ersten batchSize Beispiele in firstTrainLabels firstTrainLabels .

Sie können einige Cluster anzeigen, indem Sie mithilfe der Python-Matplotlib einige Features aus dem Stapel zeichnen:

let firstTrainFeaturesTransposed = firstTrainFeatures.transposed()
let petalLengths = firstTrainFeaturesTransposed[2].scalars
let sepalLengths = firstTrainFeaturesTransposed[0].scalars

plt.scatter(petalLengths, sepalLengths, c: firstTrainLabels.array.scalars)
plt.xlabel("Petal length")
plt.ylabel("Sepal length")
plt.show()

png

Use `print()` to show values.

Wählen Sie den Modelltyp

Warum modellieren?

Ein Modell ist eine Beziehung zwischen Features und dem Label. Für das Irisklassifizierungsproblem definiert das Modell die Beziehung zwischen den Kelch- und Blütenblattmessungen und der vorhergesagten Irisart. Einige einfache Modelle können mit wenigen Zeilen Algebra beschrieben werden, aber komplexe Modelle für maschinelles Lernen weisen eine große Anzahl von Parametern auf, die schwer zusammenzufassen sind.

Könnten Sie die Beziehung zwischen den vier Merkmalen und der Irisart ohne maschinelles Lernen bestimmen? Könnten Sie also traditionelle Programmiertechniken (z. B. viele bedingte Anweisungen) verwenden, um ein Modell zu erstellen? Vielleicht - wenn Sie den Datensatz lange genug analysiert haben, um die Beziehung zwischen Blütenblatt- und Kelchblattmessungen zu einer bestimmten Art zu bestimmen. Und dies wird bei komplizierteren Datensätzen schwierig - vielleicht unmöglich -. Ein guter Ansatz für maschinelles Lernen bestimmt das Modell für Sie . Wenn Sie dem richtigen Modelltyp für maschinelles Lernen genügend repräsentative Beispiele hinzufügen, ermittelt das Programm die Beziehungen für Sie.

Wählen Sie das Modell aus

Wir müssen die Art des zu trainierenden Modells auswählen. Es gibt viele Arten von Modellen, und die Auswahl eines guten Modells erfordert Erfahrung. Dieses Tutorial verwendet ein neuronales Netzwerk, um das Problem der Irisklassifizierung zu lösen. Neuronale Netze können komplexe Beziehungen zwischen Merkmalen und der Bezeichnung finden. Es ist ein stark strukturiertes Diagramm, das in eine oder mehrere verborgene Ebenen unterteilt ist . Jede verborgene Schicht besteht aus einem oder mehreren Neuronen . Es gibt mehrere Kategorien von neuronalen Netzen, und dieses Programm verwendet ein dichtes oder vollständig verbundenes neuronales Netz : Die Neuronen in einer Schicht empfangen Eingangsverbindungen von jedem Neuron in der vorherigen Schicht. Zum Beispiel zeigt 2 ein dichtes neuronales Netzwerk, das aus einer Eingangsschicht, zwei verborgenen Schichten und einer Ausgangsschicht besteht:

Ein Diagramm der Netzwerkarchitektur: Eingänge, 2 versteckte Schichten und Ausgänge
Abbildung 2. Ein neuronales Netzwerk mit Funktionen, verborgenen Schichten und Vorhersagen.

Wenn das Modell aus Abbildung 2 trainiert und mit einem unbeschrifteten Beispiel gefüttert wird, ergeben sich drei Vorhersagen: Die Wahrscheinlichkeit, dass es sich bei dieser Blume um die angegebene Irisart handelt. Diese Vorhersage nennt man Inferenz . In diesem Beispiel beträgt die Summe der Ausgabevorhersagen 1,0. In Abbildung 2 ist diese Vorhersage wie 0.02 : 0.02 für Iris setosa , 0.95 für Iris versicolor und 0.03 für Iris virginica . Dies bedeutet, dass das Modell mit einer Wahrscheinlichkeit von 95% vorhersagt, dass eine unbeschriftete Beispielblume eine Iris versicolor ist .

Erstellen Sie ein Modell mit der Swift for TensorFlow Deep Learning Library

Die Swift for TensorFlow Deep Learning Library definiert primitive Ebenen und Konventionen für die Verkabelung, wodurch Modelle einfach erstellt und experimentiert werden können.

Ein Modell ist ein struct dass Konform Layer , was bedeutet , dass sie eine definiert callAsFunction(_:) Methode , die Eingangskarten Tensor s zur Ausgabe Tensor s. Die Methode callAsFunction(_:) sequenziert die Eingabe häufig einfach über Unterschichten. Definieren wir ein IrisModel , das die Eingabe über drei Dense Unterschichten sequenziert.

import TensorFlow

let hiddenSize: Int = 10
struct IrisModel: Layer {
    var layer1 = Dense<Float>(inputSize: 4, outputSize: hiddenSize, activation: relu)
    var layer2 = Dense<Float>(inputSize: hiddenSize, outputSize: hiddenSize, activation: relu)
    var layer3 = Dense<Float>(inputSize: hiddenSize, outputSize: 3)

    @differentiable
    func callAsFunction(_ input: Tensor<Float>) -> Tensor<Float> {
        return input.sequenced(through: layer1, layer2, layer3)
    }
}

var model = IrisModel()

Die Aktivierungsfunktion bestimmt die Ausgabeform jedes Knotens in der Ebene. Diese Nichtlinearitäten sind wichtig - ohne sie würde das Modell einer einzelnen Schicht entsprechen. Es gibt viele verfügbare Aktivierungen, aber ReLU ist für versteckte Ebenen üblich.

Die ideale Anzahl versteckter Schichten und Neuronen hängt vom Problem und dem Datensatz ab. Wie viele Aspekte des maschinellen Lernens erfordert die Auswahl der besten Form des neuronalen Netzwerks eine Mischung aus Wissen und Experimentieren. Als Faustregel gilt: Wenn Sie die Anzahl der verborgenen Schichten und Neuronen erhöhen, wird in der Regel ein leistungsfähigeres Modell erstellt, für dessen effektives Training mehr Daten erforderlich sind.

Verwenden des Modells

Lassen Sie uns einen kurzen Blick darauf werfen, was dieses Modell mit einer Reihe von Funktionen macht:

// Apply the model to a batch of features.
let firstTrainPredictions = model(firstTrainFeatures)
print(firstTrainPredictions[0..<5])
[[  1.1514063,  -0.7520321,  -0.6730235],
 [  1.4915676,  -0.9158071,  -0.9957161],
 [  1.0549936,  -0.7799266,   -0.410466],
 [  1.1725322, -0.69009197,  -0.8345413],
 [  1.4870572,  -0.8644099,  -1.0958937]]

Hier gibt jedes Beispiel ein Logit für jede Klasse zurück.

Verwenden Sie die Softmax- Funktion, um diese Protokolle in eine Wahrscheinlichkeit für jede Klasse zu konvertieren :

print(softmax(firstTrainPredictions[0..<5]))
[[  0.7631462,  0.11375094, 0.123102814],
 [  0.8523791, 0.076757915,  0.07086295],
 [  0.7191151,  0.11478964,  0.16609532],
 [ 0.77540654,  0.12039323,  0.10420021],
 [  0.8541314,  0.08133837, 0.064530246]]

Wenn wir den argmax über Klassen hinweg nehmen, erhalten wir den vorhergesagten Klassenindex. Das Modell wurde jedoch noch nicht trainiert, daher sind dies keine guten Vorhersagen.

print("Prediction: \(firstTrainPredictions.argmax(squeezingAxis: 1))")
print("    Labels: \(firstTrainLabels)")
Prediction: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    Labels: [1, 1, 0, 1, 2, 2, 0, 2, 1, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 1, 0, 2, 0, 0, 2, 1, 2, 1, 0, 2, 0, 1]

Trainiere das Modell

Training ist die Phase des maschinellen Lernens, wenn das Modell schrittweise optimiert wird oder das Modell den Datensatz lernt . Ziel ist es, genug über die Struktur des Trainingsdatensatzes zu lernen, um Vorhersagen über unsichtbare Daten zu treffen. Wenn Sie zu viel über den Trainingsdatensatz erfahren, funktionieren die Vorhersagen nur für die Daten, die er gesehen hat, und sind nicht verallgemeinerbar. Dieses Problem wird als Überanpassung bezeichnet. Es ist so, als würde man sich die Antworten merken, anstatt zu verstehen, wie man ein Problem löst.

Das Irisklassifizierungsproblem ist ein Beispiel für überwachtes maschinelles Lernen : Das Modell wird anhand von Beispielen trainiert, die Beschriftungen enthalten. Beim unbeaufsichtigten maschinellen Lernen enthalten die Beispiele keine Beschriftungen. Stattdessen findet das Modell normalerweise Muster unter den Features.

Wählen Sie eine Verlustfunktion

Sowohl die Trainings- als auch die Evaluierungsphase müssen den Verlust des Modells berechnen. Dies misst, wie weit die Vorhersagen eines Modells von der gewünschten Bezeichnung abweichen, mit anderen Worten, wie schlecht die Leistung des Modells ist. Wir wollen diesen Wert minimieren oder optimieren.

Unser Modell berechnet seinen Verlust mithilfe der Funktion softmaxCrossEntropy(logits:labels:) , die die Klassenwahrscheinlichkeitsvorhersagen des Modells und das gewünschte Label verwendet und den durchschnittlichen Verlust über die Beispiele zurückgibt.

Berechnen wir den Verlust für das aktuelle untrainierte Modell:

let untrainedLogits = model(firstTrainFeatures)
let untrainedLoss = softmaxCrossEntropy(logits: untrainedLogits, labels: firstTrainLabels)
print("Loss test: \(untrainedLoss)")
Loss test: 1.7598655

Erstellen Sie einen Optimierer

Ein Optimierer wendet die berechneten Gradienten auf die Variablen des Modells an, um die loss zu minimieren. Sie können sich die Verlustfunktion als gekrümmte Oberfläche vorstellen (siehe Abbildung 3), und wir möchten den tiefsten Punkt finden, indem wir herumlaufen. Die Steigungen zeigen in Richtung des steilsten Aufstiegs - also fahren wir in die entgegengesetzte Richtung und bewegen uns den Hügel hinunter. Indem wir den Verlust und den Gradienten für jede Charge iterativ berechnen, passen wir das Modell während des Trainings an. Allmählich findet das Modell die beste Kombination aus Gewichten und Vorspannung, um Verluste zu minimieren. Und je geringer der Verlust, desto besser die Vorhersagen des Modells.

Optimierungsalgorithmen, die über die Zeit im 3D-Raum visualisiert werden.
Abbildung 3. Zeitlich optimierte Optimierungsalgorithmen im 3D-Raum.
(Quelle: Stanford Klasse CS231n , MIT Lizenz, Bildnachweis : Alec Radford )

Swift for TensorFlow bietet viele Optimierungsalgorithmen für das Training. Dieses Modell verwendet den SGD-Optimierer, der den SGD-Algorithmus (Stochastic Gradient Descent ) implementiert. Die learningRate legt die Schrittgröße fest, die für jede Iteration den Hügel hinunter verwendet werden soll. Dies ist ein Hyperparameter , den Sie normalerweise anpassen, um bessere Ergebnisse zu erzielen.

let optimizer = SGD(for: model, learningRate: 0.01)

Verwenden wir den optimizer , um einen einzelnen Gradientenabstiegsschritt durchzuführen. Zunächst berechnen wir den Gradienten des Verlusts in Bezug auf das Modell:

let (loss, grads) = valueWithGradient(at: model) { model -> Tensor<Float> in
    let logits = model(firstTrainFeatures)
    return softmaxCrossEntropy(logits: logits, labels: firstTrainLabels)
}
print("Current loss: \(loss)")
Current loss: 1.7598655

Als nächstes übergeben wir den soeben berechneten Gradienten an den Optimierer, der die differenzierbaren Variablen des Modells entsprechend aktualisiert:

optimizer.update(&model, along: grads)

Wenn wir den Verlust erneut berechnen, sollte er kleiner sein, da Gradientenabstiegsschritte (normalerweise) den Verlust verringern:

let logitsAfterOneStep = model(firstTrainFeatures)
let lossAfterOneStep = softmaxCrossEntropy(logits: logitsAfterOneStep, labels: firstTrainLabels)
print("Next loss: \(lossAfterOneStep)")
Next loss: 1.5318773

Trainingsschleife

Mit allen Teilen ist das Modell bereit für das Training! Eine Trainingsschleife führt die Datensatzbeispiele in das Modell ein, um bessere Vorhersagen zu treffen. Der folgende Codeblock richtet diese Trainingsschritte ein:

  1. Iterieren Sie über jede Epoche . Eine Epoche ist ein Durchgang durch den Datensatz.
  2. Iterieren Sie innerhalb einer Epoche jede Charge in der Trainingsepoche
  3. Sortieren Sie den Stapel und greifen Sie auf seine Merkmale ( x ) und Beschriftung ( y ) zu.
  4. Erstellen Sie anhand der Funktionen des sortierten Stapels eine Vorhersage und vergleichen Sie sie mit dem Etikett. Messen Sie die Ungenauigkeit der Vorhersage und verwenden Sie diese, um den Verlust und die Gradienten des Modells zu berechnen.
  5. Verwenden Sie den Gradientenabstieg, um die Variablen des Modells zu aktualisieren.
  6. Behalten Sie einige Statistiken zur Visualisierung im Auge.
  7. Wiederholen Sie dies für jede Epoche.

Die Variable epochCount gibt an, wie oft die Dataset-Sammlung epochCount werden soll. Gegenintuitiv garantiert ein längeres Training eines Modells kein besseres Modell. epochCount ist ein Hyperparameter , den Sie epochCount können. Die Auswahl der richtigen Anzahl erfordert normalerweise sowohl Erfahrung als auch Experimente.

let epochCount = 500
var trainAccuracyResults: [Float] = []
var trainLossResults: [Float] = []
func accuracy(predictions: Tensor<Int32>, truths: Tensor<Int32>) -> Float {
    return Tensor<Float>(predictions .== truths).mean().scalarized()
}

for (epochIndex, epoch) in trainingEpochs.prefix(epochCount).enumerated() {
    var epochLoss: Float = 0
    var epochAccuracy: Float = 0
    var batchCount: Int = 0
    for batchSamples in epoch {
        let batch = batchSamples.collated
        let (loss, grad) = valueWithGradient(at: model) { (model: IrisModel) -> Tensor<Float> in
            let logits = model(batch.features)
            return softmaxCrossEntropy(logits: logits, labels: batch.labels)
        }
        optimizer.update(&model, along: grad)

        let logits = model(batch.features)
        epochAccuracy += accuracy(predictions: logits.argmax(squeezingAxis: 1), truths: batch.labels)
        epochLoss += loss.scalarized()
        batchCount += 1
    }
    epochAccuracy /= Float(batchCount)
    epochLoss /= Float(batchCount)
    trainAccuracyResults.append(epochAccuracy)
    trainLossResults.append(epochLoss)
    if epochIndex % 50 == 0 {
        print("Epoch \(epochIndex): Loss: \(epochLoss), Accuracy: \(epochAccuracy)")
    }
}
Epoch 0: Loss: 1.475254, Accuracy: 0.34375
Epoch 50: Loss: 0.91668004, Accuracy: 0.6458333
Epoch 100: Loss: 0.68662673, Accuracy: 0.6979167
Epoch 150: Loss: 0.540665, Accuracy: 0.6979167
Epoch 200: Loss: 0.46283028, Accuracy: 0.6979167
Epoch 250: Loss: 0.4134724, Accuracy: 0.8229167
Epoch 300: Loss: 0.35054502, Accuracy: 0.8958333
Epoch 350: Loss: 0.2731444, Accuracy: 0.9375
Epoch 400: Loss: 0.23622067, Accuracy: 0.96875
Epoch 450: Loss: 0.18956228, Accuracy: 0.96875

Visualisieren Sie die Verlustfunktion im Laufe der Zeit

Während es hilfreich ist das Modell der Trainingsfortschritt zu drucken, ist es oft hilfreicher diesen Fortschritt zu sehen. Mit dem Python-Modul matplotlib können wir grundlegende Diagramme matplotlib .

Das Interpretieren dieser Diagramme erfordert einige Erfahrung, aber Sie möchten wirklich, dass der Verlust sinkt und die Genauigkeit steigt.

plt.figure(figsize: [12, 8])

let accuracyAxes = plt.subplot(2, 1, 1)
accuracyAxes.set_ylabel("Accuracy")
accuracyAxes.plot(trainAccuracyResults)

let lossAxes = plt.subplot(2, 1, 2)
lossAxes.set_ylabel("Loss")
lossAxes.set_xlabel("Epoch")
lossAxes.plot(trainLossResults)

plt.show()

png

Use `print()` to show values.

Beachten Sie, dass die y-Achsen der Diagramme nicht auf Null basieren.

Bewerten Sie die Wirksamkeit des Modells

Nachdem das Modell trainiert wurde, können wir einige Statistiken über seine Leistung erhalten.

Auswerten bedeutet zu bestimmen, wie effektiv das Modell Vorhersagen trifft. Um die Wirksamkeit des Modells bei der Irisklassifizierung zu bestimmen, übergeben Sie einige Kelch- und Blütenblattmessungen an das Modell und bitten Sie das Modell, vorherzusagen, welche Irisarten sie darstellen. Vergleichen Sie dann die Vorhersage des Modells mit der tatsächlichen Bezeichnung. Beispielsweise hat ein Modell, das bei der Hälfte der Eingabebeispiele die richtige Art ausgewählt hat, eine Genauigkeit von 0.5 . Abbildung 4 zeigt ein etwas effektiveres Modell, bei dem 4 von 5 Vorhersagen mit einer Genauigkeit von 80% korrekt sind:

Beispielfunktionen Etikette Modellvorhersage
5.9 3.0 4.3 1.5 1 1
6.9 3.1 5.4 2.1 2 2
5.1 3.3 1.7 0,5 0 0
6.0 3.4 4.5 1.6 1 2
5.5 2.5 4.0 1.3 1 1
Abbildung 4. Ein Irisklassifikator mit einer Genauigkeit von 80%.

Richten Sie den Testdatensatz ein

Die Bewertung des Modells ähnelt dem Training des Modells. Der größte Unterschied ist die Beispiele aus einer separaten kommen Testset anstatt dem Trainingssatz. Um die Wirksamkeit eines Modells fair beurteilen zu können, müssen sich die zur Bewertung eines Modells verwendeten Beispiele von den zum Trainieren des Modells verwendeten Beispielen unterscheiden.

Das Setup für den Testdatensatz ähnelt dem Setup für den Trainingsdatensatz. Laden Sie das Testset von http://download.tensorflow.org/data/iris_test.csv herunter:

let testDataFilename = "iris_test.csv"
download(from: "http://download.tensorflow.org/data/iris_test.csv", to: testDataFilename)

Laden Sie es nun in ein Array von IrisBatch :

let testDataset = loadIrisDatasetFromCSV(
    contentsOf: testDataFilename, hasHeader: true,
    featureColumns: [0, 1, 2, 3], labelColumns: [4]).inBatches(of: batchSize)

Bewerten Sie das Modell im Testdatensatz

Im Gegensatz zur Trainingsphase wertet das Modell nur eine einzige Epoche der Testdaten aus. In der folgenden Codezelle durchlaufen wir jedes Beispiel im Testsatz und vergleichen die Vorhersage des Modells mit der tatsächlichen Bezeichnung. Dies wird verwendet, um die Genauigkeit des Modells über den gesamten Testsatz zu messen.

// NOTE: Only a single batch will run in the loop since the batchSize we're using is larger than the test set size
for batchSamples in testDataset {
    let batch = batchSamples.collated
    let logits = model(batch.features)
    let predictions = logits.argmax(squeezingAxis: 1)
    print("Test batch accuracy: \(accuracy(predictions: predictions, truths: batch.labels))")
}
Test batch accuracy: 0.96666664

Wir können auf der ersten Charge sehen, dass das Modell normalerweise korrekt ist:

let firstTestBatch = testDataset.first!.collated
let firstTestBatchLogits = model(firstTestBatch.features)
let firstTestBatchPredictions = firstTestBatchLogits.argmax(squeezingAxis: 1)

print(firstTestBatchPredictions)
print(firstTestBatch.labels)
[1, 2, 0, 1, 1, 1, 0, 2, 1, 2, 2, 0, 2, 1, 1, 0, 1, 0, 0, 2, 0, 1, 2, 2, 1, 1, 0, 1, 2, 1]
[1, 2, 0, 1, 1, 1, 0, 2, 1, 2, 2, 0, 2, 1, 1, 0, 1, 0, 0, 2, 0, 1, 2, 1, 1, 1, 0, 1, 2, 1]

Verwenden Sie das trainierte Modell, um Vorhersagen zu treffen

Wir haben ein Modell trainiert und gezeigt, dass es gut - aber nicht perfekt - ist, Irisarten zu klassifizieren. Verwenden wir nun das trainierte Modell, um einige Vorhersagen für unbeschriftete Beispiele zu treffen. Das heißt, an Beispielen, die Features enthalten, aber keine Beschriftung.

In der Praxis können die unbeschrifteten Beispiele aus vielen verschiedenen Quellen stammen, darunter Apps, CSV-Dateien und Datenfeeds. Im Moment werden wir drei unbeschriftete Beispiele manuell bereitstellen, um ihre Beschriftungen vorherzusagen. Denken Sie daran, dass die Beschriftungsnummern einer benannten Darstellung wie folgt zugeordnet werden:

  • 0 : Iris setosa
  • 1 : Iris versicolor
  • 2 : Iris virginica
let unlabeledDataset: Tensor<Float> =
    [[5.1, 3.3, 1.7, 0.5],
     [5.9, 3.0, 4.2, 1.5],
     [6.9, 3.1, 5.4, 2.1]]

let unlabeledDatasetPredictions = model(unlabeledDataset)

for i in 0..<unlabeledDatasetPredictions.shape[0] {
    let logits = unlabeledDatasetPredictions[i]
    let classIdx = logits.argmax().scalar!
    print("Example \(i) prediction: \(classNames[Int(classIdx)]) (\(softmax(logits)))")
}
Example 0 prediction: Iris setosa ([   0.98731947,   0.012679046, 1.4035809e-06])
Example 1 prediction: Iris versicolor ([0.005065103,  0.85957265,  0.13536224])
Example 2 prediction: Iris virginica ([2.9613977e-05,     0.2637373,    0.73623306])