Tutorial: Automatisierte visuelle Überprüfung mithilfe von Transferlernen mit der ML.NET-Bildklassifizierungs-API

Erfahren Sie, wie Sie ein benutzerdefiniertes Deep-Learning-Modell mithilfe von Transferlernen, einem vorab trainierten TensorFlow-Modell und der ML.NET-Bildklassifizierungs-API trainieren, um Bilder von Betonoberflächen als gerissen oder nicht gerissen zu klassifizieren.

In diesem Tutorial lernen Sie, wie die folgenden Aufgaben ausgeführt werden:

  • Das Problem verstehen
  • Informationen zur ML.NET-Bildklassifizierungs-API
  • Grundlegendes zum vorab trainierten Modell
  • Trainieren eines benutzerdefinierten TensorFlow-Bildklassifizierungsmodells mithilfe von Transferlernen
  • Klassifizieren von Bildern mit dem benutzerdefinierten Modell

Voraussetzungen

Beispielübersicht zur Bildklassifizierung mit Transferlernen

Bei diesem Beispiel handelt es sich um eine C#.NET Core-Konsolenanwendung, die Bilder mit einem vorab mit Deep Learning trainierten TensorFlow-Modell klassifiziert. Den Code für dieses Beispiel finden Sie im Beispielbrowser.

Das Problem verstehen

Bildklassifizierung ist ein Problem des maschinellen Sehens. Bei der Bildklassifizierung wird ein Bild eingegeben, das dann in eine bestimmte Klasse eingeordnet wird. Bildklassifizierungsmodelle werden häufig mit Deep Learning und neuronalen Netzwerken trainiert. Weitere Informationen finden Sie unter Deep Learning im Vergleich zu maschinellem Lernen.

Die Bildklassifizierung kann zum Beispiel in diesen Szenarios hilfreich sein:

  • Gesichtserkennung
  • Emotionserkennung
  • Medizinische Diagnose
  • Orientierungspunkterkennung

In diesem Tutorial wird ein benutzerdefiniertes Bildklassifizierungsmodell trainiert, um eine automatisierte visuelle Überprüfung von Brückenbelägen durchzuführen, bei der durch Risse unterbrochene Strukturen identifiziert werden.

ML.NET-Bildklassifizierungs-API

ML.NET bietet verschiedene Methoden zum Durchführen einer Bildklassifizierung. In diesem Tutorial wird die Methode des Transferlernens unter Verwendung der Bildklassifizierungs-API angewendet. Die Bildklassifizierungs-API nutzt TensorFlow.NET, eine Low-Level-Bibliothek, die C#-Bindungen für die TensorFlow-C++-API bereitstellt.

Was ist Übertragungslernen?

Beim Transferlernen werden Erkenntnisse aus der Lösung eines Problems für ein anderes verwandtes Problem genutzt.

Das von Grund auf neue Trainieren eines Deep-Learning-Modells erfordert das Festlegen mehrerer Parameter, zahlreiche bezeichnete Trainingsdaten und eine große Menge an Computeressourcen (Hunderte von GPU-Stunden). Die Verwendung eines vorab trainierten Modells zusammen mit dem Transferlernen ermöglicht es Ihnen, den Trainingsprozess zu verkürzen.

Trainingsprozess

Die Bildklassifizierungs-API startet den Trainingsprozess, indem das vorab trainierte TensorFlow-Modell geladen wird. Der Trainingsprozess setzt sich aus zwei Schritten zusammen:

  1. Engpassphase
  2. Trainingsphase

Trainingsschritte

Engpassphase

Während der Engpassphase werden die Trainingsbilder geladen, wobei die Pixelwerte als Eingabe dienen, oder aber Features für die fixierten Ebenen des vorab trainierten Modells. Die fixierten Ebenen umfassen sämtliche Ebenen im neuronalen Netz bis hin zur vorletzte Ebene, die inoffiziell auch als Engpassebene bezeichnet wird. Diese Ebenen werden „fixiert“ genannt, da für diese kein Training stattfindet und Vorgänge lediglich weitergegeben werden. In diesen fixierten Ebenen werden die zugrunde liegenden Muster berechnet, anhand derer ein Modell zwischen den verschiedenen Klassen unterscheidet. Je mehr Ebenen es gibt, desto rechenintensiver ist dieser Schritt. Da es sich hierbei um eine einmalige Berechnung handelt, können die Ergebnisse zwischengespeichert und in späteren Durchläufen verwendet werden, wenn mit verschiedenen Parametern experimentiert wird.

