Zelfstudie: Objecten detecteren met BEHULP van ONNX in ML.NET
Meer informatie over het gebruik van een vooraf getraind ONNX-model in ML.NET om objecten in afbeeldingen te detecteren.
Voor het trainen van een volledig nieuw objectdetectiemodel moeten miljoenen parameters, een grote hoeveelheid gelabelde trainingsgegevens en een grote hoeveelheid rekenresources (honderden GPU-uren) worden ingesteld. Met behulp van een vooraf getraind model kunt u het trainingsproces snel doorlopen.
In deze zelfstudie leert u het volgende:
- Het probleem begrijpen
- Ontdek wat ONNX is en hoe het werkt met ML.NET
- Inzicht in het model
- Het vooraf getrainde model opnieuw gebruiken
- Objecten detecteren met een geladen model
Vereisten
- Visual Studio 2022.
- Microsoft.ML NuGet-pakket
- Microsoft.ML.ImageAnalytics NuGet-pakket
- Microsoft.ML.OnnxTransformer NuGet-pakket
- Klein YOLOv2 vooraf getraind model
- Netron (optioneel)
Overzicht van voorbeeld van ONNX-objectdetectie
In dit voorbeeld wordt een .NET Core-consoletoepassing gemaakt waarmee objecten in een afbeelding worden gedetecteerd met behulp van een vooraf getraind DEEP Learning ONNX-model. De code voor dit voorbeeld vindt u in de opslagplaats dotnet/machinelearning-samples op GitHub.
Wat is objectdetectie?
Objectdetectie is een computer vision-probleem. Hoewel objectdetectie nauw verwant is aan afbeeldingsclassificatie, wordt de classificatie van afbeeldingen op een gedetailleerdere schaal uitgevoerd. Objectdetectie zoekt en categoriseert entiteiten binnen afbeeldingen. Objectdetectiemodellen worden vaak getraind met behulp van deep learning en neurale netwerken. Zie Deep Learning versus machine learning voor meer informatie.
Objectdetectie gebruiken wanneer afbeeldingen meerdere objecten van verschillende typen bevatten.
Enkele gebruiksvoorbeelden voor objectdetectie zijn:
- Zelfrijdende auto's
- Robotica
- Gezichtsdetectie
- Veiligheid op de werkplek
- Object tellen
- Activiteitsherkenning
Een Deep Learning-model selecteren
Deep learning is een subset van machine learning. Voor het trainen van Deep Learning-modellen zijn grote hoeveelheden gegevens vereist. Patronen in de gegevens worden vertegenwoordigd door een reeks lagen. De relaties in de gegevens worden gecodeerd als verbindingen tussen de lagen met gewichten. Hoe hoger het gewicht, hoe sterker de relatie. Gezamenlijk worden deze reeks lagen en verbindingen kunstmatige neurale netwerken genoemd. Hoe meer lagen in een netwerk, hoe dieper het is, waardoor het een diep neuraal netwerk wordt.
Er zijn verschillende soorten neurale netwerken, de meest voorkomende multi-layered Perceptron (MLP), Convolutional Neural Network (CNN) en terugkerende neurale netwerken (RNN). De meest eenvoudige is de MLP, waarmee een set invoer wordt toegewezen aan een set uitvoerwaarden. Dit neurale netwerk is goed wanneer de gegevens geen ruimtelijk of tijdonderdeel hebben. De CNN maakt gebruik van convolutionele lagen om ruimtelijke informatie in de gegevens te verwerken. Een goed gebruiksvoorbeeld voor CNN's is het verwerken van afbeeldingen om de aanwezigheid van een functie in een regio van een afbeelding te detecteren (is er bijvoorbeeld een neus in het midden van een afbeelding?). Ten slotte zorgen RNN's ervoor dat de persistentie van de status of het geheugen als invoer kan worden gebruikt. RNN's worden gebruikt voor tijdreeksanalyse, waarbij de volgorde en context van gebeurtenissen belangrijk zijn.
Inzicht in het model
Objectdetectie is een taak voor het verwerken van afbeeldingen. Daarom zijn de meeste deep learning-modellen die zijn getraind om dit probleem op te lossen CNN's. Het model dat in deze zelfstudie wordt gebruikt, is het Tiny YOLOv2-model, een compactere versie van het YOLOv2-model dat wordt beschreven in het document: "YOLO9000: Better, Faster, Stronger" door Redmon en Farhadi. Kleine YOLOv2 wordt getraind op de Pascal VOC-gegevensset en bestaat uit 15 lagen die 20 verschillende klassen objecten kunnen voorspellen. Omdat Tiny YOLOv2 een verkorte versie van het oorspronkelijke YOLOv2-model is, wordt er een compromis gemaakt tussen snelheid en nauwkeurigheid. De verschillende lagen waaruit het model bestaat, kunnen worden gevisualiseerd met behulp van hulpprogramma's zoals Netron. Het inspecteren van het model zou een toewijzing opleveren van de verbindingen tussen alle lagen waaruit het neurale netwerk bestaat, waarbij elke laag de naam van de laag samen met de dimensies van de respectieve invoer/uitvoer zou bevatten. De gegevensstructuren die worden gebruikt om de invoer en uitvoer van het model te beschrijven, worden tensors genoemd. Tensors kunnen worden beschouwd als containers die gegevens opslaan in N-dimensies. In het geval van Tiny YOLOv2 is de naam van de invoerlaag image
en verwacht het een tensor van dimensies 3 x 416 x 416
. De naam van de uitvoerlaag is grid
en genereert een uitvoertenant van dimensies 125 x 13 x 13
.
Het YOLO-model maakt een afbeelding 3(RGB) x 416px x 416px
. Het model neemt deze invoer en geeft deze door de verschillende lagen om een uitvoer te produceren. De uitvoer verdeelt de invoerafbeelding in een 13 x 13
raster, waarbij elke cel in het raster bestaat uit 125
waarden.
Wat is een ONNX-model?
De Open Neural Network Exchange (ONNX) is een opensource-indeling voor AI-modellen. ONNX ondersteunt interoperabiliteit tussen frameworks. Dit betekent dat u een model kunt trainen in een van de vele populaire machine learning-frameworks zoals PyTorch, het kunt converteren naar ONNX-indeling en het ONNX-model in een ander framework kunt gebruiken, zoals ML.NET. Ga naar de ONNX-website voor meer informatie.
Het vooraf getrainde Tiny YOLOv2-model wordt opgeslagen in ONNX-indeling, een geserialiseerde weergave van de lagen en geleerde patronen van deze lagen. In ML.NET wordt de interoperabiliteit met ONNX bereikt met de ImageAnalytics
en OnnxTransformer
NuGet-pakketten. Het ImageAnalytics
pakket bevat een reeks transformaties die een afbeelding maken en coderen in numerieke waarden die kunnen worden gebruikt als invoer in een voorspellings- of trainingspijplijn. Het OnnxTransformer
pakket maakt gebruik van de ONNX Runtime om een ONNX-model te laden en te gebruiken om voorspellingen te doen op basis van de verstrekte invoer.
Het .NET Console-project instellen
Nu u een algemeen begrip hebt van wat ONNX is en hoe Tiny YOLOv2 werkt, is het tijd om de toepassing te bouwen.
Een consoletoepassing maken
Maak een C# -consoletoepassing met de naam ObjectDetection. Klik op de knop Volgende.
Kies .NET 6 als het framework dat u wilt gebruiken. Klik op de knop Maken.
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, zoek naar Microsoft.ML.
- Selecteer de knop Installeren .
- Selecteer de knop OK in het dialoogvenster Voorbeeld van wijzigingen en selecteer vervolgens de knop Accepteren in het dialoogvenster Acceptatie van licenties als u akkoord gaat met de licentievoorwaarden voor de vermelde pakketten.
- Herhaal deze stappen voor Microsoft.Windows.Compatibility, Microsoft.ML.ImageAnalytics, Microsoft.ML.OnnxTransformer en Microsoft.ML.OnnxRuntime.
Uw gegevens en vooraf getraind model voorbereiden
Download het zip-bestand van de map projectactiva en pak het uit.
Kopieer de map naar de
assets
projectmap ObjectDetection . Deze map en de bijbehorende submappen bevatten de afbeeldingsbestanden (met uitzondering van het Tiny YOLOv2-model, dat u in de volgende stap gaat downloaden en toevoegen) die nodig zijn voor deze zelfstudie.Download het Tiny YOLOv2-model uit de ONNX Model Zoo.
Kopieer het
model.onnx
bestand naar de projectmapassets\Model
ObjectDetection en wijzig de naam ervan inTinyYolo2_model.onnx
. Deze map bevat het model dat nodig is voor deze zelfstudie.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 om te kopiëren als nieuwer.
Klassen maken en paden definiëren
Open het bestand Program.cs en voeg de volgende aanvullende using
instructies toe aan het begin van het bestand:
using System.Drawing;
using System.Drawing.Drawing2D;
using ObjectDetection.YoloParser;
using ObjectDetection.DataStructures;
using ObjectDetection;
using Microsoft.ML;
Definieer vervolgens de paden van de verschillende assets.
Maak eerst de
GetAbsolutePath
methode onderaan het bestand Program.cs .string GetAbsolutePath(string relativePath) { FileInfo _dataRoot = new FileInfo(typeof(Program).Assembly.Location); string assemblyFolderPath = _dataRoot.Directory.FullName; string fullPath = Path.Combine(assemblyFolderPath, relativePath); return fullPath; }
Maak vervolgens onder de using-instructies velden om de locatie van uw assets op te slaan.
var assetsRelativePath = @"../../../assets"; string assetsPath = GetAbsolutePath(assetsRelativePath); var modelFilePath = Path.Combine(assetsPath, "Model", "TinyYolo2_model.onnx"); var imagesFolder = Path.Combine(assetsPath, "images"); var outputFolder = Path.Combine(assetsPath, "images", "output");
Voeg een nieuwe map toe aan uw project om uw invoergegevens en voorspellingsklassen op te slaan.
Klik in Solution Explorer met de rechtermuisknop op het project en selecteer Nieuwe map toevoegen>. Wanneer de nieuwe map wordt weergegeven in Solution Explorer, geeft u deze de naam 'DataStructures'.
Maak uw invoergegevensklasse in de zojuist gemaakte DataStructures-map .
Klik in Solution Explorer met de rechtermuisknop op de map DataStructures en selecteer Nieuw item toevoegen>.
Selecteer klasse in het dialoogvenster Nieuw item toevoegen en wijzig het veld Naam in ImageNetData.cs. Selecteer vervolgens de knop Toevoegen .
Het bestand ImageNetData.cs wordt geopend in de code-editor. Voeg de volgende
using
instructie toe aan het begin van ImageNetData.cs:using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.ML.Data;
Verwijder de bestaande klassedefinitie en voeg de volgende code voor de
ImageNetData
klasse toe aan het bestand ImageNetData.cs :public class ImageNetData { [LoadColumn(0)] public string ImagePath; [LoadColumn(1)] public string Label; public static IEnumerable<ImageNetData> ReadFromFile(string imageFolder) { return Directory .GetFiles(imageFolder) .Where(filePath => Path.GetExtension(filePath) != ".md") .Select(filePath => new ImageNetData { ImagePath = filePath, Label = Path.GetFileName(filePath) }); } }
ImageNetData
is de klasse invoerafbeeldingsgegevens en heeft de volgende String velden:ImagePath
bevat het pad waarin de afbeelding is opgeslagen.Label
bevat de naam van het bestand.
ImageNetData
Daarnaast bevat een methodeReadFromFile
waarmee meerdere afbeeldingsbestanden worden geladen die zijn opgeslagen in hetimageFolder
opgegeven pad en worden geretourneerd als een verzamelingImageNetData
objecten.
Maak uw voorspellingsklasse in de map DataStructures .
Klik in Solution Explorer met de rechtermuisknop op de map DataStructures en selecteer Nieuw item toevoegen>.
Selecteer in het dialoogvenster Nieuw item toevoegen de optie Klasse en wijzig het veld Naam in ImageNetPrediction.cs. Selecteer vervolgens de knop Toevoegen .
Het bestand ImageNetPrediction.cs wordt geopend in de code-editor. Voeg de volgende
using
instructie toe aan het begin van ImageNetPrediction.cs:using Microsoft.ML.Data;
Verwijder de bestaande klassedefinitie en voeg de volgende code voor de
ImageNetPrediction
klasse toe aan het bestand ImageNetPrediction.cs :public class ImageNetPrediction { [ColumnName("grid")] public float[] PredictedLabels; }
ImageNetPrediction
is de voorspellingsgegevensklasse en heeft het volgendefloat[]
veld:PredictedLabels
bevat de dimensies, objectnessscore en klassekansen voor elk van de begrenzingsvakken die in een afbeelding zijn gedetecteerd.
Variabelen initialiseren
De MLContext-klasse is een uitgangspunt voor alle ML.NET bewerkingen en het initialiseren mlContext
van een nieuwe ML.NET-omgeving die kan worden gedeeld in de werkstroomobjecten voor het maken van modellen. Het is vergelijkbaar, conceptueel gezien, met DBContext
in Entity Framework.
Initialiseer de mlContext
variabele met een nieuw exemplaar van MLContext
door de volgende regel onder het outputFolder
veld toe te voegen.
MLContext mlContext = new MLContext();
Een parser maken voor uitvoer na het procesmodel
Het model segmenteert een afbeelding in een 13 x 13
raster, waarbij elke rastercel zich bevindt 32px x 32px
. Elke rastercel bevat 5 potentiële objectbegrenzingsvakken. Een begrenzingsvak heeft 25 elementen:
x
de x-positie van het begrenzingsvak centreren ten opzichte van de rastercel waaraan deze is gekoppeld.y
de y-positie van het begrenzingsvak centreren ten opzichte van de rastercel waaraan deze is gekoppeld.w
de breedte van het begrenzingsvak.h
de hoogte van het begrenzingsvak.o
de betrouwbaarheidswaarde die een object bevat in het begrenzingsvak, ook wel objectnessscore genoemd.p1-p20
klassenkansen voor elk van de 20 klassen die door het model worden voorspeld.
In totaal vormen de 25 elementen die elk van de vijf begrenzingsvakken beschrijven de 125 elementen in elke rastercel.
De uitvoer die wordt gegenereerd door het vooraf getrainde ONNX-model is een floatmatrix van lengte 21125
, die de elementen van een tensor met dimensies 125 x 13 x 13
vertegenwoordigt. Om de voorspellingen die door het model worden gegenereerd, te transformeren in een tensor, is enige naverwerking vereist. Hiervoor maakt u een set klassen om de uitvoer te parseren.
Voeg een nieuwe map toe aan uw project om de set parserklassen te organiseren.
- Klik in Solution Explorer met de rechtermuisknop op het project en selecteer Nieuwe map toevoegen>. Wanneer de nieuwe map wordt weergegeven in Solution Explorer, geeft u deze de naam YoloParser.
Begrenzingsvakken en dimensies maken
De gegevensuitvoer van het model bevat coördinaten en dimensies van de begrenzingsvakken van objecten in de afbeelding. Maak een basisklasse voor dimensies.
Klik in Solution Explorer met de rechtermuisknop op de map YoloParser en selecteer Nieuw item toevoegen>.
Selecteer in het dialoogvenster Nieuw item toevoegen de optie Klasse en wijzig het veld Naam in DimensionsBase.cs. Selecteer vervolgens de knop Toevoegen .
Het bestand DimensionsBase.cs wordt geopend in de code-editor. Verwijder alle
using
instructies en bestaande klassedefinities.Voeg de volgende code voor de
DimensionsBase
klasse toe aan het bestand DimensionsBase.cs :public class DimensionsBase { public float X { get; set; } public float Y { get; set; } public float Height { get; set; } public float Width { get; set; } }
DimensionsBase
heeft de volgendefloat
eigenschappen:X
bevat de positie van het object langs de x-as.Y
bevat de positie van het object langs de y-as.Height
bevat de hoogte van het object.Width
bevat de breedte van het object.
Maak vervolgens een klasse voor uw begrenzingsvakken.
Klik in Solution Explorer met de rechtermuisknop op de map YoloParser en selecteer Nieuw item toevoegen>.
Selecteer in het dialoogvenster Nieuw item toevoegen de optie Klasse en wijzig het veld Naam in YoloBoundingBox.cs. Selecteer vervolgens de knop Toevoegen .
Het bestand YoloBoundingBox.cs wordt geopend in de code-editor. Voeg de volgende
using
instructie toe aan het begin van YoloBoundingBox.cs:using System.Drawing;
Voeg net boven de bestaande klassedefinitie een nieuwe klassedefinitie toe die wordt overgenomen
BoundingBoxDimensions
van deDimensionsBase
klasse die de dimensies van het desbetreffende begrenzingsvak bevat.public class BoundingBoxDimensions : DimensionsBase { }
Verwijder de bestaande
YoloBoundingBox
klassedefinitie en voeg de volgende code voor deYoloBoundingBox
klasse toe aan het bestand YoloBoundingBox.cs :public class YoloBoundingBox { public BoundingBoxDimensions Dimensions { get; set; } public string Label { get; set; } public float Confidence { get; set; } public RectangleF Rect { get { return new RectangleF(Dimensions.X, Dimensions.Y, Dimensions.Width, Dimensions.Height); } } public Color BoxColor { get; set; } }
YoloBoundingBox
heeft de volgende eigenschappen:Dimensions
bevat dimensies van het begrenzingsvak.Label
bevat de klasse van het object dat in het begrenzingsvak is gedetecteerd.Confidence
bevat het vertrouwen van de klasse.Rect
bevat de rechthoekweergave van de afmetingen van het begrenzingsvak.BoxColor
bevat de kleur die is gekoppeld aan de desbetreffende klasse die wordt gebruikt om op de afbeelding te tekenen.
De parser maken
Nu de klassen voor dimensies en begrenzingsvakken zijn gemaakt, is het tijd om de parser te maken.
Klik in Solution Explorer met de rechtermuisknop op de map YoloParser en selecteer Nieuw item toevoegen>.
Selecteer in het dialoogvenster Nieuw item toevoegen de optie Klasse en wijzig het veld Naam in YoloOutputParser.cs. Selecteer vervolgens de knop Toevoegen .
Het bestand YoloOutputParser.cs wordt geopend in de code-editor. Voeg de volgende
using
instructies toe aan het begin van YoloOutputParser.cs:using System; using System.Collections.Generic; using System.Drawing; using System.Linq;
Voeg binnen de bestaande
YoloOutputParser
klassedefinitie een geneste klasse toe die de afmetingen van elk van de cellen in de afbeelding bevat. Voeg de volgende code toe voor deCellDimensions
klasse die wordt overgenomen van deDimensionsBase
klasse boven aan deYoloOutputParser
klassedefinitie.class CellDimensions : DimensionsBase { }
Voeg in de
YoloOutputParser
klassedefinitie de volgende constanten en velden toe.public const int ROW_COUNT = 13; public const int COL_COUNT = 13; public const int CHANNEL_COUNT = 125; public const int BOXES_PER_CELL = 5; public const int BOX_INFO_FEATURE_COUNT = 5; public const int CLASS_COUNT = 20; public const float CELL_WIDTH = 32; public const float CELL_HEIGHT = 32; private int channelStride = ROW_COUNT * COL_COUNT;
ROW_COUNT
is het aantal rijen in het raster waarin de afbeelding is onderverdeeld.COL_COUNT
is het aantal kolommen in het raster waarin de afbeelding is onderverdeeld.CHANNEL_COUNT
is het totale aantal waarden in één cel van het raster.BOXES_PER_CELL
is het aantal begrenzingsvakken in een cel,BOX_INFO_FEATURE_COUNT
is het aantal functies in een vak (x,y,hoogte,breedte,betrouwbaarheid).CLASS_COUNT
is het aantal klassevoorspellingen in elk begrenzingsvak.CELL_WIDTH
is de breedte van één cel in het afbeeldingsraster.CELL_HEIGHT
is de hoogte van één cel in het afbeeldingsraster.channelStride
is de beginpositie van de huidige cel in het raster.
Wanneer het model een voorspelling doet, ook wel scoren genoemd, wordt de
416px x 416px
invoerafbeelding verdeeld in een raster van cellen met de grootte van13 x 13
. Elke cel bevat.32px x 32px
Binnen elke cel zijn er 5 begrenzingsvakken met elk 5 functies (x, y, breedte, hoogte, betrouwbaarheid). Bovendien bevat elk begrenzingsvak de waarschijnlijkheid van elk van de klassen, in dit geval 20. Daarom bevat elke cel 125 stukjes informatie (5 kenmerken + 20 klassenkansen).
Maak een lijst met ankers hieronder channelStride
voor alle vijf begrenzingsvakken:
private float[] anchors = new float[]
{
1.08F, 1.19F, 3.42F, 4.41F, 6.63F, 11.38F, 9.42F, 5.11F, 16.62F, 10.52F
};
Ankers zijn vooraf gedefinieerde hoogte- en breedteverhoudingen van begrenzingsvakken. De meeste objecten of klassen die door een model worden gedetecteerd, hebben vergelijkbare verhoudingen. Dit is waardevol als het gaat om het maken van begrenzingsvakken. In plaats van de begrenzingsvakken te voorspellen, wordt de verschuiving van de vooraf gedefinieerde dimensies berekend, waardoor de berekening die nodig is om het begrenzingsvak te voorspellen, wordt verminderd. Deze ankerverhoudingen worden doorgaans berekend op basis van de gebruikte gegevensset. Omdat de gegevensset bekend is en de waarden vooraf zijn berekend, kunnen de ankers in code worden vastgelegd.
Definieer vervolgens de labels of klassen die door het model worden voorspeld. Dit model voorspelt 20 klassen, een subset van het totale aantal klassen dat wordt voorspeld door het oorspronkelijke YOLOv2-model.
Voeg uw lijst met labels toe onder de anchors
.
private string[] labels = new string[]
{
"aeroplane", "bicycle", "bird", "boat", "bottle",
"bus", "car", "cat", "chair", "cow",
"diningtable", "dog", "horse", "motorbike", "person",
"pottedplant", "sheep", "sofa", "train", "tvmonitor"
};
Er zijn kleuren gekoppeld aan elk van de klassen. Wijs de klassenkleuren toe onder uw labels
:
private static Color[] classColors = new Color[]
{
Color.Khaki,
Color.Fuchsia,
Color.Silver,
Color.RoyalBlue,
Color.Green,
Color.DarkOrange,
Color.Purple,
Color.Gold,
Color.Red,
Color.Aquamarine,
Color.Lime,
Color.AliceBlue,
Color.Sienna,
Color.Orchid,
Color.Tan,
Color.LightPink,
Color.Yellow,
Color.HotPink,
Color.OliveDrab,
Color.SandyBrown,
Color.DarkTurquoise
};
Helperfuncties maken
Er zijn een reeks stappen betrokken bij de naverwerkingsfase. Hiervoor kunnen verschillende helpermethoden worden gebruikt.
De helpermethoden die door de parser worden gebruikt, zijn:
Sigmoid
past de sigmoid-functie toe die een getal tussen 0 en 1 uitvoert.Softmax
normaliseert een invoervector in een waarschijnlijkheidsverdeling.GetOffset
wijst elementen in de eendimensionale modeluitvoer toe aan de bijbehorende positie in een125 x 13 x 13
tensor.ExtractBoundingBoxes
extraheert de dimensies van het begrenzingsvak met behulp van deGetOffset
methode uit de modeluitvoer.GetConfidence
extraheert de betrouwbaarheidswaarde die aangeeft hoe zeker het model is dat het een object heeft gedetecteerd en deSigmoid
functie gebruikt om het om te zetten in een percentage.MapBoundingBoxToCell
gebruikt de afmetingen van het begrenzingsvak en wijst deze toe aan de desbetreffende cel in de afbeelding.ExtractClasses
extraheert de klassevoorspellingen voor het begrenzingsvak uit de modeluitvoer met behulp van deGetOffset
methode en verandert deze in een waarschijnlijkheidsverdeling met behulp van deSoftmax
methode.GetTopResult
selecteert de klasse in de lijst met voorspelde klassen met de hoogste waarschijnlijkheid.IntersectionOverUnion
filters overlappende begrenzingsvakken met lagere waarschijnlijkheden.
Voeg de code toe voor alle helpermethoden onder uw lijst met classColors
.
private float Sigmoid(float value)
{
var k = (float)Math.Exp(value);
return k / (1.0f + k);
}
private float[] Softmax(float[] values)
{
var maxVal = values.Max();
var exp = values.Select(v => Math.Exp(v - maxVal));
var sumExp = exp.Sum();
return exp.Select(v => (float)(v / sumExp)).ToArray();
}
private int GetOffset(int x, int y, int channel)
{
// YOLO outputs a tensor that has a shape of 125x13x13, which
// WinML flattens into a 1D array. To access a specific channel
// for a given (x,y) cell position, we need to calculate an offset
// into the array
return (channel * this.channelStride) + (y * COL_COUNT) + x;
}
private BoundingBoxDimensions ExtractBoundingBoxDimensions(float[] modelOutput, int x, int y, int channel)
{
return new BoundingBoxDimensions
{
X = modelOutput[GetOffset(x, y, channel)],
Y = modelOutput[GetOffset(x, y, channel + 1)],
Width = modelOutput[GetOffset(x, y, channel + 2)],
Height = modelOutput[GetOffset(x, y, channel + 3)]
};
}
private float GetConfidence(float[] modelOutput, int x, int y, int channel)
{
return Sigmoid(modelOutput[GetOffset(x, y, channel + 4)]);
}
private CellDimensions MapBoundingBoxToCell(int x, int y, int box, BoundingBoxDimensions boxDimensions)
{
return new CellDimensions
{
X = ((float)x + Sigmoid(boxDimensions.X)) * CELL_WIDTH,
Y = ((float)y + Sigmoid(boxDimensions.Y)) * CELL_HEIGHT,
Width = (float)Math.Exp(boxDimensions.Width) * CELL_WIDTH * anchors[box * 2],
Height = (float)Math.Exp(boxDimensions.Height) * CELL_HEIGHT * anchors[box * 2 + 1],
};
}
public float[] ExtractClasses(float[] modelOutput, int x, int y, int channel)
{
float[] predictedClasses = new float[CLASS_COUNT];
int predictedClassOffset = channel + BOX_INFO_FEATURE_COUNT;
for (int predictedClass = 0; predictedClass < CLASS_COUNT; predictedClass++)
{
predictedClasses[predictedClass] = modelOutput[GetOffset(x, y, predictedClass + predictedClassOffset)];
}
return Softmax(predictedClasses);
}
private ValueTuple<int, float> GetTopResult(float[] predictedClasses)
{
return predictedClasses
.Select((predictedClass, index) => (Index: index, Value: predictedClass))
.OrderByDescending(result => result.Value)
.First();
}
private float IntersectionOverUnion(RectangleF boundingBoxA, RectangleF boundingBoxB)
{
var areaA = boundingBoxA.Width * boundingBoxA.Height;
if (areaA <= 0)
return 0;
var areaB = boundingBoxB.Width * boundingBoxB.Height;
if (areaB <= 0)
return 0;
var minX = Math.Max(boundingBoxA.Left, boundingBoxB.Left);
var minY = Math.Max(boundingBoxA.Top, boundingBoxB.Top);
var maxX = Math.Min(boundingBoxA.Right, boundingBoxB.Right);
var maxY = Math.Min(boundingBoxA.Bottom, boundingBoxB.Bottom);
var intersectionArea = Math.Max(maxY - minY, 0) * Math.Max(maxX - minX, 0);
return intersectionArea / (areaA + areaB - intersectionArea);
}
Nadat u alle helpermethoden hebt gedefinieerd, is het tijd om ze te gebruiken om de modeluitvoer te verwerken.
Maak onder de IntersectionOverUnion
methode de ParseOutputs
methode om de uitvoer te verwerken die door het model is gegenereerd.
public IList<YoloBoundingBox> ParseOutputs(float[] yoloModelOutputs, float threshold = .3F)
{
}
Maak een lijst om uw begrenzingsvakken op te slaan en variabelen in de ParseOutputs
methode te definiëren.
var boxes = new List<YoloBoundingBox>();
Elke afbeelding is onderverdeeld in een raster met 13 x 13
cellen. Elke cel bevat vijf begrenzingsvakken. Voeg onder de boxes
variabele code toe om alle vakken in elk van de cellen te verwerken.
for (int row = 0; row < ROW_COUNT; row++)
{
for (int column = 0; column < COL_COUNT; column++)
{
for (int box = 0; box < BOXES_PER_CELL; box++)
{
}
}
}
Bereken in de binnenste lus de beginpositie van het huidige vak in de eendimensionale modeluitvoer.
var channel = (box * (CLASS_COUNT + BOX_INFO_FEATURE_COUNT));
Direct daaronder gebruikt u de ExtractBoundingBoxDimensions
methode om de afmetingen van het huidige begrenzingsvak op te halen.
BoundingBoxDimensions boundingBoxDimensions = ExtractBoundingBoxDimensions(yoloModelOutputs, row, column, channel);
Gebruik vervolgens de GetConfidence
methode om het vertrouwen voor het huidige begrenzingsvak te verkrijgen.
float confidence = GetConfidence(yoloModelOutputs, row, column, channel);
Gebruik daarna de MapBoundingBoxToCell
methode om het huidige begrenzingsvak toe te wijzen aan de huidige cel die wordt verwerkt.
CellDimensions mappedBoundingBox = MapBoundingBoxToCell(row, column, box, boundingBoxDimensions);
Controleer voordat u verdere verwerking uitvoert of uw betrouwbaarheidswaarde groter is dan de opgegeven drempelwaarde. Zo niet, dan verwerkt u het volgende begrenzingsvak.
if (confidence < threshold)
continue;
Anders kunt u doorgaan met het verwerken van de uitvoer. De volgende stap is het ophalen van de waarschijnlijkheidsverdeling van de voorspelde klassen voor het huidige begrenzingsvak met behulp van de ExtractClasses
methode.
float[] predictedClasses = ExtractClasses(yoloModelOutputs, row, column, channel);
Gebruik vervolgens de GetTopResult
methode om de waarde en index van de klasse op te halen met de hoogste waarschijnlijkheid voor het huidige vak en de bijbehorende score te berekenen.
var (topResultIndex, topResultScore) = GetTopResult(predictedClasses);
var topScore = topResultScore * confidence;
Gebruik de topScore
functie om alleen de begrenzingsvakken boven de opgegeven drempelwaarde te houden.
if (topScore < threshold)
continue;
Als het huidige begrenzingsvak de drempelwaarde overschrijdt, maakt u een nieuw BoundingBox
object en voegt u dit toe aan de boxes
lijst.
boxes.Add(new YoloBoundingBox()
{
Dimensions = new BoundingBoxDimensions
{
X = (mappedBoundingBox.X - mappedBoundingBox.Width / 2),
Y = (mappedBoundingBox.Y - mappedBoundingBox.Height / 2),
Width = mappedBoundingBox.Width,
Height = mappedBoundingBox.Height,
},
Confidence = topScore,
Label = labels[topResultIndex],
BoxColor = classColors[topResultIndex]
});
Zodra alle cellen in de afbeelding zijn verwerkt, retourneert u de boxes
lijst. Voeg de volgende retourinstructie toe onder de buitenste for-lus in de ParseOutputs
methode.
return boxes;
Overlappende vakken filteren
Nu alle zeer zeker begrenzingsvakken zijn geëxtraheerd uit de modeluitvoer, moet u aanvullende filters uitvoeren om overlappende afbeeldingen te verwijderen. Voeg een methode toe die onder de ParseOutputs
methode wordt aangeroepenFilterBoundingBoxes
:
public IList<YoloBoundingBox> FilterBoundingBoxes(IList<YoloBoundingBox> boxes, int limit, float threshold)
{
}
Begin in de FilterBoundingBoxes
methode door een matrix te maken die gelijk is aan de grootte van gedetecteerde vakken en alle sleuven als actief of gereed voor verwerking te markeren.
var activeCount = boxes.Count;
var isActiveBoxes = new bool[boxes.Count];
for (int i = 0; i < isActiveBoxes.Length; i++)
isActiveBoxes[i] = true;
Sorteer vervolgens de lijst met de begrenzingsvakken in aflopende volgorde op basis van betrouwbaarheid.
var sortedBoxes = boxes.Select((b, i) => new { Box = b, Index = i })
.OrderByDescending(b => b.Box.Confidence)
.ToList();
Maak daarna een lijst voor het opslaan van de gefilterde resultaten.
var results = new List<YoloBoundingBox>();
Begin met het verwerken van elk begrenzingsvak door elk van de begrenzingsvakken te herhalen.
for (int i = 0; i < boxes.Count; i++)
{
}
Controleer in deze for-lus of het huidige begrenzingsvak kan worden verwerkt.
if (isActiveBoxes[i])
{
}
Zo ja, voeg het begrenzingsvak toe aan de lijst met resultaten. Als de resultaten de opgegeven limiet overschrijden voor vakken die moeten worden geëxtraheerd, breekt u de lus uit. Voeg de volgende code toe in de if-instructie.
var boxA = sortedBoxes[i].Box;
results.Add(boxA);
if (results.Count >= limit)
break;
Kijk anders naar de aangrenzende begrenzingsvakken. Voeg de volgende code toe onder de selectievakjeslimiet.
for (var j = i + 1; j < boxes.Count; j++)
{
}
Als het aangrenzende vak actief is of klaar is om te worden verwerkt, gebruikt u de IntersectionOverUnion
methode om te controleren of het eerste vak en het tweede vak de opgegeven drempelwaarde overschrijden. Voeg de volgende code toe aan uw binnenste for-loop.
if (isActiveBoxes[j])
{
var boxB = sortedBoxes[j].Box;
if (IntersectionOverUnion(boxA.Rect, boxB.Rect) > threshold)
{
isActiveBoxes[j] = false;
activeCount--;
if (activeCount <= 0)
break;
}
}
Buiten de binnenste for-lus die aangrenzende begrenzingsvakken controleert, controleert u of er nog begrenzingsvakken moeten worden verwerkt. Zo niet, dan kunt u de buitenste for-lus losmaken.
if (activeCount <= 0)
break;
Retourneer ten slotte, buiten de eerste for-loop van de FilterBoundingBoxes
methode, de resultaten:
return results;
Mooi! Nu is het tijd om deze code samen met het model te gebruiken voor scoren.
Het model gebruiken voor scoren
Net als bij naverwerking zijn er enkele stappen in de scorestappen. Als u dit wilt helpen, voegt u een klasse toe die de scorelogica aan uw project bevat.
Klik in Solution Explorer met de rechtermuisknop op het project en selecteer Nieuw item toevoegen>.
Selecteer in het dialoogvenster Nieuw item toevoegen de optie Klasse en wijzig het veld Naam in OnnxModelScorer.cs. Selecteer vervolgens de knop Toevoegen .
Het bestand OnnxModelScorer.cs wordt geopend in de code-editor. Voeg de volgende
using
instructies toe aan het begin van OnnxModelScorer.cs:using System; using System.Collections.Generic; using System.Linq; using Microsoft.ML; using Microsoft.ML.Data; using ObjectDetection.DataStructures; using ObjectDetection.YoloParser;
Voeg in de
OnnxModelScorer
klassedefinitie de volgende variabelen toe.private readonly string imagesFolder; private readonly string modelLocation; private readonly MLContext mlContext; private IList<YoloBoundingBox> _boundingBoxes = new List<YoloBoundingBox>();
Maak daaronder een constructor voor de
OnnxModelScorer
klasse waarmee de eerder gedefinieerde variabelen worden geïnitialiseerd.public OnnxModelScorer(string imagesFolder, string modelLocation, MLContext mlContext) { this.imagesFolder = imagesFolder; this.modelLocation = modelLocation; this.mlContext = mlContext; }
Zodra u de constructor hebt gemaakt, definieert u een aantal structs die variabelen bevatten die betrekking hebben op de afbeeldings- en modelinstellingen. Maak een struct die wordt aangeroepen
ImageNetSettings
om de verwachte hoogte en breedte te bevatten als invoer voor het model.public struct ImageNetSettings { public const int imageHeight = 416; public const int imageWidth = 416; }
Maak daarna een andere struct met de naam
TinyYoloModelSettings
van de invoer- en uitvoerlagen van het model. Als u de naam van de invoer- en uitvoerlagen van het model wilt visualiseren, kunt u een hulpprogramma zoals Netron gebruiken.public struct TinyYoloModelSettings { // for checking Tiny yolo2 Model input and output parameter names, //you can use tools like Netron, // which is installed by Visual Studio AI Tools // input tensor name public const string ModelInput = "image"; // output tensor name public const string ModelOutput = "grid"; }
Maak vervolgens de eerste set methoden die worden gebruikt voor scoren. Maak de
LoadModel
methode in uwOnnxModelScorer
klas.private ITransformer LoadModel(string modelLocation) { }
Voeg in de
LoadModel
methode de volgende code toe voor logboekregistratie.Console.WriteLine("Read model"); Console.WriteLine($"Model location: {modelLocation}"); Console.WriteLine($"Default parameters: image size=({ImageNetSettings.imageWidth},{ImageNetSettings.imageHeight})");
ML.NET pijplijnen moeten weten waar het gegevensschema op moet worden uitgevoerd wanneer de
Fit
methode wordt aangeroepen. In dit geval wordt een proces gebruikt dat vergelijkbaar is met training. Omdat er echter geen daadwerkelijke training plaatsvindt, is het acceptabel om een legeIDataView
te gebruiken. Maak een nieuweIDataView
voor de pijplijn op basis van een lege lijst.var data = mlContext.Data.LoadFromEnumerable(new List<ImageNetData>());
Definieer daaronder de pijplijn. De pijplijn bestaat uit vier transformaties.
LoadImages
laadt de afbeelding als bitmap.ResizeImages
schaalt de afbeelding opnieuw naar de opgegeven grootte (in dit geval416 x 416
).ExtractPixels
wijzigt de pixelweergave van de afbeelding van een bitmap in een numerieke vector.ApplyOnnxModel
laadt het ONNX-model en gebruikt het om te scoren op de opgegeven gegevens.
Definieer uw pijplijn in de
LoadModel
methode onder dedata
variabele.var pipeline = mlContext.Transforms.LoadImages(outputColumnName: "image", imageFolder: "", inputColumnName: nameof(ImageNetData.ImagePath)) .Append(mlContext.Transforms.ResizeImages(outputColumnName: "image", imageWidth: ImageNetSettings.imageWidth, imageHeight: ImageNetSettings.imageHeight, inputColumnName: "image")) .Append(mlContext.Transforms.ExtractPixels(outputColumnName: "image")) .Append(mlContext.Transforms.ApplyOnnxModel(modelFile: modelLocation, outputColumnNames: new[] { TinyYoloModelSettings.ModelOutput }, inputColumnNames: new[] { TinyYoloModelSettings.ModelInput }));
Nu is het tijd om het model te instantiëren voor scoren. Roep de
Fit
methode in de pijplijn aan en retourneer deze voor verdere verwerking.var model = pipeline.Fit(data); return model;
Zodra het model is geladen, kan het worden gebruikt om voorspellingen te doen. Als u dit proces wilt vergemakkelijken, maakt u een methode die onder de LoadModel
methode wordt aangeroepenPredictDataUsingModel
.
private IEnumerable<float[]> PredictDataUsingModel(IDataView testData, ITransformer model)
{
}
Voeg in de PredictDataUsingModel
code de volgende code toe voor logboekregistratie.
Console.WriteLine($"Images location: {imagesFolder}");
Console.WriteLine("");
Console.WriteLine("=====Identify the objects in the images=====");
Console.WriteLine("");
Gebruik vervolgens de Transform
methode om de gegevens te scoren.
IDataView scoredData = model.Transform(testData);
Extraheer de voorspelde waarschijnlijkheden en retourneer ze voor aanvullende verwerking.
IEnumerable<float[]> probabilities = scoredData.GetColumn<float[]>(TinyYoloModelSettings.ModelOutput);
return probabilities;
Nu beide stappen zijn ingesteld, combineert u deze in één methode. Voeg onder de methode een nieuwe methode toe met de PredictDataUsingModel
naam Score
.
public IEnumerable<float[]> Score(IDataView data)
{
var model = LoadModel(modelLocation);
return PredictDataUsingModel(data, model);
}
Bijna klaar! Nu is het tijd om alles te gebruiken.
Objecten detecteren
Nu alle installatie is voltooid, is het tijd om enkele objecten te detecteren.
Modeluitvoer beoordelen en parseren
Voeg onder het maken van de mlContext
variabele een try-catch-instructie toe.
try
{
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Begin binnen het try
blok met het implementeren van de objectdetectielogica. Laad eerst de gegevens in een IDataView
.
IEnumerable<ImageNetData> images = ImageNetData.ReadFromFile(imagesFolder);
IDataView imageDataView = mlContext.Data.LoadFromEnumerable(images);
Maak vervolgens een exemplaar van OnnxModelScorer
en gebruik deze om de geladen gegevens te scoren.
// Create instance of model scorer
var modelScorer = new OnnxModelScorer(imagesFolder, modelFilePath, mlContext);
// Use model to score data
IEnumerable<float[]> probabilities = modelScorer.Score(imageDataView);
Nu is het tijd voor de stap na verwerking. Maak een exemplaar van YoloOutputParser
en gebruik dit om de modeluitvoer te verwerken.
YoloOutputParser parser = new YoloOutputParser();
var boundingBoxes =
probabilities
.Select(probability => parser.ParseOutputs(probability))
.Select(boxes => parser.FilterBoundingBoxes(boxes, 5, .5F));
Zodra de modeluitvoer is verwerkt, is het tijd om de begrenzingsvakken op de afbeeldingen te tekenen.
Voorspellingen visualiseren
Nadat het model de afbeeldingen heeft gescoord en de uitvoer is verwerkt, moeten de begrenzingsvakken op de afbeelding worden getekend. Voeg hiervoor een methode toe die wordt aangeroepen DrawBoundingBox
onder de GetAbsolutePath
methode in Program.cs.
void DrawBoundingBox(string inputImageLocation, string outputImageLocation, string imageName, IList<YoloBoundingBox> filteredBoundingBoxes)
{
}
Laad eerst de afbeelding en haal de afmetingen van de hoogte en breedte op in de DrawBoundingBox
methode.
Image image = Image.FromFile(Path.Combine(inputImageLocation, imageName));
var originalImageHeight = image.Height;
var originalImageWidth = image.Width;
Maak vervolgens een for-each-lus om elk van de begrenzingsvakken te herhalen die door het model worden gedetecteerd.
foreach (var box in filteredBoundingBoxes)
{
}
Haal in de voor-elke lus de afmetingen van het begrenzingsvak op.
var x = (uint)Math.Max(box.Dimensions.X, 0);
var y = (uint)Math.Max(box.Dimensions.Y, 0);
var width = (uint)Math.Min(originalImageWidth - x, box.Dimensions.Width);
var height = (uint)Math.Min(originalImageHeight - y, box.Dimensions.Height);
Omdat de afmetingen van het begrenzingsvak overeenkomen met de modelinvoer 416 x 416
, kunt u de afmetingen van het begrenzingsvak aanpassen aan de werkelijke grootte van de afbeelding.
x = (uint)originalImageWidth * x / OnnxModelScorer.ImageNetSettings.imageWidth;
y = (uint)originalImageHeight * y / OnnxModelScorer.ImageNetSettings.imageHeight;
width = (uint)originalImageWidth * width / OnnxModelScorer.ImageNetSettings.imageWidth;
height = (uint)originalImageHeight * height / OnnxModelScorer.ImageNetSettings.imageHeight;
Definieer vervolgens een sjabloon voor tekst die boven elk begrenzingsvak wordt weergegeven. De tekst bevat de klasse van het object in het desbetreffende begrenzingsvak en de betrouwbaarheid.
string text = $"{box.Label} ({(box.Confidence * 100).ToString("0")}%)";
Als u op de afbeelding wilt tekenen, converteert u deze naar een Graphics
object.
using (Graphics thumbnailGraphic = Graphics.FromImage(image))
{
}
Stem in het using
codeblok de objectinstellingen van Graphics
de afbeelding af.
thumbnailGraphic.CompositingQuality = CompositingQuality.HighQuality;
thumbnailGraphic.SmoothingMode = SmoothingMode.HighQuality;
thumbnailGraphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
Stel daaronder het lettertype en de kleuropties voor het tekst- en begrenzingsvak in.
// Define Text Options
Font drawFont = new Font("Arial", 12, FontStyle.Bold);
SizeF size = thumbnailGraphic.MeasureString(text, drawFont);
SolidBrush fontBrush = new SolidBrush(Color.Black);
Point atPoint = new Point((int)x, (int)y - (int)size.Height - 1);
// Define BoundingBox options
Pen pen = new Pen(box.BoxColor, 3.2f);
SolidBrush colorBrush = new SolidBrush(box.BoxColor);
Maak en vul een rechthoek boven het begrenzingsvak om de tekst te bevatten met behulp van de FillRectangle
methode. Hiermee kunt u de tekst contrasteren en de leesbaarheid verbeteren.
thumbnailGraphic.FillRectangle(colorBrush, (int)x, (int)(y - size.Height - 1), (int)size.Width, (int)size.Height);
Teken vervolgens de tekst en het begrenzingsvak op de afbeelding met behulp van de DrawString
en DrawRectangle
methoden.
thumbnailGraphic.DrawString(text, drawFont, fontBrush, atPoint);
// Draw bounding box on image
thumbnailGraphic.DrawRectangle(pen, x, y, width, height);
Voeg buiten de for-each-lus code toe om de afbeeldingen op te slaan in de outputFolder
.
if (!Directory.Exists(outputImageLocation))
{
Directory.CreateDirectory(outputImageLocation);
}
image.Save(Path.Combine(outputImageLocation, imageName));
Voor aanvullende feedback dat de toepassing voorspellingen doet zoals verwacht tijdens de runtime, voegt u een methode toe die onder de DrawBoundingBox
methode in het bestand Program.cs wordt aangeroepen LogDetectedObjects
om de gedetecteerde objecten naar de console uit te voeren.
void LogDetectedObjects(string imageName, IList<YoloBoundingBox> boundingBoxes)
{
Console.WriteLine($".....The objects in the image {imageName} are detected as below....");
foreach (var box in boundingBoxes)
{
Console.WriteLine($"{box.Label} and its Confidence score: {box.Confidence}");
}
Console.WriteLine("");
}
Nu u helpermethoden hebt om visuele feedback te maken op basis van de voorspellingen, voegt u een for-loop toe om elk van de gescoorde afbeeldingen te herhalen.
for (var i = 0; i < images.Count(); i++)
{
}
Haal in de for-lus de naam op van het afbeeldingsbestand en de begrenzingsvakken die eraan zijn gekoppeld.
string imageFileName = images.ElementAt(i).Label;
IList<YoloBoundingBox> detectedObjects = boundingBoxes.ElementAt(i);
Gebruik daaronder de DrawBoundingBox
methode om de begrenzingsvakken op de afbeelding te tekenen.
DrawBoundingBox(imagesFolder, outputFolder, imageFileName, detectedObjects);
Ten slotte gebruikt u de LogDetectedObjects
methode om voorspellingen naar de console uit te voeren.
LogDetectedObjects(imageFileName, detectedObjects);
Voeg na de try-catch-instructie aanvullende logica toe om aan te geven dat het proces is uitgevoerd.
Console.WriteLine("========= End of Process..Hit any Key ========");
Dat is het!
Resultaten
Nadat u de vorige stappen hebt uitgevoerd, voert u de console-app (Ctrl+F5) uit. Uw resultaten moeten vergelijkbaar zijn met de volgende uitvoer. U ziet mogelijk waarschuwingen of het verwerken van berichten, maar deze berichten zijn voor de duidelijkheid verwijderd uit de volgende resultaten.
=====Identify the objects in the images=====
.....The objects in the image image1.jpg are detected as below....
car and its Confidence score: 0.9697262
car and its Confidence score: 0.6674225
person and its Confidence score: 0.5226039
car and its Confidence score: 0.5224892
car and its Confidence score: 0.4675332
.....The objects in the image image2.jpg are detected as below....
cat and its Confidence score: 0.6461141
cat and its Confidence score: 0.6400049
.....The objects in the image image3.jpg are detected as below....
chair and its Confidence score: 0.840578
chair and its Confidence score: 0.796363
diningtable and its Confidence score: 0.6056048
diningtable and its Confidence score: 0.3737402
.....The objects in the image image4.jpg are detected as below....
dog and its Confidence score: 0.7608147
person and its Confidence score: 0.6321323
dog and its Confidence score: 0.5967442
person and its Confidence score: 0.5730394
person and its Confidence score: 0.5551759
========= End of Process..Hit any Key ========
Als u de afbeeldingen met begrenzingsvakken wilt zien, gaat u naar de assets/images/output/
map. Hieronder ziet u een voorbeeld van een van de verwerkte afbeeldingen.
Gefeliciteerd. U hebt nu een machine learning-model gebouwd voor objectdetectie door een vooraf getraind ONNX
model opnieuw te gebruiken in ML.NET.
U vindt de broncode voor deze zelfstudie in de opslagplaats dotnet/machinelearning-samples .
In deze zelfstudie heeft u het volgende geleerd:
- Het probleem begrijpen
- Ontdek wat ONNX is en hoe het werkt met ML.NET
- Inzicht in het model
- Het vooraf getrainde model opnieuw gebruiken
- Objecten detecteren met een geladen model
Bekijk de GitHub-opslagplaats met Machine Learning-voorbeelden om een uitgebreid voorbeeld van objectdetectie te verkennen.