Zelfstudie: Een ML.NET classificatiemodel trainen om afbeeldingen te categoriseren

Leer hoe u een classificatiemodel traint om afbeeldingen te categoriseren met behulp van een vooraf getraind TensorFlow-model voor afbeeldingsverwerking.

Het TensorFlow-model is getraind om afbeeldingen in duizend categorieën te classificeren. Omdat het TensorFlow-model weet hoe patronen in afbeeldingen moeten worden herkend, kan het ML.NET model een deel ervan in de pijplijn gebruiken om onbewerkte afbeeldingen te converteren naar functies of invoer om een classificatiemodel te trainen.

In deze zelfstudie leert u het volgende:

  • Inzicht in het probleem
  • Het vooraf getrainde TensorFlow-model opnemen in de ML.NET-pijplijn
  • Het ML.NET-model trainen en evalueren
  • Een testafbeelding classificeren

U vindt de broncode voor deze zelfstudie in de opslagplaats dotnet/samples . Standaard is de .NET-projectconfiguratie voor deze zelfstudie gericht op .NET core 2.2.

Vereisten

De juiste machine learning-taak selecteren

Deep learning

Deep Learning is een subset van Machine Learning, die een revolutie teweegbrengen op gebieden als computer vision en spraakherkenning.

Deep Learning-modellen worden getraind met behulp van grote sets gelabelde gegevens en neurale netwerken die meerdere leerlagen bevatten. Deep learning:

  • Presteert beter op sommige taken, zoals Computer Vision.
  • Vereist enorme hoeveelheden trainingsgegevens.

Afbeeldingsclassificatie is een specifieke classificatietaak waarmee we afbeeldingen automatisch kunnen classificeren in categorieën zoals:

  • Een menselijk gezicht in een afbeelding detecteren of niet.
  • Katten versus honden detecteren.

Of, zoals in de volgende afbeeldingen, om te bepalen of een afbeelding een voedsel, speelgoed of apparaat is:

pizza afbeeldingteddybeer afbeeldingbroodrooster afbeelding

Notitie

De voorgaande afbeeldingen zijn eigendom van Wikimedia Commons en worden als volgt toegeschreven:

Als u een volledig nieuw afbeeldingsclassificatiemodel wilt trainen, moet u miljoenen parameters, een groot aantal gelabelde trainingsgegevens en een enorme hoeveelheid rekenresources (honderden GPU-uren) instellen. Hoewel het niet zo effectief is als het trainen van een aangepast model, kunt u met een vooraf getraind model dit proces versnellen door te werken met duizenden installatiekopieën versus miljoenen gelabelde afbeeldingen en vrij snel een aangepast model te bouwen (binnen een uur op een computer zonder GPU). In deze zelfstudie wordt het proces nog verder omlaag geschaald met behulp van slechts een dozijn trainingsafbeeldingen.

De Inception model is getraind om afbeeldingen in duizend categorieën te classificeren, maar voor deze zelfstudie moet u afbeeldingen classificeren in een kleinere categorieset en alleen die categorieën. U kunt de Inception modelmogelijkheid gebruiken om afbeeldingen te herkennen en te classificeren in de nieuwe beperkte categorieën van uw aangepaste afbeeldingsclassificatie.

  • Voedsel
  • Toy
  • Apparaat

In deze zelfstudie wordt gebruikgemaakt van het Deep Learning-model tensorFlow , een populair model voor afbeeldingsherkenning dat is getraind op de ImageNet gegevensset. Het TensorFlow-model classificeert volledige afbeeldingen in duizend klassen, zoals 'Umbrella', 'Jersey' en 'Vaatwasser'.

Omdat de Inception model al vooraf is getraind op duizenden verschillende afbeeldingen, bevat het intern de installatiekopieën die nodig zijn voor afbeeldingsidentificatie. We kunnen gebruikmaken van deze interne installatiekopieën in het model om een nieuw model met veel minder klassen te trainen.