Trainingsphase

Sobald die Ausgabewerte aus der Engpassphase berechnet sind, dienen sie als Eingabe für das nochmalige Training der letzten Ebene des Modells. Dieser Prozess ist iterativ und wird so oft ausgeführt, wie durch Modellparameter angegeben ist. Bei jeder Ausführung werden Verlust und Genauigkeit ausgewertet. Anschließend werden die entsprechenden Anpassungen zur Verbesserung des Modells vorgenommen, um so den Verlust zu minimieren und die Genauigkeit zu maximieren. Nach Abschluss des Trainings verfügen Sie über zwei Modellformate. Eines wird als .pb-Version des Modells und das andere als für ML.NET serialisierte .zip-Version des Modells bezeichnet. Für die Arbeit in von ML.NET unterstützten Umgebungen wird die .zip-Version des Modells empfohlen. In Umgebungen, in denen ML.NET nicht unterstützt wird, haben Sie jedoch die Möglichkeit, die .pb-Version zu verwenden.

Grundlegendes zum vorab trainierten Modell

Das in diesem Tutorial verwendete vorab trainierte Modell ist die 101-Ebenen-Variante des Modells „Residual Network (ResNet) v2“. Das Originalmodell ist darauf trainiert, Bilder in tausend Kategorien einzuteilen. Das Modell verwendet ein Bild der Größe 224 × 224 als Eingabe und gibt die Klassenwahrscheinlichkeiten für jede der Klassen aus, für die es trainiert ist. Ein Teil dieses Modells wird verwendet, um ein neues Modell mit benutzerdefinierten Bildern zu trainieren, damit dieses Vorhersagen für zwei Klassen treffen kann.

Erstellen einer Konsolenanwendung

Nachdem Sie nun grundlegende Kenntnisse über das Transferlernen und die Bildklassifizierungs-API haben, ist es an der Zeit, die Anwendung zu erstellen.

  1. Erstellen Sie eine C#-Konsolenanwendung namens „DeepLearning_ImageClassification_Binary“. Klicken Sie auf die Schaltfläche Weiter.

  2. Wählen Sie .NET 6 als zu verwendendes Framework aus. Klicken Sie auf die Schaltfläche Erstellen .

  3. Installieren Sie das NuGet-Paket Microsoft.ML:

    Hinweis

    In diesem Beispiel wird, sofern nicht anders angegeben, die neueste stabile Version der genannten NuGet-Pakete verwendet.

    1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen Sie NuGet-Pakete verwalten aus.
    2. Wählen Sie als Paketquelle „nuget.org“ aus.
    3. Wählen Sie die Registerkarte Durchsuchen aus.
    4. Aktivieren Sie das Kontrollkästchen Vorabversion einbeziehen.
    5. Suchen Sie nach Microsoft.ML.
    6. Wählen Sie die Schaltfläche Installieren aus.
    7. Wählen Sie die Schaltfläche OK im Dialogfeld Vorschau der Änderungen und dann die Schaltfläche Ich stimme zu im Dialogfeld Zustimmung zur Lizenz aus, wenn Sie den Lizenzbedingungen für die aufgelisteten Pakete zustimmen.
    8. Wiederholen Sie diese Schritte für die NuGet-Pakete Microsoft.ML.Vision, SciSharp.TensorFlow.Redist Version 2.3.1 und Microsoft.ML.ImageAnalytics.

Vorbereiten und Verstehen der Daten

Hinweis

Die Datasets für dieses Tutorial stammen von Marc Maguire, Sattar Dorafshan und Robert J. Thomas, „SDNET2018: A concrete crack image dataset for machine learning applications“ (2018). Durchsuchen Sie alle Datasets. Dokument 48. https://digitalcommons.usu.edu/all_datasets/48

