Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
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 handleiding leer je hoe je:
- 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
Vereiste voorwaarden
- Visual Studio 2022 of hoger.
- 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 nemen en deze 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 8 als framework dat u wilt gebruiken. Klik op de knop Maken.
Installeer het Microsoft.ML NuGet-pakket:
Opmerking
In dit voorbeeld wordt de laatste 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 projectbestandenmap en pak het uit.
Kopieer de
assetsmap naar je 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.onnxbestand naar de projectmapassets\Modelen wijzig de naam ervan inTinyYolo2_model.onnx. Deze map bevat het model dat nodig is voor deze cursus.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 naar 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
GetAbsolutePathmethode onderaan het Program.cs-bestand .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 onder de
usinginstructies 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 selecteerNieuwe map>. 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 selecteerNieuw item>.
Selecteer in het dialoogvenster Nieuw item toevoegen de optie Klasse en wijzig het veld Naamin ImageNetData.cs. Selecteer vervolgens Toevoegen.
Het bestand ImageNetData.cs wordt geopend in de code-editor. Voeg de volgende
usinginstructie 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
ImageNetDataklasse toe aan het ImageNetData.cs-bestand :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) }); } }ImageNetDatais de klasse invoerafbeeldingsgegevens en heeft de volgende String velden:-
ImagePathbevat het pad waarin de afbeelding is opgeslagen. -
Labelbevat de naam van het bestand.
ImageNetDataDaarnaast bevat een methodeReadFromFilewaarmee meerdere afbeeldingsbestanden worden geladen die zijn opgeslagen in hetimageFolderopgegeven pad en worden geretourneerd als een verzamelingImageNetDataobjecten.-
Maak uw voorspellingsklasse in de map DataStructures .
Klik in Solution Explorer met de rechtermuisknop op de map DataStructures en selecteerNieuw item>.
Selecteer klasse in het dialoogvenster Nieuw item toevoegen en wijzig het veld Naamin ImageNetPrediction.cs. Selecteer vervolgens Toevoegen.
Het bestand ImageNetPrediction.cs wordt geopend in de code-editor. Voeg de volgende
usinginstructie toe aan het begin van ImageNetPrediction.cs:using Microsoft.ML.Data;Verwijder de bestaande klassedefinitie en voeg de volgende code voor de
ImageNetPredictionklasse toe aan het ImageNetPrediction.cs-bestand :public class ImageNetPrediction { [ColumnName("grid")] public float[] PredictedLabels; }ImageNetPredictionis de voorspellingsgegevensklasse en heeft het volgendefloat[]veld:-
PredictedLabelsbevat de dimensies, objectness-score en klassewaarschijnlijkheden voor elk van de begrenzingsboxen die in een afbeelding zijn gedetecteerd.
-
Variabelen initialiseren
De MLContext-klasse is startpunt voor alle ML.NET-bewerkingen en initialisatie mlContext creëert een nieuwe ML.NET-omgeving die kan worden gedeeld in de werkstromen 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 om modeluitvoer na te bewerken
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 bounding box heeft 25 elementen:
-
xde x-positie van het centrum van de begrenzingsdoos ten opzichte van de rastercel waaraan deze is gekoppeld. -
yde y-positie van het centrum van het begrenzingsvak ten opzichte van de rastercel waarmee het is geassocieerd. -
wde breedte van het omgrenzingsvak. -
hde hoogte van het omsluitende kader. -
ode waarschijnlijkheidswaarde dat een object binnen het omkaderingsvak bestaat, ook wel objectnessscore genoemd. -
p1-p20klassenkansen 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 met lengte 21125, die de elementen van een tensor met dimensies 125 x 13 x 13vertegenwoordigt. 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 selecteerNieuwe map>. 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 selecteerNieuw item>.
Selecteer in het dialoogvenster Nieuw item toevoegen de optie Klasse en wijzig het veld Naamin DimensionsBase.cs. Selecteer vervolgens Toevoegen.
Het bestand DimensionsBase.cs wordt geopend in de code-editor. Verwijder alle
usinginstructies en bestaande klassedefinities.Voeg de volgende code voor de
DimensionsBaseklasse toe aan het DimensionsBase.cs-bestand :public class DimensionsBase { public float X { get; set; } public float Y { get; set; } public float Height { get; set; } public float Width { get; set; } }DimensionsBaseheeft de volgendefloateigenschappen:-
Xbevat de positie van het object langs de x-as. -
Ybevat de positie van het object langs de y-as. -
Heightbevat de hoogte van het object. -
Widthbevat de breedte van het object.
-
Maak vervolgens een klasse voor jouw begrenzingsrechthoeken.
Klik in Solution Explorer met de rechtermuisknop op de map YoloParser en selecteerNieuw item>.
Selecteer in het dialoogvenster Nieuw item toevoegen de optie Klasse en wijzig het veld Naamin YoloBoundingBox.cs. Selecteer vervolgens Toevoegen.
Het bestand YoloBoundingBox.cs wordt geopend in de code-editor. Voeg de volgende
usinginstructie toe aan het begin van YoloBoundingBox.cs:using System.Drawing;Voeg net boven de bestaande klassedefinitie een nieuwe klassedefinitie toe genaamd
BoundingBoxDimensionsdie erft van deDimensionsBaseklasse om de dimensies van het desbetreffende begrenzingsvak te bevatten.public class BoundingBoxDimensions : DimensionsBase { }Verwijder de bestaande
YoloBoundingBoxklassedefinitie en voeg de volgende code voor deYoloBoundingBoxklasse toe aan het YoloBoundingBox.cs-bestand :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; } }YoloBoundingBoxheeft de volgende eigenschappen:-
Dimensionsbevat dimensies van de omsluitende doos. -
Labelbevat de klasse van het object dat in de omsluitende rechthoek is gedetecteerd. -
Confidencebevat het vertrouwen van de klasse. -
Rectbevat de rechthoekweergave van de afmetingen van het begrenzingsvak. -
BoxColorbevat 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 selecteerNieuw item>.
Selecteer in het dialoogvenster Nieuw item toevoegen de optie Klasse en wijzig het veld Naamin YoloOutputParser.cs. Selecteer vervolgens Toevoegen.
Het bestand YoloOutputParser.cs wordt geopend in de code-editor. Voeg de volgende
usinginstructies toe aan het begin van YoloOutputParser.cs:using System; using System.Collections.Generic; using System.Drawing; using System.Linq;Voeg binnen de bestaande
YoloOutputParserklassedefinitie een geneste klasse toe die de afmetingen van elk van de cellen in de afbeelding bevat. Voeg de volgende code toe voor deCellDimensionsklasse die wordt overgenomen van deDimensionsBaseklasse boven aan deYoloOutputParserklassedefinitie.class CellDimensions : DimensionsBase { }Voeg in de
YoloOutputParserklassedefinitie 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_COUNTis het aantal rijen in het raster waarin de afbeelding is onderverdeeld. -
COL_COUNTis het aantal kolommen in het raster waarin de afbeelding is onderverdeeld. -
CHANNEL_COUNTis het totale aantal waarden in één cel van het raster. -
BOXES_PER_CELLis het aantal begrenzingskaders in een cel, -
BOX_INFO_FEATURE_COUNTis het aantal functies in een vak (x,y,hoogte,breedte,betrouwbaarheid). -
CLASS_COUNTis het aantal klassevoorspellingen in elk begrenzingsvak. -
CELL_WIDTHis de breedte van één cel in het afbeeldingsraster. -
CELL_HEIGHTis de hoogte van één cel in het afbeeldingsraster. -
channelStrideis de beginpositie van de huidige cel in het raster.
Wanneer het model een voorspelling doet, ook wel scoren genoemd, wordt de
416px x 416pxinvoerafbeelding verdeeld in een raster van cellen met de grootte van13 x 13. Elke cel bevat.32px x 32pxBinnen elke cel zijn er 5 begrenzingsvakken die elk 5 kenmerken bevatten (x, y, breedte, hoogte, betrouwbaarheid). Bovendien bevat elke begrenzingsdoos de waarschijnlijkheid van elke klasse, waarvan er in dit geval 20 zijn. Daarom bevat elke cel 125 stukjes informatie (5 kenmerken + 20 klassenkansen).-
Maak een lijst met ankers hieronder channelStride voor alle vijf begrenzingskaders:
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 begrenzingskaders. 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 begrenzingskaders te voorspellen, wordt de verschuiving van de vooraf gedefinieerde dimensies berekend, waardoor minder berekeningen nodig zijn om het begrenzingskader te voorspellen. Deze ankerverhoudingen worden doorgaans berekend op basis van de gebruikte gegevensset. Omdat de gegevensset bekend is en de waarden vooraf zijn gecomputeerd, 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:
-
Sigmoidpast de sigmoid-functie toe die een getal tussen 0 en 1 uitvoert. -
Softmaxnormaliseert een invoervector in een waarschijnlijkheidsverdeling. -
GetOffsetwijst elementen in de eendimensionale modeluitvoer toe aan de bijbehorende positie in een125 x 13 x 13tensor. -
ExtractBoundingBoxesextraheert de dimensies van de omsluitende rechthoek uit de modeluitvoer met behulp van deGetOffsetmethode. -
GetConfidenceextraheert de betrouwbaarheidswaarde die aangeeft hoe zeker het model is dat het een object heeft gedetecteerd en deSigmoidfunctie gebruikt om het om te zetten in een percentage. -
MapBoundingBoxToCellgebruikt de afmetingen van het begrenzingsvak en wijst deze toe aan de desbetreffende cel in de afbeelding. -
ExtractClassesextraheert de klassevoorspellingen voor het begrenzingsvak uit de modeluitvoer met behulp van deGetOffsetmethode en verandert deze in een waarschijnlijkheidsverdeling met behulp van deSoftmaxmethode. -
GetTopResultselecteert de klasse in de lijst met voorspelde klassen met de hoogste waarschijnlijkheid. -
IntersectionOverUnionfilters overlappende begrenzingsvakjes met lagere kansen.
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, verwerk 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 betrouwbare begrenzingsvakken zijn geëxtraheerd uit de modeluitvoer, moet aanvullende filtering worden uitgevoerd om overlap in afbeeldingen te verwijderen. Voeg een methode toe die onder de FilterBoundingBoxes methode wordt aangeroepenParseOutputs:
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 iteratief over de begrenzingsvakken te gaan.
for (int i = 0; i < boxes.Count; i++)
{
}
Controleer in deze for-lus of het huidige begrenzingsvak kan worden verwerkt.
if (isActiveBoxes[i])
{
}
Als dat het geval is, voeg de omkaderingsvak toe aan de lijst met resultaten. Als de resultaten de opgegeven limiet voor te extraheren vakken overschrijden, verlaat dan de lus. 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 omkaderingen. Voeg de volgende code toe onder de selectievakjeslimiet.
for (var j = i + 1; j < boxes.Count; j++)
{
}
Net als het eerste vak, als het aangrenzende vak actief is of klaar is om te worden verwerkt, gebruikt u de methode IntersectionOverUnion 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, nagaan of er nog begrenzingsvakken over zijn die 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;
Geweldig! 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 het waarderingsproces. 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 selecteerNieuw item>.
Selecteer in het dialoogvenster Nieuw item toevoegen de optie Klasse en wijzig het veld Naamin OnnxModelScorer.cs. Selecteer vervolgens Toevoegen.
Het bestand OnnxModelScorer.cs wordt geopend in de code-editor. Voeg de volgende
usinginstructies 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
OnnxModelScorerklassedefinitie 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
OnnxModelScorerklasse 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
ImageNetSettingsom 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
TinyYoloModelSettingsvan 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
LoadModelmethode in uwOnnxModelScorerklas.private ITransformer LoadModel(string modelLocation) { }Voeg in de
LoadModelmethode 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
Fitmethode 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 legeIDataViewte gebruiken. Maak een nieuweIDataViewvoor 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.
-
LoadImageslaadt de afbeelding als bitmap. -
ResizeImagesschaalt de afbeelding opnieuw naar de opgegeven grootte (in dit geval416 x 416). -
ExtractPixelswijzigt de pixelweergave van de afbeelding van een bitmap in een numerieke vector. -
ApplyOnnxModellaadt het ONNX-model en gebruikt het om te scoren op de opgegeven gegevens.
Definieer uw pijplijn in de
LoadModelmethode onder dedatavariabele.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
Fitmethode 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 PredictDataUsingModel methode wordt aangeroepenLoadModel.
private IEnumerable<float[]> PredictDataUsingModel(IDataView testData, ITransformer model)
{
}
Voeg in de PredictDataUsingModelcode 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 daar! 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 output is verwerkt, dienen de begrenzende kaders op de afbeeldingen te worden getekend. Voeg hiervoor een methode toe die onder de DrawBoundingBox methode van GetAbsolutePath wordt aangeroepen.
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-loop om over elk van de begrenzingsvakken te itereren die door het model worden gedetecteerd.
foreach (var box in filteredBoundingBoxes)
{
}
Haal in de for-each-lus de afmetingen van de omsluitende box 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 binnen het desbetreffende begrenzingsvak evenals het vertrouwen.
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))
{
}
Pas in het using codeblok de instellingen van het Graphics object van de afbeelding aan.
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 runtime, voegt u een methode toe die onder de LogDetectedObjects methode in het DrawBoundingBox wordt aangeroepen 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!
Results
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 verwerkingsberichten, 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 begrenzingskaders 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 tutorial leerde je hoe je:
- 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.