Zoals in het volgende diagram wordt weergegeven, voegt u een verwijzing toe naar de ML.NET NuGet-pakketten in uw .NET Core- of .NET Framework-toepassingen. ML.NET bevat en verwijst naar de systeemeigen TensorFlow bibliotheek waarmee u code kunt schrijven waarmee een bestaand getraind TensorFlow modelbestand wordt geladen.

Diagram van TensorFlow-transformatie ML.NET arch

Classificatie met meerdere klassen

Nadat we het beginmodel van TensorFlow hebben gebruikt om functies te extraheren die geschikt zijn als invoer voor een klassiek machine learning-algoritme, voegen we een ML.NET classificatie met meerdere klassen toe.

De specifieke trainer die in dit geval wordt gebruikt, is het multinomiale logistieke regressie-algoritme.

Het algoritme dat door deze trainer is geïmplementeerd, presteert goed bij problemen met een groot aantal functies, wat het geval is voor een deep learning-model dat werkt op afbeeldingsgegevens.

Zie Deep learning versus machine learning voor meer informatie.

Gegevens

Er zijn twee gegevensbronnen: het .tsv bestand en de afbeeldingsbestanden. Het tags.tsv bestand bevat twee kolommen: de eerste is gedefinieerd als ImagePath en de tweede de Label kolom die overeenkomt met de afbeelding. Het volgende voorbeeldbestand heeft geen veldnamenrij en ziet er als volgt uit:

broccoli.jpg	food
pizza.jpg	food
pizza2.jpg	food
teddy2.jpg	toy
teddy3.jpg	toy
teddy4.jpg	toy
toaster.jpg	appliance
toaster2.png	appliance

De trainings- en testafbeeldingen bevinden zich in de assets-mappen die u in een ZIP-bestand downloadt. Deze beelden zijn van Wikimedia Commons.

Wikimedia Commons, de gratis mediaopslagplaats. Opgehaald op 10:48, 17 oktober 2018 van: https://commons.wikimedia.org/wiki/Pizzahttps://commons.wikimedia.org/wiki/Toasterhttps://commons.wikimedia.org/wiki/Teddy_bear

Instellen

Een project maken

  1. Maak een C# -consoletoepassing met de naam TransferLearningTF. Klik op de knop Next

  2. Kies .NET 6 als het framework dat u wilt gebruiken. Klik op de knop Maken.

  3. Installeer het Microsoft.ML NuGet-pakket:

    Notitie

    In dit voorbeeld wordt de meest recente stabiele versie van de vermelde NuGet-pakketten gebruikt, tenzij anders vermeld.

    • Klik in Solution Explorer met de rechtermuisknop op uw project en selecteer NuGet-pakketten beheren.
    • Kies 'nuget.org' als pakketbron, selecteer het tabblad Bladeren en zoek naar Microsoft.ML.
    • Selecteer de knop Installeren .
    • Selecteer de knop OK in het dialoogvenster Voorbeeld van wijzigingen .
    • Selecteer de knop Ik ga akkoord in het dialoogvenster Licentie-acceptatie als u akkoord gaat met de licentievoorwaarden voor de vermelde pakketten.
    • Herhaal deze stappen voor Microsoft.ML.ImageAnalytics, SciSharp.TensorFlow.Redist en Microsoft.ML.TensorFlow.

Assets downloaden

  1. Download het zip-bestand van de map met projectactiva en pak het bestand uit.

  2. Kopieer de map naar de assets projectmap TransferLearningTF . Deze map en de bijbehorende submappen bevatten de gegevens en ondersteuningsbestanden (met uitzondering van het Inception-model, dat u in de volgende stap gaat downloaden en toevoegen) die nodig zijn voor deze zelfstudie.

  3. Download het Inception-model en pak het uit.

  4. Kopieer de inhoud van de inception5h map die zojuist is uitgepakt naar de projectmap assets/inceptionTransferLearningTF. Deze map bevat het model en de aanvullende ondersteuningsbestanden die nodig zijn voor deze zelfstudie, zoals wordt weergegeven in de volgende afbeelding:

    Inhoud van de beginmap

  5. Klik in Solution Explorer met de rechtermuisknop op elk van de bestanden in de assetmap en submappen en selecteer Eigenschappen. Wijzig onder Geavanceerd de waarde van Kopiëren naar uitvoermap in Kopiëren indien nieuwer.