SDNET2018 ist ein Bilddataset, das Anmerkungen für gerissene und nicht gerissene Betonstrukturen (Brückenbeläge, Mauern und Gehwege) enthält.

Beispiele für Brückenbeläge des SDNET2018-Datasets

Die Daten sind in drei Unterverzeichnissen organisiert:

  • D enthält Bilder von Brückenbelägen
  • P enthält Bilder von Gehwegen
  • W enthält Bilder von Mauern

Jedes dieser Unterverzeichnisse enthält zwei zusätzliche Unterverzeichnisse mit Präfixen:

  • C ist das Präfix für gerissene Oberflächen
  • U ist das Präfix für nicht gerissene Oberflächen

In diesem Tutorial werden ausschließlich Bilder von Brückenbelägen verwendet.

  1. Laden Sie das Dataset herunter, und entpacken Sie es.
  2. Erstellen Sie in Ihrem Projekt ein Verzeichnis mit dem Namen „assets“, um darin die Datasetdateien zu speichern.
  3. Kopieren Sie die Unterverzeichnisse CD und UD aus dem zuletzt entpackten Verzeichnis in das Verzeichnis assets.

Erstellen von Eingabe- und Ausgabeklassen

  1. Öffnen Sie die Datei Program.cs, und ersetzen Sie die vorhandenen using-Anweisungen am Anfang der Datei durch die folgenden Anweisungen:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.IO;
    using Microsoft.ML;
    using static Microsoft.ML.DataOperationsCatalog;
    using Microsoft.ML.Vision;
    
  2. Erstellen Sie in der Datei Program.cs unter der Program-Klasse eine Klasse mit dem Namen ImageData. Diese Klasse wird verwendet, um die ursprünglich geladenen Daten darzustellen.

    class ImageData
    {
        public string ImagePath { get; set; }
    
        public string Label { get; set; }
    }
    

    ImageData enthält die folgenden Eigenschaften:

    • ImagePath ist der vollqualifizierte Pfad, in dem das Bild gespeichert ist.
    • Label ist die Kategorie, zu der das Bild gehört. Dies ist der vorherzusagende Wert.
  3. Erstellen Sie Klassen für Ihre Eingabe- und Ausgabedaten.

    1. Definieren Sie unter der ImageData-Klasse das Schema Ihrer Eingabedaten in einer neuen Klasse namens ModelInput.

      class ModelInput
      {
          public byte[] Image { get; set; }
          
          public UInt32 LabelAsKey { get; set; }
      
          public string ImagePath { get; set; }
      
          public string Label { get; set; }
      }
      

      ModelInput enthält die folgenden Eigenschaften:

      • Image ist die byte[]-Darstellung des Bilds. Bei dem Modell wird erwartet, dass Bilddaten diesen Typ für das Training aufweisen.
      • LabelAsKey ist die numerische Darstellung von Label.
      • ImagePath ist der vollqualifizierte Pfad, in dem das Bild gespeichert ist.
      • Label ist die Kategorie, zu der das Bild gehört. Dies ist der vorherzusagende Wert.

      Nur Image und LabelAsKey werden verwendet, um das Modell zu trainieren und Vorhersagen zu treffen. Die Eigenschaften ImagePath und Label werden beibehalten, damit einfacher auf den Namen und die Kategorie der ursprünglichen Bilddatei zugegriffen werden kann.

    2. Anschließend definieren Sie unter der ModelInput-Klasse das Schema Ihrer Ausgabedaten in einer neuen Klasse namens ModelOutput.

      class ModelOutput
      {
          public string ImagePath { get; set; }
      
          public string Label { get; set; }
      
          public string PredictedLabel { get; set; }
      }
      

      ModelOutput enthält die folgenden Eigenschaften:

      • ImagePath ist der vollqualifizierte Pfad, in dem das Bild gespeichert ist.
      • Label ist die ursprüngliche Kategorie, zu der das Bild gehört. Dies ist der vorherzusagende Wert.
      • PredictedLabel ist der vom Modell vorhergesagte Wert.

      Ähnlich wie bei ModelInput ist nur PredictedLabel für Vorhersagen erforderlich, da dies die vom Modell getroffene Vorhersage enthält. Die Eigenschaften ImagePath und Label werden beibehalten, damit einfacher auf den Namen und die Kategorie der ursprünglichen Bilddatei zugegriffen werden kann.

