Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Lär dig hur du tränar en anpassad djupinlärningsmodell med hjälp av överföringsinlärning, en förtränad TensorFlow-modell och API:et för ML.NET bildklassificering för att klassificera bilder av betongytor som spruckna eller obeackade.
I den här tutorialen lär du dig följande:
- Förstå problemet
- Läs mer om API:et för ML.NET bildklassificering
- Förstå den förtränade modellen
- Använda överföringsinlärning för att träna en anpassad TensorFlow-bildklassificeringsmodell
- Klassificera bilder med den anpassade modellen
Förutsättningar
Förstå problemet
Bildklassificering är ett problem inom datorseende. Bildklassificeringen tar en bild som indata och kategoriserar den i en föreskriven klass. Bildklassificeringsmodeller tränas ofta med djupinlärning och neurala nätverk. Mer information finns i Djupinlärning jämfört med maskininlärning.
Några scenarier där bildklassificering är användbar är:
- Ansiktsigenkänning
- Känsloavkänning
- Medicinsk diagnos
- Identifiering av landmärke
Den här handledningen tränar en anpassad bildklassificeringsmodell för att utföra automatiserad visuell inspektion av brodäck för att identifiera strukturer som har skadats av sprickor.
ML.NET API för bildklassificering
ML.NET tillhandahåller olika sätt att utföra bildklassificering. I den här handledningen tillämpas överföringsinlärning med API:et för bildklassificering. API:et för bildklassificering använder TensorFlow.NET, ett bibliotek på låg nivå som tillhandahåller C#-bindningar för TensorFlow C++-API:et.
Vad är överföringsinlärning?
Överföringsinlärning tillämpar kunskap som erhållits från att lösa ett problem på ett annat relaterat problem.
Träning av en djupinlärningsmodell från grunden kräver att du anger flera parametrar, en stor mängd märkta träningsdata och en stor mängd beräkningsresurser (hundratals GPU-timmar). Att använda en förtränad modell tillsammans med överföringsinlärning gör att du kan förkorta träningsprocessen.
Utbildningsprocess
API:et för bildklassificering startar träningsprocessen genom att läsa in en förtränad TensorFlow-modell. Träningsprocessen består av två steg:
- Flaskhalsfas.
- Träningsfas.
Flaskhalsfas
Under flaskhalsfasen läses uppsättningen träningsbilder in och pixelvärdena används som indata, eller funktioner, för de fasta lagren i den förtränade modellen. De frusna lagren innehåller alla lager i det neurala nätverket upp till det näst sista lagret, som informellt kallas flaskhalsskiktet. Dessa lager kallas frusna eftersom träning inte kommer att ske på dessa lager och operationerna passerar igenom. Det är i dessa frusna lager där mönster på lägre nivå som hjälper en modell att skilja mellan de olika klasserna beräknas. Ju större antalet lager, desto mer beräkningsintensivt är det här steget. Eftersom det här är en engångsberäkning kan resultatet cachelagras och användas i senare körningar när du experimenterar med olika parametrar.
Träningsfas
När utdatavärdena från flaskhalsfasen har beräknats används de som indata för att träna om modellens sista lager. Den här processen är iterativ och körs för det antal gånger som anges av modellparametrar. Under varje körning utvärderas förlust och noggrannhet. Sedan görs lämpliga justeringar för att förbättra modellen med målet att minimera förlusten och maximera noggrannheten. När träningen är klar genereras två modellformat. En av dem är .pb modellens version och den andra är den .zip ML.NET serialiserade versionen av modellen. När du arbetar i miljöer som stöds av ML.NET rekommenderar vi att du använder .zip modellens version. I miljöer där ML.NET inte stöds har du dock möjlighet att använda .pb versionen.
Förstå den förutbildade modellen
Den förtränade modellen som används i den här handledningen är 101-lagersvarianten av modellen Residual Network (ResNet) v2. Den ursprungliga modellen tränas att klassificera bilder i tusen kategorier. Modellen tar som indata en bild av storlek 224 x 224 och matar ut klassannolikheterna för var och en av de klasser som den tränas på. En del av den här modellen används för att träna en ny modell med hjälp av anpassade avbildningar för att göra förutsägelser mellan två klasser.
Skapa konsolprogram
Nu när du har en allmän förståelse för överföringsinlärning och API:et för bildklassificering är det dags att skapa programmet.
Skapa ett C# -konsolprogram med namnet "DeepLearning_ImageClassification_Binary". Klicka på knappen Nästa.
Välj .NET 8 som det ramverk som ska användas och välj sedan Skapa.
Installera Microsoft.ML NuGet-paketet:
Anmärkning
Det här exemplet använder den senaste stabila versionen av De NuGet-paket som nämns om inget annat anges.
- Högerklicka på projektet i Solution Explorer och välj Hantera NuGet-paket.
- Välj "nuget.org" som paketkälla.
- Välj fliken Bläddra.
- Markera kryssrutan Inkludera förhandsversion .
- Sök efter Microsoft.ML.
- Välj knappen Installera.
- Välj knappen Jag accepterar i dialogrutan Licensgodkännande om du godkänner licensvillkoren för de paket som anges.
- Upprepa de här stegen för NuGet-paketen Microsoft.ML.Vision, SciSharp.TensorFlow.Redist (version 2.3.1) och Microsoft.ML.ImageAnalytics .
Förbereda och förstå data
Anmärkning
Datauppsättningarna för den här självstudien kommer från Maguire, Marc; Dorafshan, Sattar; och Thomas, Robert J., "SDNET2018: En bilddatamängd av betongsprickor för maskininlärningsapplikationer" (2018). Bläddra bland alla datauppsättningar. Papper 48. https://digitalcommons.usu.edu/all_datasets/48
SDNET2018 är en bilddatauppsättning som innehåller anteckningar för spruckna och icke-spruckna betongkonstruktioner (bryggdäck, väggar och trottoarer).
Data organiseras i tre underkataloger:
- D innehåller brodäcks-bilder
- P innehåller trottoarbilder
- W innehåller väggbilder
Var och en av dessa underkataloger innehåller ytterligare två prefixunderkataloger:
- C är prefixet som används för spruckna ytor
- U är prefixet som används för osprickade ytor
I den här självstudien används endast bryggdäcksbilder.
- Ladda ned datauppsättningen och packa upp.
- Skapa en katalog med namnet "Tillgångar" i projektet för att spara datamängdsfilerna.
- Kopiera CD- och UD-underkatalogerna från den nyligen uppackade katalogen till katalogen Assets.
Skapa indata- och utdataklasser
Öppna filen Program.cs och ersätt det befintliga innehållet med följande
usingdirektiv:using Microsoft.ML; using Microsoft.ML.Vision; using static Microsoft.ML.DataOperationsCatalog;Skapa en klass med namnet
ImageData. Den här klassen används för att representera de initialt inlästa data.class ImageData { public string? ImagePath { get; set; } public string? Label { get; set; } }ImageDatainnehåller följande egenskaper:-
ImagePathär den fullständigt kvalificerade sökvägen där avbildningen lagras. -
Labelär den kategori som bilden tillhör. Det här är det värde som ska förutsägas.
-
Skapa klasser för dina in- och utdata.
ImageDataUnder klassen definierar du schemat för dina indata i en ny klass med namnetModelInput.class ModelInput { public byte[]? Image { get; set; } public uint LabelAsKey { get; set; } public string? ImagePath { get; set; } public string? Label { get; set; } }ModelInputinnehåller följande egenskaper:-
Imageär bildensbyte[]representation. Modellen förväntar sig att bilddata ska vara av den här typen för träning. -
LabelAsKeyär den numeriska representationen avLabel. -
ImagePathär den fullständigt kvalificerade sökvägen där avbildningen lagras. -
Labelär den kategori som bilden tillhör. Det här är det värde som ska förutsägas.
Endast
ImageochLabelAsKeyanvänds för att träna modellen och göra förutsägelser. EgenskapernaImagePathochLabelbevaras för att underlätta åtkomsten till det ursprungliga bildfilnamnet och kategorin.-
ModelInputUnder klassen definierar du sedan schemat för dina utdata i en ny klass med namnetModelOutput.class ModelOutput { public string? ImagePath { get; set; } public string? Label { get; set; } public string? PredictedLabel { get; set; } }ModelOutputinnehåller följande egenskaper:-
ImagePathär den fullständigt kvalificerade sökvägen där avbildningen lagras. -
Labelär den ursprungliga kategorin som bilden tillhör. Det här är det värde som ska förutsägas. -
PredictedLabelär det värde som förutsägs av modellen.
ModelInputPå samma sätt krävs baraPredictedLabelför att göra förutsägelser eftersom den innehåller den förutsägelse som modellen har gjort. EgenskapernaImagePathochLabelbevaras för att underlätta åtkomsten till det ursprungliga avbildningsfilens namn och kategori.-
Definiera sökvägar och initiera variabler
I direktiven
usinglägger du till följande kod i:Definiera platsen för tillgångarna.
Initiera variabeln
mlContextmed en ny instans av MLContext.MLContext-klassen är en startpunkt för alla ML.NET åtgärder, och när mlContext initieras skapas en ny ML.NET miljö som kan delas mellan arbetsflödesobjekten för modellskapande. Det liknar konceptuellt
DbContexti Entity Framework.
var projectDirectory = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "../../../")); var assetsRelativePath = Path.Combine(projectDirectory, "Assets"); MLContext mlContext = new();
Läs in data
Skapa datainläsningsverktygsmetod
Bilderna lagras i två underkataloger. Innan data läses in måste de formateras till en lista med ImageData objekt. Det gör du genom att LoadImagesFromDirectory skapa metoden:
static IEnumerable<ImageData> LoadImagesFromDirectory(string folder, bool useFolderNameAsLabel = true)
{
var files = Directory.GetFiles(folder, "*",
searchOption: SearchOption.AllDirectories);
foreach (var file in files)
{
if ((Path.GetExtension(file) != ".jpg") && (Path.GetExtension(file) != ".png"))
continue;
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[..index];
break;
}
}
}
yield return new ImageData()
{
ImagePath = file,
Label = label
};
}
}
LoadImagesFromDirectory-metoden:
- Hämtar alla filsökvägar från underkatalogerna.
- Itererar genom var och en av filerna med hjälp av en
foreach-instruktion och kontrollerar att filnamnstilläggen stöds. API:et för bildklassificering stöder JPEG- och PNG-format. - Hämtar etiketten för filen. Om parametern
useFolderNameAsLabelär inställd påtrueanvänds den överordnade katalogen där filen sparas som etikett. Annars förväntar den sig att etiketten ska vara ett prefix för filnamnet eller själva filnamnet. - Skapar en ny instans av
ModelInput.
Förbered datan
Lägg till följande kod efter raden där du skapar den nya instansen av MLContext.
IEnumerable<ImageData> images = LoadImagesFromDirectory(folder: assetsRelativePath, useFolderNameAsLabel: true);
IDataView imageData = mlContext.Data.LoadFromEnumerable(images);
IDataView shuffledData = mlContext.Data.ShuffleRows(imageData);
var preprocessingPipeline = mlContext.Transforms.Conversion.MapValueToKey(
inputColumnName: "Label",
outputColumnName: "LabelAsKey")
.Append(mlContext.Transforms.LoadRawImageBytes(
outputColumnName: "Image",
imageFolder: assetsRelativePath,
inputColumnName: "ImagePath"));
IDataView preProcessedData = preprocessingPipeline
.Fit(shuffledData)
.Transform(shuffledData);
TrainTestData trainSplit = mlContext.Data.TrainTestSplit(data: preProcessedData, testFraction: 0.3);
TrainTestData validationTestSplit = mlContext.Data.TrainTestSplit(trainSplit.TestSet);
IDataView trainSet = trainSplit.TrainSet;
IDataView validationSet = validationTestSplit.TrainSet;
IDataView testSet = validationTestSplit.TestSet;
Föregående kod:
LoadImagesFromDirectoryAnropar verktygsmetoden för att hämta listan över bilder som används för träning när variabeln har initieratsmlContext.Läser in bilderna i en
IDataViewmed hjälp avLoadFromEnumerable-metoden.Blandar data med hjälp av
ShuffleRowsmetoden . Data läses in i den ordning de lästes upp från katalogerna. Shuffle utförs för att balansera den.Utför viss förbearbetning av data före träningen. Detta görs eftersom maskininlärningsmodeller förväntar sig att indata ska vara i numeriskt format. Förbearbetningskoden skapar en
EstimatorChainbestående avMapValueToKeyochLoadRawImageBytestransformeringar. TransformeringenMapValueToKeytar det kategoriska värdet iLabelkolumnen, konverterar det till ett numerisktKeyTypevärde och lagrar det i en ny kolumn med namnetLabelAsKey.LoadImagesTar värdena frånImagePathkolumnen tillsammans med parameternimageFolderför att läsa in bilder för träning.Använder
Fit-metoden för att tillämpa data påpreprocessingPipelineEstimatorChain, följt avTransform-metoden, som returnerar enIDataViewsom innehåller förbearbetade data.Delar upp data i tränings-, validerings- och testuppsättningar.
För att träna en modell är det viktigt att ha en träningsdatauppsättning och en valideringsdatauppsättning. Modellen tränas på träningsuppsättningen. Hur bra det gör förutsägelser på osedda data mäts av prestandan mot valideringsuppsättningen. Baserat på resultatet av den prestandan gör modellen justeringar i vad den har lärt sig i ett försök att förbättra. Valideringsuppsättningen kan komma från att antingen dela upp den ursprungliga datamängden eller från en annan källa som redan har reserverats för detta ändamål.
Kodexemplet utför två delningar. Först delas förbearbetade data och 70% används för träning medan de återstående 30% används för validering. Sedan delas valideringsuppsättningen 30% upp i validerings- och testuppsättningar där 90% används för validering och 10% används för testning.
Ett sätt att tänka på syftet med dessa datapartitioner är att ta en examen. När du studerar för ett prov granskar du dina anteckningar, böcker eller andra resurser för att få ett grepp om de begrepp som finns på provet. Det här är vad tåguppsättningen är till för. Sedan kan du göra ett övningsprov för att verifiera din kunskap. Det är här valideringsuppsättningen är praktisk. Du vill kontrollera om du har ett bra grepp om begreppen innan du tar det faktiska provet. Baserat på dessa resultat noterar du vad du har fel eller inte förstod väl och införlivar dina ändringar när du granskar för det verkliga provet. Slutligen tar du provet. Det här är vad testuppsättningen används för. Du har aldrig sett de frågor som finns på provet och använder nu det du har lärt dig från träning och validering för att tillämpa dina kunskaper på den aktuella uppgiften.
Tilldelar partitionerna sina respektive värden för tränings-, validerings- och testdata.
Definiera träningspipeline
Modellträning består av två steg. Först används API för bildklassificering för att träna modellen. Sedan konverteras de kodade etiketterna PredictedLabel i kolumnen tillbaka till sitt ursprungliga kategoriska värde med hjälp av transformeringen MapKeyToValue .
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
};
var trainingPipeline = mlContext.MulticlassClassification.Trainers.ImageClassification(classifierOptions)
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel"));
ITransformer trainedModel = trainingPipeline.Fit(trainSet);
Föregående kod:
Skapar en ny variabel för att lagra en uppsättning obligatoriska och valfria parametrar för en ImageClassificationTrainer. En ImageClassificationTrainer tar flera valfria parametrar:
-
FeatureColumnNameär kolumnen som används som indata för modellen. -
LabelColumnNameär kolumnen för det värde som ska förutsägas. -
ValidationSetär denIDataViewsom innehåller valideringsdata. -
Archdefinierar vilken av de förtränade modellarkitekturerna som ska användas. I den här handledningen används 101-lagers-varianten av ResNetv2-modellen. -
MetricsCallbackbinder en funktion för att spåra förloppet under träningen. -
TestOnTrainSetinstruerar modellen att mäta prestanda mot träningsuppsättningen när det inte finns någon verifieringsuppsättning. -
ReuseTrainSetBottleneckCachedValuesanger för modellen om de cachelagrade värdena ska användas från flaskhalsfasen i efterföljande körningar. Flaskhalsfasen är en engångsberäkning som är krävande ur beräkningssynpunkt första gången den utförs. Om träningsdata inte ändras och du vill experimentera med ett annat antal epoker eller batchstorlekar minskar användningen av cachelagrade värden avsevärt den tid som krävs för att träna en modell. -
ReuseValidationSetBottleneckCachedValuesliknarReuseTrainSetBottleneckCachedValuesbara att det i det här fallet är för valideringsdatauppsättningen.
-
Definierar träningspipelinen
EstimatorChainsom består av bådemapLabelEstimatoroch ImageClassificationTrainer.FitAnvänder metoden för att träna modellen.
Använd modellen
Nu när du har tränat modellen är det dags att använda den för att klassificera bilder.
Skapa en ny verktygsmetod med namnet OutputPrediction för att visa förutsägelseinformation i konsolen.
static void OutputPrediction(ModelOutput prediction)
{
string? imageName = Path.GetFileName(prediction.ImagePath);
Console.WriteLine($"Image: {imageName} | Actual Value: {prediction.Label} | Predicted Value: {prediction.PredictedLabel}");
}
Klassificera en enskild bild
Skapa en metod med namnet
ClassifySingleImageför att göra och mata ut en enda bildförutsägelse.static void ClassifySingleImage(MLContext mlContext, IDataView data, ITransformer trainedModel) { PredictionEngine<ModelInput, ModelOutput> predictionEngine = mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(trainedModel); ModelInput image = mlContext.Data.CreateEnumerable<ModelInput>(data, reuseRowObject: true).First(); ModelOutput prediction = predictionEngine.Predict(image); Console.WriteLine("Classifying single image"); OutputPrediction(prediction); }ClassifySingleImage-metoden:- Skapar en
PredictionEngineinutiClassifySingleImage-metoden.PredictionEngineär ett bekvämlighets-API som gör att du kan skicka in och sedan utföra en förutsägelse på en enda instans av data. - Om du vill komma åt en enda
ModelInputinstans konverterar dudataIDataViewtill enIEnumerablemed hjälp avCreateEnumerablemetoden och hämtar sedan den första observationen. -
PredictAnvänder metoden för att klassificera bilden. - Matar ut förutsägelsen till konsolen med
OutputPrediction-metoden.
- Skapar en
Anropa
ClassifySingleImagenär du anroparFit-metoden med ett testset av bilder.ClassifySingleImage(mlContext, testSet, trainedModel);
Klassificera flera bilder
Skapa en metod med namnet
ClassifyImagesför att skapa och mata ut flera bildförutsägelser.static void ClassifyImages(MLContext mlContext, IDataView data, ITransformer trainedModel) { IDataView predictionData = trainedModel.Transform(data); IEnumerable<ModelOutput> predictions = mlContext.Data.CreateEnumerable<ModelOutput>(predictionData, reuseRowObject: true).Take(10); Console.WriteLine("Classifying multiple images"); foreach (var prediction in predictions) { OutputPrediction(prediction); } }ClassifyImages-metoden:- Skapar en
IDataViewsom innehåller förutsägelserna genom att använda metodenTransform. - För att iterera över förutsägelserna konverterar
predictionDataIDataViewtill enIEnumerablemed metodenCreateEnumerableoch hämtar sedan de första 10 observationerna. - Itererar och matar ut de ursprungliga och förutsagda etiketterna för förutsägelserna.
- Skapar en
Anropa
ClassifyImagesnär du har anropatClassifySingleImage()-metoden med hjälp av en testuppsättning bilder.ClassifyImages(mlContext, testSet, trainedModel);
Kör programmet
Kör konsolappen. Utdata bör likna följande utdata.
Anmärkning
Du kan se varningar eller bearbetningsmeddelanden; dessa meddelanden har tagits bort från de följande resultaten för tydlighetens skull. För korthet har utdata komprimerats.
Flaskhalsfasen
Inget värde skrivs ut för bildnamnet eftersom bilderna läses in som ett byte[] därför finns det inget bildnamn att visa.
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
Träningsfas
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
Klassificera bilders utdata
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
Vid inspektion av 7001-220.jpg bild kan du kontrollera att den inte är sprucken, som modellen förutsade.
Grattis! Nu har du skapat en djupinlärningsmodell för att klassificera bilder.
Förbättra modellen
Om du inte är nöjd med resultatet av modellen kan du försöka förbättra dess prestanda genom att prova några av följande metoder:
- Mer data: Ju fler exempel en modell lär sig av, desto bättre presterar den. Ladda ned hela SDNET2018 datauppsättningen och använd den för att träna.
- Utöka data: En vanlig teknik för att lägga till variation i data är att utöka data genom att ta en bild och tillämpa olika transformeringar (rotera, vända, skifta, beskära). Detta lägger till mer varierande exempel för modellen att lära sig av.
- Träna under en längre tid: Ju längre du tränar, desto mer finjusterad blir modellen. Om du ökar antalet epoker kan det förbättra modellens prestanda.
- Experimentera med hyperparametrarna: Förutom de parametrar som används i den här självstudien kan andra parametrar justeras för att eventuellt förbättra prestandan. Om du ändrar inlärningshastigheten, som avgör omfattningen av uppdateringar som görs i modellen efter varje epok, kan prestandan förbättras.
- Använd en annan modellarkitektur: Beroende på hur dina data ser ut kan den modell som bäst kan lära sig dess funktioner skilja sig åt. Om du inte är nöjd med modellens prestanda kan du prova att ändra arkitekturen.
Nästa steg
I den här handledningen har du lärt dig hur du skapar en anpassad djupinlärningsmodell med hjälp av transfer learning, en förtränad TensorFlow-modell för bildklassificering och ML.NET API för bildklassificering för att klassificera bilder av betongytor som spruckna eller ospruckna.
Gå vidare till nästa handledning för att lära dig mer.