Klassen maken en paden definiëren

  1. Voeg de volgende aanvullende using instructies toe aan het begin van het bestand Program.cs :

    using Microsoft.ML;
    using Microsoft.ML.Data;
    
  2. Voeg de volgende code toe aan de regel direct onder de using-instructies om de assetpaden op te geven:

    string _assetsPath = Path.Combine(Environment.CurrentDirectory, "assets");
    string _imagesFolder = Path.Combine(_assetsPath, "images");
    string _trainTagsTsv = Path.Combine(_imagesFolder, "tags.tsv");
    string _testTagsTsv = Path.Combine(_imagesFolder, "test-tags.tsv");
    string _predictSingleImage = Path.Combine(_imagesFolder, "toaster3.jpg");
    string _inceptionTensorFlowModel = Path.Combine(_assetsPath, "inception", "tensorflow_inception_graph.pb");
    
  3. Maak klassen voor uw invoergegevens en voorspellingen.

    public class ImageData
    {
        [LoadColumn(0)]
        public string? ImagePath;
    
        [LoadColumn(1)]
        public string? Label;
    }
    

    ImageData is de gegevensklasse van de invoerafbeelding en heeft de volgende String velden:

    • ImagePath bevat de naam van het installatiekopieënbestand.
    • Label bevat een waarde voor het afbeeldingslabel.
  4. Voeg een nieuwe klasse toe aan uw project voor ImagePrediction:

    public class ImagePrediction : ImageData
    {
        public float[]? Score;
    
        public string? PredictedLabelValue;
    }
    

    ImagePrediction is de voorspellingsklasse van de afbeelding en heeft de volgende velden:

    • Score bevat het betrouwbaarheidspercentage voor een bepaalde afbeeldingsclassificatie.
    • PredictedLabelValue bevat een waarde voor het label voor de voorspelde afbeeldingsclassificatie.

    ImagePrediction is de klasse die wordt gebruikt voor voorspelling nadat het model is getraind. Het heeft een string (ImagePath) voor het pad naar de installatiekopieën. De Label wordt gebruikt om het model opnieuw te gebruiken en te trainen. De PredictedLabelValue wordt gebruikt tijdens voorspelling en evaluatie. Voor de evaluatie wordt een invoer met trainingsgegevens, de voorspelde waarden en het model gebruikt.

Variabelen initialiseren

  1. Initialiseer de mlContext variabele met een nieuw exemplaar van MLContext. Vervang de Console.WriteLine("Hello World!") regel door de volgende code:

    MLContext mlContext = new MLContext();
    

    De MLContext klasse is een startpunt voor alle ML.NET bewerkingen en als u initialiseert mlContext , wordt er een nieuwe ML.NET omgeving gemaakt die kan worden gedeeld met de werkstroomobjecten voor het maken van modellen. Het is conceptueel DBContext vergelijkbaar met in Entity Framework.

Een struct maken voor parameters van het Beginmodel

  1. Het Inception-model heeft verschillende parameters die u moet doorgeven. Maak een struct om de parameterwaarden toe te wijzen aan beschrijvende namen met de volgende code, net na het initialiseren van de mlContext variabele:

    struct InceptionSettings
    {
        public const int ImageHeight = 224;
        public const int ImageWidth = 224;
        public const float Mean = 117;
        public const float Scale = 1;
        public const bool ChannelsLast = true;
    }
    

Een weergavehulpprogrammamethode maken