Erstellen eines Arbeitsbereichsverzeichnisses

Wenn sich Trainings-und Validierungsdaten nicht häufig ändern, empfiehlt es sich, die berechneten Engpasswerte für weitere Ausführungen zwischenzuspeichern.

  1. Erstellen Sie in Ihrem Projekt ein neues Verzeichnis namens workspace, um die berechneten Engpasswerte und die .pb-Version des Modells zu speichern.

Definieren von Pfaden und Initialisieren von Variablen

  1. Definieren Sie unter den using-Anweisungen den Speicherort Ihrer Ressourcen, der berechneten Engpasswerte und der .pb-Version des Modells.

    var projectDirectory = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "../../../"));
    var workspaceRelativePath = Path.Combine(projectDirectory, "workspace");
    var assetsRelativePath = Path.Combine(projectDirectory, "assets");
    
  2. Initialisieren Sie die mlContext-Variable mit einer neuen Instanz von MLContext.

    MLContext mlContext = new MLContext();
    

    Die MLContext-Klasse ist der Startpunkt für alle ML.NET-Vorgänge. Durch das Initialisieren von MLContext wird eine neue ML.NET-Umgebung erstellt, die für mehrere Objekte des Modellerstellungsworkflows verwendet werden kann. Die Klasse ähnelt dem Konzept von DbContext in Entity Framework.

Laden der Daten

Erstellen einer Hilfsmethode zum Laden von Daten

Die Bilder werden in zwei Unterverzeichnissen gespeichert. Vor dem Laden der Daten müssen diese in eine Liste mit ImageData-Objekten formatiert werden. Erstellen Sie dazu die LoadImagesFromDirectory-Methode auf.

IEnumerable<ImageData> LoadImagesFromDirectory(string folder, bool useFolderNameAsLabel = true)
{

}
  1. Fügen Sie in LoadImagesFromDirectory den folgenden Code hinzu, um alle Dateipfade aus den Unterverzeichnissen abzurufen:

    var files = Directory.GetFiles(folder, "*",
        searchOption: SearchOption.AllDirectories);
    
  2. Durchlaufen Sie dann die einzelnen Dateien mithilfe einer foreach-Anweisung.

    foreach (var file in files)
    {
    
    }
    
  3. Überprüfen Sie, ob in der foreach-Anweisung die Dateierweiterungen unterstützt werden. Die Bildklassifizierungs-API unterstützt JPEG- und PNG-Formate.

    if ((Path.GetExtension(file) != ".jpg") && (Path.GetExtension(file) != ".png"))
        continue;
    
    
  4. Rufen Sie anschließend die Bezeichnung für die Datei ab. Wenn der useFolderNameAsLabel-Parameter auf true festgelegt ist, wird das übergeordnete Verzeichnis, in dem die Datei gespeichert wird, als Bezeichnung verwendet. Andernfalls wird erwartet, dass die Bezeichnung ein Präfix des Dateinamens oder der Dateiname selbst ist.

    var label = Path.GetFileName(file);
    
    if (useFolderNameAsLabel)
        label = Directory.GetParent(file).Name;
    else
    {
        for (int index = 0; index < label.Length; index++)
        {
            if (!char.IsLetter(label[index]))
            {
                label = label.Substring(0, index);
                break;
            }
        }
    }
    
  5. Abschließend erstellen Sie eine neue Instanz von ModelInput.

    yield return new ImageData()
    {
        ImagePath = file,
        Label = label
    };
    