Omdat u de afbeeldingsgegevens en de bijbehorende voorspellingen meer dan één keer weergeeft, maakt u een weergavehulpprogrammamethode om de weergave van de afbeelding en voorspellingsresultaten te verwerken.

  1. Maak de DisplayResults() methode, net na de InceptionSettings struct, met behulp van de volgende code:

    void DisplayResults(IEnumerable<ImagePrediction> imagePredictionData)
    {
    
    }
    
  2. Vul de hoofdtekst van de DisplayResults methode in:

    foreach (ImagePrediction prediction in imagePredictionData)
    {
        Console.WriteLine($"Image: {Path.GetFileName(prediction.ImagePath)} predicted as: {prediction.PredictedLabelValue} with score: {prediction.Score?.Max()} ");
    }
    

Een methode maken om een voorspelling te doen

  1. Maak de ClassifySingleImage() methode, net vóór de DisplayResults() methode, met behulp van de volgende code:

    void ClassifySingleImage(MLContext mlContext, ITransformer model)
    {
    
    }
    
  2. Maak een ImageData -object dat het volledig gekwalificeerde pad en de naam van het afbeeldingsbestand voor de ene ImagePathbevat. Voeg de volgende code toe als de volgende regels in de ClassifySingleImage() methode:

    var imageData = new ImageData()
    {
        ImagePath = _predictSingleImage
    };
    
  3. Maak één voorspelling door de volgende code toe te voegen als de volgende regel in de ClassifySingleImage methode:

    // Make prediction function (input = ImageData, output = ImagePrediction)
    var predictor = mlContext.Model.CreatePredictionEngine<ImageData, ImagePrediction>(model);
    var prediction = predictor.Predict(imageData);
    

    Gebruik de predict()- methode om de voorspelling op te halen. De PredictionEngine is een handige API waarmee u een voorspelling kunt uitvoeren op één exemplaar van gegevens. PredictionEngine is niet thread-safe. Het is acceptabel om te gebruiken in omgevingen met één thread of prototype. Voor verbeterde prestaties en threadveiligheid in productieomgevingen gebruikt u de PredictionEnginePool service, waarmee een ObjectPool van PredictionEngine -objecten wordt gemaakt voor gebruik in uw toepassing. Raadpleeg deze handleiding over het gebruik PredictionEnginePool in een ASP.NET Core web-API.

    Notitie

    PredictionEnginePool de service-extensie is momenteel in preview.

  4. Het voorspellingsresultaat weergeven als de volgende regel code in de ClassifySingleImage() methode:

    Console.WriteLine($"Image: {Path.GetFileName(imageData.ImagePath)} predicted as: {prediction.PredictedLabelValue} with score: {prediction.Score?.Max()} ");
    

De pijplijn voor het ML.NET-model maken

Een ML.NET modelpijplijn is een keten van schattingen. Er vindt geen uitvoering plaats tijdens het bouwen van de pijplijn. De estimator-objecten worden gemaakt, maar niet uitgevoerd.

  1. Een methode toevoegen om het model te genereren

    Deze methode vormt de kern van de zelfstudie. Er wordt een pijplijn voor het model gemaakt en de pijplijn wordt getraind om het ML.NET model te produceren. Het model wordt ook geëvalueerd op basis van enkele eerder ongeziene testgegevens.

    Maak de GenerateModel() methode, net na de InceptionSettings struct en net vóór de DisplayResults() methode, met behulp van de volgende code:

    ITransformer GenerateModel(MLContext mlContext)
    {
    
    }
    
  2. Voeg de schattingen toe om de pixels uit de afbeeldingsgegevens te laden, het formaat ervan te wijzigen en te extraheren:

    IEstimator<ITransformer> pipeline = mlContext.Transforms.LoadImages(outputColumnName: "input", imageFolder: _imagesFolder, inputColumnName: nameof(ImageData.ImagePath))
                    // The image transforms transform the images into the model's expected format.
                    .Append(mlContext.Transforms.ResizeImages(outputColumnName: "input", imageWidth: InceptionSettings.ImageWidth, imageHeight: InceptionSettings.ImageHeight, inputColumnName: "input"))
                    .Append(mlContext.Transforms.ExtractPixels(outputColumnName: "input", interleavePixelColors: InceptionSettings.ChannelsLast, offsetImage: InceptionSettings.Mean))
    

    De afbeeldingsgegevens moeten worden verwerkt in de indeling die het TensorFlow-model verwacht. In dit geval worden de afbeeldingen in het geheugen geladen, het formaat ervan gewijzigd in een consistente grootte en worden de pixels geëxtraheerd in een numerieke vector.

  3. Voeg de estimator toe om het TensorFlow-model te laden en maak een score:

    .Append(mlContext.Model.LoadTensorFlowModel(_inceptionTensorFlowModel).
        ScoreTensorFlowModel(outputColumnNames: new[] { "softmax2_pre_activation" }, inputColumnNames: new[] { "input" }, addBatchDimensionInput: true))
    

    Deze fase in de pijplijn laadt het TensorFlow-model in het geheugen en verwerkt vervolgens de vector van pixelwaarden via het TensorFlow-modelnetwerk. Het toepassen van invoer op een deep learning-model en het genereren van een uitvoer met behulp van het model, wordt scoren genoemd. Wanneer u het model in zijn geheel gebruikt, maakt scoren een deductie of voorspelling.

    In dit geval gebruikt u het hele TensorFlow-model, met uitzondering van de laatste laag, de laag die de deductie maakt. De uitvoer van de voorlaatste laag heeft het softmax_2_preactivationlabel . De uitvoer van deze laag is in feite een vector van functies die de oorspronkelijke invoerafbeeldingen karakteriseren.

    Deze functievector die door het TensorFlow-model wordt gegenereerd, wordt gebruikt als invoer voor een ML.NET trainingsalgoritmen.

  4. Voeg de estimator toe om de tekenreekslabels in de trainingsgegevens toe te wijzen aan sleutelwaarden voor gehele getallen:

    .Append(mlContext.Transforms.Conversion.MapValueToKey(outputColumnName: "LabelKey", inputColumnName: "Label"))
    

    Voor de ML.NET trainer die vervolgens wordt toegevoegd, moeten de labels een indeling hebben in key plaats van willekeurige tekenreeksen. Een sleutel is een getal met een een-op-een-toewijzing aan een tekenreekswaarde.

  5. Voeg het ML.NET trainingsalgoritmen toe:

    .Append(mlContext.MulticlassClassification.Trainers.LbfgsMaximumEntropy(labelColumnName: "LabelKey", featureColumnName: "softmax2_pre_activation"))
    
  6. Voeg de estimator toe om de voorspelde sleutelwaarde weer toe te wijzen aan een tekenreeks:

    .Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabelValue", "PredictedLabel"))
    .AppendCacheCheckpoint(mlContext);
    

Het model trainen

  1. Laad de trainingsgegevens met behulp van de wrapper LoadFromTextFile . Voeg de volgende code toe als de volgende regel in de GenerateModel() methode:

    IDataView trainingData = mlContext.Data.LoadFromTextFile<ImageData>(path:  _trainTagsTsv, hasHeader: false);
    

    Gegevens in ML.NET worden weergegeven als een IDataView-interface. IDataView is een flexibele, efficiënte manier om gegevens in tabelvorm (numeriek en tekst) te beschrijven. Gegevens kunnen vanuit een tekstbestand of in realtime (bijvoorbeeld SQL-database of logboekbestanden) naar een IDataView object worden geladen.

  2. Train het model met de gegevens die hierboven zijn geladen:

    ITransformer model = pipeline.Fit(trainingData);
    

    Met de Fit() methode wordt uw model getraind door de trainingsgegevensset toe te passen op de pijplijn.