Vorbereiten der Daten

  1. Rufen Sie die LoadImagesFromDirectory-Hilfsmethode auf, um die Liste der Bilder abzurufen, die nach der Initialisierung der mlContext-Variablen für das Training verwendet werden.

    IEnumerable<ImageData> images = LoadImagesFromDirectory(folder: assetsRelativePath, useFolderNameAsLabel: true);
    
  2. Laden Sie dann die Bilder mithilfe der LoadFromEnumerable-Methode in eine IDataView-Schnittstelle.

    IDataView imageData = mlContext.Data.LoadFromEnumerable(images);
    
  3. Die Daten werden in der Reihenfolge geladen, in der sie aus den Verzeichnissen gelesen wurden. Um die Daten auszugleichen, mischen Sie sie zufällig mithilfe der ShuffleRows-Methode.

    IDataView shuffledData = mlContext.Data.ShuffleRows(imageData);
    
  4. Bei Modellen für maschinelles Lernen wird eine Eingabe im numerischen Format erwartet. Daher muss vor dem Training eine Vorverarbeitung der Daten durchgeführt werden. Erstellen Sie eine EstimatorChain, die aus MapValueToKey und LoadRawImageBytes-Transformationen besteht. Die MapValueToKey-Transformation übernimmt den kategorischen Wert aus der Spalte Label, konvertiert diesen in einen numerischen KeyType-Wert und speichert ihn in einer neuen Spalte namens LabelAsKey. LoadImages greift auf Werte aus der Spalte ImagePath zusammen mit dem Parameter imageFolder zu, um Bilder für das Training zu laden.

    var preprocessingPipeline = mlContext.Transforms.Conversion.MapValueToKey(
            inputColumnName: "Label",
            outputColumnName: "LabelAsKey")
        .Append(mlContext.Transforms.LoadRawImageBytes(
            outputColumnName: "Image",
            imageFolder: assetsRelativePath,
            inputColumnName: "ImagePath"));
    
  5. Verwenden Sie die Fit-Methode, um die Daten auf die preprocessingPipelineEstimatorChain gefolgt von der Transform-Methode anzuwenden, wodurch eine IDataView zurückgegeben wird, die die vorverarbeiteten Daten enthält.

    IDataView preProcessedData = preprocessingPipeline
                        .Fit(shuffledData)
                        .Transform(shuffledData);
    
  6. Beim Trainieren eines Modells ist es wichtig, sowohl über ein Trainingsdataset als auch ein Validierungsdataset zu verfügen. Das Modell wird mit dem Trainingsset trainiert. Wie gut es Vorhersagen über unbekannte Daten erstellt, wird an der Leistung im Vergleich zum Validierungsset gemessen. Basierend auf den Ergebnissen dieser Leistung nimmt das Modell Anpassungen an dem Gelernten vor, um die Ergebnisse zu verbessern. Das Validierungsset kann entweder aus der Aufteilung des ursprünglichen Datasets oder aus einer anderen Quelle stammen, die bereits für diesen Zweck vorgesehen ist. In diesem Fall wird das vorverarbeitete Datenset in Trainings-, Validierungs- und Testsets unterteilt.

    TrainTestData trainSplit = mlContext.Data.TrainTestSplit(data: preProcessedData, testFraction: 0.3);
    TrainTestData validationTestSplit = mlContext.Data.TrainTestSplit(trainSplit.TestSet);
    

    Im obigen Codebeispiel werden zwei Aufteilungen vorgenommen. Zunächst werden die vorverarbeiteten Daten aufgeteilt, wobei 70% für das Training und die restlichen 30% für die Validierung verwendet werden. Anschließend werden die 30% des Validierungssets weiter in Validierungs- und Testsets unterteilt, wobei 90% für die Validierung und 10% für Tests verwendet werden.

    Ein gutes Beispiel, um den Sinn und Zweck dieser Datenaufteilungen zu verstehen, ist eine Prüfungsituation. Wenn Sie für eine Prüfung lernen, lesen Sie Ihre Notizen, Bücher oder andere Unterlagen, um die in der Prüfung enthaltenen Themen zu lernen und zu vertiefen. Dafür ist das Trainingsset da. Dann können Sie eine Probeklausur ablegen, um Ihren Wissensstand zu überprüfen. Hier bietet sich das Validierungsset an. Sie möchten vor der eigentlichen Prüfung feststellen, ob Sie die Inhalte richtig verstanden haben. Ausgehend von den Ergebnissen können Sie herausfinden, was Sie falsch gemacht bzw. nicht richtig verstanden haben, und so die Ergebnisse in den Lernprozess für die eigentliche Prüfung einbeziehen. Zum Schluss legen Sie die Prüfung ab. Dafür wird das Testset verwendet. Sie haben die Fragen in der Prüfung noch nie gesehen und nutzen zur Bearbeitung der vorliegenden Aufgabe nun das, was Sie sich durch den Lernprozess (Training) und die Überprüfung des Gelernten (Validierung) angeeignet haben.

  7. Ordnen Sie den Teilbereichen die jeweiligen Werte für die Trainings-, Validierungs- und Testdaten zu.

    IDataView trainSet = trainSplit.TrainSet;
    IDataView validationSet = validationTestSplit.TrainSet;
    IDataView testSet = validationTestSplit.TestSet;
    

Definieren der Trainingspipeline

Das Modelltraining umfasst mehrere Schritte. Zunächst wird die Bildklassifizierungs-API verwendet, um das Modell zu trainieren. Anschließend werden die verschlüsselten Bezeichnungen in der Spalte PredictedLabel mithilfe der MapKeyToValue-Transformation wieder in ihren ursprünglichen kategorischen Wert konvertiert.

  1. Erstellen Sie eine neue Variable, um einen Satz erforderlicher und optionaler Parameter für ein ImageClassificationTrainer-Element zu speichern.

    var classifierOptions = new ImageClassificationTrainer.Options()
    {
        FeatureColumnName = "Image",
        LabelColumnName = "LabelAsKey",
        ValidationSet = validationSet,
        Arch = ImageClassificationTrainer.Architecture.ResnetV2101,
        MetricsCallback = (metrics) => Console.WriteLine(metrics),
        TestOnTrainSet = false,
        ReuseTrainSetBottleneckCachedValues = true,
        ReuseValidationSetBottleneckCachedValues = true
    };
    

    Ein ImageClassificationTrainer-Element nimmt mehrere optionale Parameter an:

    • FeatureColumnName ist die Spalte, die als Eingabe für das Modell verwendet wird.
    • LabelColumnName ist die Spalte für den vorherzusagenden Wert.
    • ValidationSet ist die IDataView-Schnittstelle, die die Validierungsdaten enthält.
    • Arch definiert, welche der vorab trainierten Modellarchitekturen verwendet werden soll. In diesem Tutorial wird die 101-Ebenen-Variante des Modells „ResNetv2“ verwendet.
    • MetricsCallback verknüpft eine Funktion, um den Fortschritt während des Trainings zu verfolgen.
    • TestOnTrainSet weist das Modell an, die Leistung anhand des Trainingssets zu messen, wenn kein Validierungsset vorhanden ist.
    • ReuseTrainSetBottleneckCachedValues informiert das Modell, ob die zwischengespeicherten Werte aus der Engpassphase in nachfolgenden Durchläufen verwendet werden sollen. Die Engpassphase ist eine einmalige Pass-Through-Berechnung, die bei der ersten Durchführung sehr rechenintensiv ist. Wenn sich die Trainingsdaten nicht ändern, und Sie mit einer anderen Anzahl von Epochen oder anderen Batchgrößen experimentieren möchten, können Sie mit den zwischengespeicherten Werten den Zeitaufwand für das Training eines Modells erheblich verringern.
    • ReuseValidationSetBottleneckCachedValues ist vergleichbar mit ReuseTrainSetBottleneckCachedValues, allerdings handelt es sich in diesem Fall um das Validierungsdataset.
    • WorkspacePath definiert das Verzeichnis, in dem die berechneten Engpasswerte und die .pb-Version des Modells gespeichert werden sollen.
  2. Definieren Sie die EstimatorChain-Trainingspipeline, die aus mapLabelEstimator und ImageClassificationTrainer besteht.

    var trainingPipeline = mlContext.MulticlassClassification.Trainers.ImageClassification(classifierOptions)
        .Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel"));
    
  3. Verwenden Sie die Methode Fit, um Ihr Modell zu trainieren.

    ITransformer trainedModel = trainingPipeline.Fit(trainSet);
    