De nauwkeurigheid van het model evalueren

  1. Laad en transformeer de testgegevens door de volgende code toe te voegen aan de volgende regel van de GenerateModel methode:

    IDataView testData = mlContext.Data.LoadFromTextFile<ImageData>(path: _testTagsTsv, hasHeader: false);
    IDataView predictions = model.Transform(testData);
    
    // Create an IEnumerable for the predictions for displaying results
    IEnumerable<ImagePrediction> imagePredictionData = mlContext.Data.CreateEnumerable<ImagePrediction>(predictions, true);
    DisplayResults(imagePredictionData);
    

    Er zijn enkele voorbeeldafbeeldingen die u kunt gebruiken om het model te evalueren. Net als de trainingsgegevens moeten deze worden geladen in een IDataView, zodat ze door het model kunnen worden getransformeerd.

  2. Voeg de volgende code toe aan de GenerateModel() methode om het model te evalueren:

    MulticlassClassificationMetrics metrics =
        mlContext.MulticlassClassification.Evaluate(predictions,
            labelColumnName: "LabelKey",
            predictedLabelColumnName: "PredictedLabel");
    

    Zodra u de voorspellingsset hebt, gebruikt u de methode Evaluate():

    • Evalueert het model (vergelijkt de voorspelde waarden met de testgegevensset labels).
    • Retourneert de metrische gegevens van de modelprestaties.
  3. De metrische gegevens van de nauwkeurigheid van het model weergeven

    Gebruik de volgende code om de metrische gegevens weer te geven, de resultaten te delen en er vervolgens actie op te ondernemen:

    Console.WriteLine($"LogLoss is: {metrics.LogLoss}");
    Console.WriteLine($"PerClassLogLoss is: {String.Join(" , ", metrics.PerClassLogLoss.Select(c => c.ToString()))}");
    

    De volgende metrische gegevens worden geëvalueerd voor afbeeldingsclassificatie:

    • Log-loss - zie Logboekverlies. U wilt dat logboekverlies zo dicht mogelijk bij nul is.
    • Per class Log-loss. U wilt dat logboekverlies per klasse zo dicht mogelijk bij nul ligt.
  4. Voeg de volgende code toe om het getrainde model als volgende regel te retourneren:

    return model;
    

Nu kunt u de toepassing uitvoeren.

  1. Voeg de aanroep toe aan GenerateModel na het maken van de MLContext klasse:

    ITransformer model = GenerateModel(mlContext);
    
  2. Voeg de aanroep toe aan de ClassifySingleImage() methode na de aanroep van de GenerateModel() methode:

    ClassifySingleImage(mlContext, model);
    
  3. Voer uw console-app uit (Ctrl + F5). De resultaten moeten vergelijkbaar zijn met de volgende uitvoer. (Mogelijk ziet u waarschuwingen of verwerkingsberichten, maar deze berichten zijn voor de duidelijkheid verwijderd uit de volgende resultaten.)

    =============== Training classification model ===============
    Image: broccoli2.jpg predicted as: food with score: 0.8955513
    Image: pizza3.jpg predicted as: food with score: 0.9667718
    Image: teddy6.jpg predicted as: toy with score: 0.9797683
    =============== Classification metrics ===============
    LogLoss is: 0.0653774699265059
    PerClassLogLoss is: 0.110315812569315 , 0.0204391272836966 , 0
    =============== Making single image classification ===============
    Image: toaster3.jpg predicted as: appliance with score: 0.9646884
    

Gefeliciteerd U hebt nu een classificatiemodel gemaakt in ML.NET om afbeeldingen te categoriseren met behulp van een vooraf getrainde TensorFlow voor afbeeldingsverwerking.

U vindt de broncode voor deze zelfstudie in de opslagplaats dotnet/samples .

In deze zelfstudie heeft u het volgende geleerd:

  • Inzicht in het probleem
  • Het vooraf getrainde TensorFlow-model opnemen in de ML.NET-pijplijn
  • Het ML.NET-model trainen en evalueren
  • Een testafbeelding classificeren

Bekijk de GitHub-opslagplaats met Machine Learning-voorbeelden om een uitgebreid voorbeeld van afbeeldingsclassificatie te bekijken.