Verwenden des Modells

Nachdem Sie Ihr Modell trainiert haben, ist es an der Zeit, es zur Klassifizierung von Bildern zu verwenden.

Erstellen Sie eine neue Hilfsmethode namens OutputPrediction, um Vorhersageinformationen in der Konsole anzuzeigen.

private static void OutputPrediction(ModelOutput prediction)
{
    string imageName = Path.GetFileName(prediction.ImagePath);
    Console.WriteLine($"Image: {imageName} | Actual Value: {prediction.Label} | Predicted Value: {prediction.PredictedLabel}");
}

Klassifizieren eines einzelnen Bilds

  1. Erstellen Sie eine neue Methode namens ClassifySingleImage, um eine Einzelbildvorhersage zu erstellen und auszugeben.

    void ClassifySingleImage(MLContext mlContext, IDataView data, ITransformer trainedModel)
    {
    
    }
    
  2. Erstellen Sie eine PredictionEngine-Klasse innerhalb der ClassifySingleImage-Methode. Die PredictionEngine-Klasse ist eine praktische API, mit der Sie eine Vorhersage für eine einzelne Dateninstanz übergeben und dann ausführen können.

    PredictionEngine<ModelInput, ModelOutput> predictionEngine = mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(trainedModel);
    
  3. Um auf eine einzelne ModelInput-Instanz zuzugreifen, konvertieren Sie die dataIDataView in eine IEnumerable mit der CreateEnumerable-Methode und erhalten Sie dann das erste Ergebnis.

    ModelInput image = mlContext.Data.CreateEnumerable<ModelInput>(data,reuseRowObject:true).First();
    
  4. Verwenden Sie die Predict-Methode, um das Bild zu klassifizieren.

    ModelOutput prediction = predictionEngine.Predict(image);
    
  5. Geben Sie die Vorhersage mit der OutputPrediction-Methode in der Konsole aus.

    Console.WriteLine("Classifying single image");
    OutputPrediction(prediction);
    
  6. Rufen Sie ClassifySingleImage unter dem Aufruf der Fit-Methode mithilfe des Testsets der Bilder auf.

    ClassifySingleImage(mlContext, testSet, trainedModel);
    

Klassifizieren mehrerer Bilder

  1. Fügen Sie eine neue Methode namens ClassifyImages unter der ClassifySingleImage-Methode hinzu, um mehrere Bildvorhersagen zu erstellen und auszugeben.

    void ClassifyImages(MLContext mlContext, IDataView data, ITransformer trainedModel)
    {
    
    }
    
  2. Erstellen Sie mithilfe der Transform-Methode eine IDataView-Schnittstelle, die die Vorhersagen enthält. Fügen Sie der ClassifyImages-Methode den folgenden Code hinzu.

    IDataView predictionData = trainedModel.Transform(data);
    
  3. Zur Iteration über die Vorhersagen konvertieren Sie die predictionDataIDataView in eine IEnumerable mithilfe der CreateEnumerable-Methode und erhalten Sie dann die ersten zehn Ergebnisse.

    IEnumerable<ModelOutput> predictions = mlContext.Data.CreateEnumerable<ModelOutput>(predictionData, reuseRowObject: true).Take(10);
    
  4. Iterieren Sie die ursprünglichen und vorhergesagten Bezeichnungen für die Vorhersagen, und geben Sie sie aus.

    Console.WriteLine("Classifying multiple images");
    foreach (var prediction in predictions)
    {
        OutputPrediction(prediction);
    }
    
  5. Rufen Sie schließlich ClassifyImages unter der ClassifySingleImage()-Methode mithilfe des Testsets der Bilder auf.

    ClassifyImages(mlContext, testSet, trainedModel);
    

Ausführen der Anwendung

Führen Sie die Konsolenanwendung aus. Die Ausgabe sollte in etwa wie folgt aussehen. Möglicherweise werden Warnungen oder Verarbeitungsnachrichten angezeigt. Diese wurden jedoch aus Gründen der Übersichtlichkeit aus den folgenden Ergebnissen entfernt. Aus Gründen der Kürze wurde die Ausgabe komprimiert.

Engpassphase

Für den Bildnamen wird kein Wert ausgegeben, da die Bilder als byte[] geladen werden, sodass kein Bildname angezeigt werden kann.

Phase: Bottleneck Computation, Dataset used:      Train, Image Index: 279
Phase: Bottleneck Computation, Dataset used:      Train, Image Index: 280
Phase: Bottleneck Computation, Dataset used: Validation, Image Index:   1
Phase: Bottleneck Computation, Dataset used: Validation, Image Index:   2

Trainingsphase

Phase: Training, Dataset used: Validation, Batch Processed Count:   6, Epoch:  21, Accuracy:  0.6797619
Phase: Training, Dataset used: Validation, Batch Processed Count:   6, Epoch:  22, Accuracy:  0.7642857
Phase: Training, Dataset used: Validation, Batch Processed Count:   6, Epoch:  23, Accuracy:  0.7916667

Klassifizieren der Ausgabe von Bildern

Classifying single image
Image: 7001-220.jpg | Actual Value: UD | Predicted Value: UD

Classifying multiple images
Image: 7001-220.jpg | Actual Value: UD | Predicted Value: UD
Image: 7001-163.jpg | Actual Value: UD | Predicted Value: UD
Image: 7001-210.jpg | Actual Value: UD | Predicted Value: UD

Bei der Überprüfung des Bilds 7001-220.jpg können Sie feststellen, dass tatsächlich kein Riss zu sehen ist.

Für die Vorhersage verwendetes SDNET2018-Datasetbild

Herzlichen Glückwunsch! Sie haben ein Deep-Learning-Modell zur Klassifizierung von Bildern erstellt.

Verbessern des Modells

Wenn Sie mit den Ergebnissen des Modells nicht zufrieden sind, können Sie versuchen, seine Leistung zu verbessern, indem Sie einige der folgenden Ansätze ausprobieren:

  • Mehr Daten: Je mehr Beispiele vorhanden sind, von denen ein Modell lernt, desto besser ist dessen Leistung. Laden Sie das vollständige SDNET2018-Dataset herunter, und verwenden Sie es für das Training.
  • Erweitern der Daten: Eine gängige Technik, um eine größere Datenvielfalt zu erreichen, ist die Erweiterung der Daten durch Aufnahme eines Bilds und Anwendung verschiedener Transformationen (Drehen, Spiegeln, Verschieben, Zuschneiden). Auf diese Weise erhalten Sie verschiedene Beispiele, von denen das Modell lernen kann.
  • Längere Trainingsdauer: Umso länger die Trainingsdauer, desto genauer werden die Ergebnisse des Modells sein. Durch die Erhöhung der Anzahl von Epochen kann sich die Leistung des Modell erheblich verbessern.
  • Experimentieren mit Hyperparametern: Zusätzlich zu den in diesem Tutorial verwendeten Parametern können weitere Parameter angepasst werden, um die Leistung zu steigern. Die Änderung des Lerntempos, das den Umfang der Aktualisierungen am Modell nach jeder Epoche bestimmt, kann zu einer höheren Leistung führen.
  • Verwenden einer anderen Modellarchitektur: Abhängig von der Beschaffenheit Ihrer Daten kann sich das Modell, das am besten deren Merkmale erlernen kann, unterscheiden. Wenn Sie mit der Leistung Ihres Modells unzufrieden sind, sollten Sie versuchen, die Architektur zu ändern.

Nächste Schritte

In diesem Tutorial haben Sie erfahren, wie Sie ein benutzerdefiniertes Deep-Learning-Modell mithilfe von Transferlernen, einem vorab trainierten TensorFlow-Modell und der ML.NET-Bildklassifizierungs-API erstellen, um Bilder von Betonoberflächen als gerissen oder nicht gerissen zu klassifizieren.

Fahren Sie mit dem nächsten Tutorial fort, um mehr zu erfahren.