Oktatóanyag: Objektumok észlelése ONNX használatával a ML.NET

Megtudhatja, hogyan használhat előre betanított ONNX-modellt ML.NET a képek objektumainak észleléséhez.

Az objektumészlelési modell alapoktól való betanításához több millió paramétert, nagy mennyiségű címkézett betanítási adatot és nagy mennyiségű számítási erőforrást (több száz GPU-órát) kell beállítani. Az előre betanított modell használatával parancsikont adhat a betanítási folyamatnak.

Ebben az oktatóanyagban az alábbiakkal fog megismerkedni:

  • A probléma ismertetése
  • Ismerje meg, mi az ONNX, és hogyan működik ML.NET
  • A modell megismerése
  • Az előre betanított modell újrafelhasználása
  • Betöltött modellel rendelkező objektumok észlelése

Pre-requisites

ONNX objektumészlelési minta áttekintése

Ez a minta egy .NET core konzolalkalmazást hoz létre, amely egy előre betanított mélytanulási ONNX-modellel észleli a rendszerképen belüli objektumokat. A minta kódja a GitHub dotnet/machinelearning-samples adattárában található.

Mi az objektumészlelés?

Az objektumészlelés számítógépes látási probléma. Bár szorosan kapcsolódik a képbesoroláshoz, az objektumészlelés részletesebb léptékben végzi el a képbesorolást. Az objektumészlelés egyaránt megkeresi és kategorizálja az entitásokat a képeken belül. Az objektumészlelési modelleket általában mélytanulási és neurális hálózatokkal tanítják be. További információt a mély tanulás és a gépi tanulás című témakörben talál.

Objektumészlelést akkor használjon, ha a képek több különböző típusú objektumot tartalmaznak.

Screenshots showing Image Classification versus Object Classification.

Az objektumészlelés néhány használati esete:

  • Önvezető autók
  • Robotika
  • Arcfelismerés
  • Munkahelyi Széf ty
  • Objektumszámlálás
  • Tevékenységfelismerés

Mélytanulási modell kiválasztása

A mély tanulás a gépi tanulás egyik részhalmaza. A mélytanulási modellek betanítása érdekében nagy mennyiségű adatra van szükség. Az adatok mintáit rétegek sorozata képviseli. Az adatokban lévő kapcsolatok a súlyokat tartalmazó rétegek közötti kapcsolatokként vannak kódolva. Minél nagyobb a súly, annál erősebb a kapcsolat. A rétegek és kapcsolatok sorozatát együttesen mesterséges neurális hálózatoknak nevezzük. Minél több réteg van egy hálózatban, annál "mélyebb", így mély neurális hálózat.

A neurális hálózatoknak különböző típusai vannak, a leggyakoribbak a többrétegű perceptron (MLP), a konvolúciós neurális hálózat (CNN) és a Recurrent Neural Network (RNN). A legalapvetőbb az MLP, amely bemeneteket képez le kimenetek halmazához. Ez a neurális hálózat akkor jó, ha az adatok nem rendelkeznek térbeli vagy időösszetevővel. A CNN konvolúciós rétegeket használ az adatokban található térbeli információk feldolgozásához. A CNN-ek esetében jó példa a képfeldolgozás egy funkció jelenlétének észlelésére egy kép egy régiójában (például van orra a kép közepén?). Végül az RNN-k lehetővé teszik az állapot vagy a memória megőrzését bemenetként. Az RNN-eket idősorozat-elemzéshez használják, ahol fontos az események sorrendje és kontextusa.

A modell megismerése

Az objektumészlelés képfeldolgozási feladat. Ezért a probléma megoldására betanított mélytanulási modellek többsége CNN-eket jelent. Az oktatóanyagban használt modell a Tiny YOLOv2 modell, amely a tanulmányban leírt YOLOv2 modell kompaktabb verziója: "YOLO9000: Better, Faster, Stronger" by Redmon and Farhadi. Az apró YOLOv2 a Pascal VOC adatkészleten van betanítve, és 15 rétegből áll, amelyek 20 különböző objektumosztály előrejelzésére képesek. Mivel a Tiny YOLOv2 az eredeti YOLOv2 modell sűrített verziója, a sebesség és a pontosság közötti kompromisszum jön létre. A modellt alkotó különböző rétegek a Netronhoz hasonló eszközökkel jeleníthetők meg. A modell vizsgálata a neurális hálózatot alkotó összes réteg közötti kapcsolatok leképezését eredményezné, ahol minden réteg tartalmazza a réteg nevét és a megfelelő bemenet /kimenet dimenzióit. A modell bemeneteinek és kimeneteinek leírására használt adatstruktúrákat tenzoroknak nevezzük. A Tensorok olyan tárolókként is felfoghatók, amelyek N dimenziókban tárolják az adatokat. A Tiny YOLOv2 esetében a bemeneti réteg neve, image és a dimenziók 3 x 416 x 416tenzorára számít. A kimeneti réteg neve a grid dimenziók 125 x 13 x 13kimeneti tenzorát hozza létre.

Input layer being split into hidden layers, then output layer

A YOLO-modell egy képet 3(RGB) x 416px x 416pxkészít. A modell ezt a bemenetet használja, és átadja a különböző rétegeken a kimenet létrehozásához. A kimenet egy rácsra 13 x 13 osztja a bemeneti képet, amelyben a rács minden celláját értékek alkotják 125 .

Mi az AZ ONNX-modell?

Az Open Neural Network Exchange (ONNX) az AI-modellek nyílt forráskód formátuma. Az ONNX támogatja a keretrendszerek közötti interoperabilitást. Ez azt jelenti, hogy betaníthat egy modellt az olyan népszerű gépi tanulási keretrendszerek egyikében, mint a PyTorch, átalakíthatja ONNX formátumba, és felhasználhatja az ONNX-modellt egy másik keretrendszerben, például ML.NET. További információért látogasson el az ONNX webhelyére.

Diagram of ONNX supported formats being used.

Az előre betanított Tiny YOLOv2 modell ONNX formátumban van tárolva, amely szerializált módon jeleníti meg az adott rétegek rétegeit és tanult mintáit. A ML.NET az ONNX és a ImageAnalyticsOnnxTransformer NuGet csomagokkal való együttműködés érhető el. A ImageAnalytics csomag olyan átalakítások sorozatát tartalmazza, amelyek egy képet vesznek fel, és numerikus értékekre kódolják, amelyek az előrejelzési vagy betanítási folyamat bemeneteként használhatók. A OnnxTransformer csomag az ONNX runtime használatával tölt be egy ONNX-modellt, és a megadott bemenet alapján előrejelzéseket készít.

Data flow of ONNX file into the ONNX Runtime.

A .NET-konzolprojekt beállítása

Most, hogy általános ismereteket szerezhet az ONNX-ről és a Tiny YOLOv2 működéséről, ideje felépíteni az alkalmazást.

Konzolalkalmazás létrehozása

  1. Hozzon létre egy "ObjectDetection" nevű C# -konzolalkalmazást . Kattintson a Tovább gombra.

  2. Válassza a .NET 6-ot a használni kívánt keretrendszerként. Kattintson a Létrehozás gombra.

  3. Telepítse a Microsoft.ML NuGet-csomagot:

    Megjegyzés:

    Ez a minta az említett NuGet-csomagok legújabb stabil verzióját használja, hacsak másként nem rendelkezik.

    • A Megoldáskezelő kattintson a jobb gombbal a projektre, és válassza a NuGet-csomagok kezelése lehetőséget.
    • Válassza a "nuget.org" lehetőséget a Csomag forrásaként, válassza a Tallózás lapot, keresse meg a Microsoft.ML.
    • Válassza a Telepítés gombot.
    • Kattintson az OK gombra a Változások előnézete párbeszédpanelen, majd válassza az Elfogadom gombot a Licenc elfogadása párbeszédpanelen, ha elfogadja a felsorolt csomagok licencfeltételét.
    • Ismételje meg ezeket a lépéseket a Microsoft.Windows.Compatibility, a Microsoft.ML.ImageAnalytics, a Microsoft.ML.OnnxTransformer és a Microsoft.ML.OnnxRuntime esetében.

Az adatok és az előre betanított modell előkészítése

  1. Töltse le a project assets könyvtár zip-fájl és unzip.

  2. Másolja a könyvtárat az assetsObjectDetection projektkönyvtárába. Ez a könyvtár és alkönyvtárai tartalmazzák az oktatóanyaghoz szükséges képfájlokat (kivéve a Tiny YOLOv2 modellt, amelyet a következő lépésben letöltünk és hozzáadunk).

  3. Töltse le a Tiny YOLOv2 modellt az ONNX Model Zoo-ból.

  4. Másolja a fájlt az model.onnxObjectDetection projektkönyvtárába assets\Model , és nevezze át a fájlra TinyYolo2_model.onnx. Ez a könyvtár az oktatóanyaghoz szükséges modellt tartalmazza.

  5. A Megoldáskezelő kattintson a jobb gombbal az eszközkönyvtárban és az alkönyvtárakban lévő fájlokra, és válassza a Tulajdonságok lehetőséget. A Speciális területen módosítsa a Másolás kimeneti könyvtárra értékét másolásra, ha újabb.

Osztályok létrehozása és útvonalak definiálása

Nyissa meg a Program.cs fájlt, és adja hozzá a következő további using utasításokat a fájl tetejére:

using System.Drawing;
using System.Drawing.Drawing2D;
using ObjectDetection.YoloParser;
using ObjectDetection.DataStructures;
using ObjectDetection;
using Microsoft.ML;

Ezután határozza meg a különböző objektumok elérési útját.

  1. Először hozza létre a metódust GetAbsolutePath a Program.cs fájl alján.

    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;
    }
    
  2. Ezután a felhasználói utasítások alatt hozzon létre mezőket az eszközök helyének tárolásához.

    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");
    

Adjon hozzá egy új könyvtárat a projekthez a bemeneti adatok és előrejelzési osztályok tárolásához.

A Megoldáskezelő kattintson a jobb gombbal a projektre, majd válassza az Új mappa hozzáadása>lehetőséget. Amikor az új mappa megjelenik a Megoldáskezelő, nevezze el "DataStructures"-nek.

Hozza létre a bemeneti adatosztályt az újonnan létrehozott DataStructures könyvtárban.

  1. A Megoldáskezelő kattintson a jobb gombbal a DataStructures könyvtárra, majd válassza az Új elem hozzáadása>lehetőséget.

  2. Az Új elem hozzáadása párbeszédpanelen válassza az Osztály lehetőséget, és módosítsa a Név mezőt ImageNetData.cs-ra. Ezután válassza a Hozzáadás gombot.

    Megnyílik az ImageNetData.cs fájl a kódszerkesztőben. Adja hozzá a következő using utasítást az ImageNetData.cs elejéhez:

    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using Microsoft.ML.Data;
    

    Távolítsa el a meglévő osztálydefiníciót, és adja hozzá az ImageNetData osztály következő kódját az ImageNetData.cs fájlhoz:

    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 a bemeneti kép adatosztálya, és a következő String mezőket tartalmazza:

    • ImagePath a rendszerkép tárolási útvonalát tartalmazza.
    • Label a fájl nevét tartalmazza.

    Emellett egy metódust ReadFromFile is tartalmaz, ImageNetData amely több, a imageFolder megadott elérési úton tárolt képfájlt tölt be, és objektumgyűjteményként ImageNetData adja vissza őket.

Hozza létre az előrejelzési osztályt a DataStructures könyvtárban.

  1. A Megoldáskezelő kattintson a jobb gombbal a DataStructures könyvtárra, majd válassza az Új elem hozzáadása>lehetőséget.

  2. Az Új elem hozzáadása párbeszédpanelen válassza az Osztály lehetőséget, és módosítsa a Név mezőt ImageNetPrediction.cs értékre. Ezután válassza a Hozzáadás gombot.

    Megnyílik az ImageNetPrediction.cs fájl a kódszerkesztőben. Adja hozzá a következő using utasítást az ImageNetPrediction.cs elejéhez:

    using Microsoft.ML.Data;
    

    Távolítsa el a meglévő osztálydefiníciót, és adja hozzá az ImageNetPrediction osztály következő kódját az ImageNetPrediction.cs fájlhoz:

    public class ImageNetPrediction
    {
        [ColumnName("grid")]
        public float[] PredictedLabels;
    }
    

    ImageNetPrediction az előrejelzési adatosztály, és a következő float[] mezővel rendelkezik:

    • PredictedLabels a képen észlelt minden egyes határolókeret dimenzióit, objektumértékét és osztály valószínűségét tartalmazza.

Változók inicializálása

Az MLContext osztály minden ML.NET művelet kiindulópontja, és az inicializálás mlContext új ML.NET környezetet hoz létre, amely megosztható a modelllétrehozási munkafolyamat-objektumok között. Ez fogalmilag hasonló az Entity Frameworkhez DBContext .

Inicializálja a mlContext változót egy új példánysal MLContext úgy, hogy hozzáadja a következő sort a outputFolder mező alá.

MLContext mlContext = new MLContext();

Elemző létrehozása a folyamat utáni modellkimenetekhez

A modell egy képet egy 13 x 13 rácsba szegmentált, ahol az egyes rácscellák találhatók 32px x 32px. Minden rácscella 5 lehetséges objektum határolókeretet tartalmaz. A határolókeret 25 elemből áll:

Grid sample on the left, and Bounding Box sample on the right

  • x a határolókeret középpontjának x pozíciója a hozzá társított rácscellához viszonyítva.
  • y a határolókeret középpontjának y pozíciója a hozzá társított rácscellához viszonyítva.
  • w a határolókeret szélessége.
  • h a határolókeret magassága.
  • o az objektumnak a határolókereten belüli megbízhatósági értéke, más néven objektumérték.
  • p1-p20 osztály-valószínűségek a modell által előrejelzett 20 osztály mindegyikéhez.

Összesen az 5 határolókeretet leíró 25 elem alkotja az egyes rácscellákban található 125 elemet.

Az előre betanított ONNX-modell által generált kimenet egy úszó hosszúságú 21125tömb, amely egy dimenziókkal 125 x 13 x 13rendelkező tenzor elemeit jelöli . Ahhoz, hogy a modell által generált előrejelzéseket tenzorlá alakíthassa, szükség van némi utófeldolgozási munkára. Ehhez hozzon létre egy osztálykészletet a kimenet elemzéséhez.

Adjon hozzá egy új könyvtárat a projekthez az elemzőosztályok halmazának rendszerezéséhez.

  1. A Megoldáskezelő kattintson a jobb gombbal a projektre, majd válassza az Új mappa hozzáadása>lehetőséget. Amikor az új mappa megjelenik a Megoldáskezelő, nevezze el "YoloParser"-nek.

Határolókeretek és dimenziók létrehozása

A modell által megadott adatkimenet a képen belüli objektumok határolódobozainak koordinátáit és dimenzióit tartalmazza. Hozzon létre egy alaposztályt a dimenziókhoz.

  1. A Megoldáskezelő kattintson a jobb gombbal a YoloParser könyvtárra, majd válassza az Új elem hozzáadása>lehetőséget.

  2. Az Új elem hozzáadása párbeszédpanelen válassza az Osztály lehetőséget, és módosítsa a Név mezőt DimensionsBase.cs-ra. Ezután válassza a Hozzáadás gombot.

    A DimensionsBase.cs fájl megnyílik a kódszerkesztőben. Távolítsa el az összes using utasítást és a meglévő osztálydefiníciót.

    Adja hozzá az DimensionsBase osztály következő kódját a DimensionsBase.cs fájlhoz:

    public class DimensionsBase
    {
        public float X { get; set; }
        public float Y { get; set; }
        public float Height { get; set; }
        public float Width { get; set; }
    }
    

    DimensionsBase a következő float tulajdonságokkal rendelkezik:

    • X az objektum pozícióját tartalmazza az x tengely mentén.
    • Y az objektum pozícióját tartalmazza az y tengely mentén.
    • Height az objektum magasságát tartalmazza.
    • Width az objektum szélességét tartalmazza.

Ezután hozzon létre egy osztályt a határolókeretekhez.

  1. A Megoldáskezelő kattintson a jobb gombbal a YoloParser könyvtárra, majd válassza az Új elem hozzáadása>lehetőséget.

  2. Az Új elem hozzáadása párbeszédpanelen válassza az Osztály lehetőséget, és módosítsa a Név mezőt YoloBoundingBox.cs-ra. Ezután válassza a Hozzáadás gombot.

    Megnyílik a YoloBoundingBox.cs fájl a kódszerkesztőben. Adja hozzá a következő using utasítást a YoloBoundingBox.cs tetejére:

    using System.Drawing;
    

    A meglévő osztálydefiníció felett adjon hozzá egy új osztálydefiníciót BoundingBoxDimensions , amely örökli az osztálytól a DimensionsBase megfelelő határolókeret dimenzióit.

    public class BoundingBoxDimensions : DimensionsBase { }
    

    Távolítsa el a meglévő YoloBoundingBox osztálydefiníciót, és adja hozzá az YoloBoundingBox osztály következő kódját a YoloBoundingBox.cs fájlhoz:

    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 a következő tulajdonságokkal rendelkezik:

    • Dimensions a határolókeret méreteit tartalmazza.
    • Label A határolókereten belül észlelt objektumosztályt tartalmazza.
    • Confidence az osztály megbízhatóságát tartalmazza.
    • Rect a határolókeret méreteinek téglalapos ábrázolását tartalmazza.
    • BoxColor a kép rajzolásához használt megfelelő osztályhoz társított színt tartalmazza.

Az elemző létrehozása

Most, hogy létrejöttek a dimenziók és a határolókeretek osztályai, ideje létrehozni az elemzőt.

  1. A Megoldáskezelő kattintson a jobb gombbal a YoloParser könyvtárra, majd válassza az Új elem hozzáadása>lehetőséget.

  2. Az Új elem hozzáadása párbeszédpanelen válassza az Osztály lehetőséget, és módosítsa a Név mezőt YoloOutputParser.cs-ra. Ezután válassza a Hozzáadás gombot.

    Megnyílik a YoloOutputParser.cs fájl a kódszerkesztőben. Adja hozzá a következő using utasításokat a YoloOutputParser.cs elejéhez:

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    

    A meglévő YoloOutputParser osztálydefiníción belül adjon hozzá egy beágyazott osztályt, amely a kép egyes celláinak dimenzióit tartalmazza. Adja hozzá a következő kódot az CellDimensions osztály definíciójának YoloOutputParser tetején lévő osztálytól DimensionsBase öröklő osztályhoz.

    class CellDimensions : DimensionsBase { }
    
  3. YoloOutputParser Az osztálydefiníción belül adja hozzá a következő állandókat és mezőket.

    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 a rács azon sorainak száma, amelybe a rendszerkép fel van osztva.
    • COL_COUNT a rács oszlopainak száma, amelybe a rendszerkép fel van osztva.
    • CHANNEL_COUNT A rács egy cellájában található értékek teljes száma.
    • BOXES_PER_CELL a cellában lévő határolókeretek száma,
    • BOX_INFO_FEATURE_COUNT a mezőben található funkciók száma (x,y,magasság,szélesség,megbízhatóság).
    • CLASS_COUNT az egyes határolókeretekben található osztály-előrejelzések száma.
    • CELL_WIDTH a képrács egy cellájának szélessége.
    • CELL_HEIGHT a képrács egyik cellájának magassága.
    • channelStride az aktuális cella kezdőpozíciója a rácsban.

    Amikor a modell előrejelzést készít, más néven pontozást, a 416px x 416px bemeneti képet egy olyan cellarácsra osztja, amelynek mérete 13 x 13. Minden cella tartalmaz 32px x 32px. Minden cellán belül 5 határolókeret található, amelyek mindegyike 5 funkciót tartalmaz (x, y, szélesség, magasság, megbízhatóság). Ezenkívül minden egyes határolókeret tartalmazza az osztályok valószínűségét, ami ebben az esetben 20. Ezért minden cella 125 információt tartalmaz (5 jellemző + 20 osztály valószínűsége).

Hozzon létre egy listát az alábbi channelStride horgonyokról mind az 5 határolókerethez:

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
};

A horgonyok a határolókeretek előre meghatározott magassági és szélességi arányai. A modell által észlelt objektumok vagy osztályok többsége hasonló arányokkal rendelkezik. Ez hasznos a határolókeretek létrehozásakor. A határolókeretek előrejelzése helyett a rendszer kiszámítja az előre definiált dimenziókból származó eltolást, így csökkenti a határolókeret előrejelzéséhez szükséges számítást. Ezek a horgonyarányok kiszámítása általában a használt adatkészlet alapján történik. Ebben az esetben, mivel az adathalmaz ismert, és az értékek előre ki lettek számítva, a horgonyok kódoltak lehetnek.

Ezután adja meg a modell által előrejelzett címkéket vagy osztályokat. Ez a modell 20 osztályt jelez előre, amely az eredeti YOLOv2 modell által előrejelzett osztályok teljes számának részhalmaza.

Adja hozzá a címkék listáját a anchorskövetkező alá: .

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"
};

Mindegyik osztályhoz vannak színek társítva. Rendelje hozzá az osztályszíneket a következőhöz 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
};

Segédfüggvények létrehozása

Az utófeldolgozási fázisban több lépés is szerepel. Ennek érdekében számos segítő módszert lehet alkalmazni.

Az elemző által használt segédmetódusok a következők:

  • Sigmoid a szigmoid függvényt alkalmazza, amely 0 és 1 közötti számot ad ki.
  • Softmax a bemeneti vektort valószínűségeloszlássá normalizálja.
  • GetOffset az egydimenziós modell kimenetének elemeit a tenzor megfelelő pozíciójára 125 x 13 x 13 képezi le.
  • ExtractBoundingBoxes a modell kimenetéből kinyeri a határolókeret dimenzióit a GetOffset metódus használatával.
  • GetConfidence Kinyeri a megbízhatósági értéket, amely azt jelzi, hogy a modell mennyire biztos abban, hogy észlelt egy objektumot, és a Sigmoid függvény használatával százalékot ad.
  • MapBoundingBoxToCell a határolókeret méreteit használja, és a kép megfelelő cellájába képezi le őket.
  • ExtractClasses kinyeri a határolókeret osztály-előrejelzéseit a modell kimenetéből a GetOffset metódus használatával, és a metódus használatával valószínűségeloszlássá alakítja őket Softmax .
  • GetTopResult A legnagyobb valószínűséggel rendelkező előrejelzett osztályok listájából választja ki az osztályt.
  • IntersectionOverUnion kisebb valószínűségű, átfedésben lévő határolókereteket szűr.

Adja hozzá a kódot az összes segítő metódushoz a lista classColorsalatt.

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);
}

Miután definiálta az összes segédmetó módszert, ideje őket használni a modell kimenetének feldolgozásához.

IntersectionOverUnion A metódus alatt hozza létre a metódust a ParseOutputs modell által létrehozott kimenet feldolgozásához.

public IList<YoloBoundingBox> ParseOutputs(float[] yoloModelOutputs, float threshold = .3F)
{

}

Hozzon létre egy listát a határolókeretek tárolásához és a ParseOutputs változók metóduson belüli definiálásához.

var boxes = new List<YoloBoundingBox>();

Minden kép cellarácsra 13 x 13 van osztva. Minden cella öt határolókeretet tartalmaz. boxes A változó alatt adjon hozzá kódot az egyes cellák összes dobozának feldolgozásához.

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++)
        {

        }
    }
}

A legbelső hurokban számítsa ki az aktuális mező kezdőpozícióját az egydimenziós modell kimenetén belül.

var channel = (box * (CLASS_COUNT + BOX_INFO_FEATURE_COUNT));

Közvetlenül alatta, használja a ExtractBoundingBoxDimensions metódust az aktuális határolókeret méreteinek lekéréséhez.

BoundingBoxDimensions boundingBoxDimensions = ExtractBoundingBoxDimensions(yoloModelOutputs, row, column, channel);

Ezután használja a metódust GetConfidence az aktuális határolókeret megbízhatóságának lekéréséhez.

float confidence = GetConfidence(yoloModelOutputs, row, column, channel);

Ezt követően a MapBoundingBoxToCell metódussal megfelelteti az aktuális határolókeretet a feldolgozandó aktuális cellának.

CellDimensions mappedBoundingBox = MapBoundingBoxToCell(row, column, box, boundingBoxDimensions);

A további feldolgozás előtt ellenőrizze, hogy a megbízhatósági érték nagyobb-e a megadott küszöbértéknél. Ha nem, dolgozza fel a következő határolókeretet.

if (confidence < threshold)
    continue;

Ellenkező esetben folytassa a kimenet feldolgozását. A következő lépés az aktuális határolókeret előrejelzett osztályainak valószínűségeloszlása a ExtractClasses metódus használatával.

float[] predictedClasses = ExtractClasses(yoloModelOutputs, row, column, channel);

Ezután a GetTopResult metódussal lekérheti annak az osztálynak az értékét és indexét, amelynek legnagyobb a valószínűsége az aktuális mezőben, és kiszámítja a pontszámát.

var (topResultIndex, topResultScore) = GetTopResult(predictedClasses);
var topScore = topResultScore * confidence;

Ezzel ismét csak azokat a topScore határolókereteket tartsa meg, amelyek túllépik a megadott küszöbértéket.

if (topScore < threshold)
    continue;

Végül, ha az aktuális határolókeret túllépi a küszöbértéket, hozzon létre egy új BoundingBox objektumot, és adja hozzá a boxes listához.

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]
});

A kép összes cellájának feldolgozása után adja vissza a boxes listát. Adja hozzá a következő visszatérési utasítást a metódusban a legkülönlegesebb for-loop ParseOutputs alá.

return boxes;

Átfedésben lévő mezők szűrése

Most, hogy az összes nagyon magabiztos határolókeret ki lett nyerve a modell kimenetéből, további szűrést kell végezni az átfedésben lévő képek eltávolításához. Adjon hozzá egy metódus alatti metódust FilterBoundingBoxesParseOutputs :

public IList<YoloBoundingBox> FilterBoundingBoxes(IList<YoloBoundingBox> boxes, int limit, float threshold)
{

}

A metóduson FilterBoundingBoxes belül először hozzon létre egy olyan tömböt, amely megegyezik az észlelt dobozok méretével, és az összes tárolóhelyet aktívként vagy feldolgozásra készként jelöli meg.

var activeCount = boxes.Count;
var isActiveBoxes = new bool[boxes.Count];

for (int i = 0; i < isActiveBoxes.Length; i++)
    isActiveBoxes[i] = true;

Ezután rendezze a határolókereteket tartalmazó listát csökkenő sorrendbe a megbízhatóság alapján.

var sortedBoxes = boxes.Select((b, i) => new { Box = b, Index = i })
                    .OrderByDescending(b => b.Box.Confidence)
                    .ToList();

Ezután hozzon létre egy listát a szűrt eredmények tárolásához.

var results = new List<YoloBoundingBox>();

Kezdje el feldolgozni az egyes határolókereteket a határolókeretek iterálásával.

for (int i = 0; i < boxes.Count; i++)
{

}

Ebben a for-loopban ellenőrizze, hogy az aktuális határolókeret feldolgozható-e.

if (isActiveBoxes[i])
{

}

Ha igen, adja hozzá a határolókeretet az eredmények listájához. Ha az eredmények túllépik a kinyerni kívánt mezők megadott korlátját, bontsa ki a hurkot. Adja hozzá a következő kódot az if-utasításban.

var boxA = sortedBoxes[i].Box;
results.Add(boxA);

if (results.Count >= limit)
    break;

Ellenkező esetben tekintse meg a szomszédos határolókereteket. Adja hozzá a következő kódot a jelölőnégyzetkorlát alá.

for (var j = i + 1; j < boxes.Count; j++)
{

}

Az első mezőhöz hasonlóan, ha a szomszédos mező aktív vagy készen áll a feldolgozásra, a IntersectionOverUnion módszerrel ellenőrizheti, hogy az első és a második mező túllépi-e a megadott küszöbértéket. Adja hozzá a következő kódot a legbelső for-loophoz.

if (isActiveBoxes[j])
{
    var boxB = sortedBoxes[j].Box;

    if (IntersectionOverUnion(boxA.Rect, boxB.Rect) > threshold)
    {
        isActiveBoxes[j] = false;
        activeCount--;

        if (activeCount <= 0)
            break;
    }
}

A szomszédos határolókereteket ellenőrző legbelső for-hurokon kívül ellenőrizze, hogy vannak-e még feldolgozandó határolókeretek. Ha nem, bontsa ki a külső for-loop.

if (activeCount <= 0)
    break;

Végül a metódus kezdeti for-loopon FilterBoundingBoxes kívül adja vissza az eredményeket:

return results;

Great! Most itt az ideje, hogy ezt a kódot a pontozási modellel együtt használja.

A modell használata pontozáshoz

Az utófeldolgozáshoz hasonlóan a pontozási lépésekben is van néhány lépés. Ehhez adjon hozzá egy osztályt, amely tartalmazza a pontozási logikát a projektben.

  1. A Megoldáskezelő kattintson a jobb gombbal a projektre, majd válassza az Új elem hozzáadása>lehetőséget.

  2. Az Új elem hozzáadása párbeszédpanelen válassza az Osztály lehetőséget, és módosítsa a Név mezőt OnnxModelScorer.cs fájlra. Ezután válassza a Hozzáadás gombot.

    Megnyílik az OnnxModelScorer.cs fájl a kódszerkesztőben. Adja hozzá a következő using utasításokat az OnnxModelScorer.cs tetejére:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.ML;
    using Microsoft.ML.Data;
    using ObjectDetection.DataStructures;
    using ObjectDetection.YoloParser;
    

    OnnxModelScorer Az osztálydefiníción belül adja hozzá a következő változókat.

    private readonly string imagesFolder;
    private readonly string modelLocation;
    private readonly MLContext mlContext;
    
    private IList<YoloBoundingBox> _boundingBoxes = new List<YoloBoundingBox>();
    

    Közvetlenül alatta hozzon létre egy konstruktort az OnnxModelScorer osztályhoz, amely inicializálja a korábban definiált változókat.

    public OnnxModelScorer(string imagesFolder, string modelLocation, MLContext mlContext)
    {
        this.imagesFolder = imagesFolder;
        this.modelLocation = modelLocation;
        this.mlContext = mlContext;
    }
    

    Miután létrehozta a konstruktort, definiáljon néhány szerkezetet, amelyek a rendszerképhez és a modell beállításaihoz kapcsolódó változókat tartalmaznak. Hozzon létre egy szerkezetet ImageNetSettings , amely a modell bemeneteként várt magasságot és szélességet tartalmazza.

    public struct ImageNetSettings
    {
        public const int imageHeight = 416;
        public const int imageWidth = 416;
    }
    

    Ezután hozzon létre egy másik, a TinyYoloModelSettings modell bemeneti és kimeneti rétegeinek nevét tartalmazó szerkezetet. A modell bemeneti és kimeneti rétegeinek nevének megjelenítéséhez használhat egy olyan eszközt, mint a Netron.

    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";
    }
    

    Ezután hozza létre a pontozáshoz használt módszerek első készletét. Hozza létre a metódust LoadModel az OnnxModelScorer osztályon belül.

    private ITransformer LoadModel(string modelLocation)
    {
    
    }
    

    A metóduson LoadModel belül adja hozzá a következő kódot a naplózáshoz.

    Console.WriteLine("Read model");
    Console.WriteLine($"Model location: {modelLocation}");
    Console.WriteLine($"Default parameters: image size=({ImageNetSettings.imageWidth},{ImageNetSettings.imageHeight})");
    

    ML.NET folyamatoknak ismernie kell a metódus meghívásakor Fit működő adatsémát. Ebben az esetben a rendszer a betanításhoz hasonló folyamatot használ. Mivel azonban nem történik tényleges betanítás, elfogadható IDataViewüres . Hozzon létre egy újat IDataView a folyamathoz egy üres listából.

    var data = mlContext.Data.LoadFromEnumerable(new List<ImageNetData>());
    

    Alatta definiálja a folyamatot. A folyamat négy átalakításból áll.

    • LoadImages betölti a képet bitképként.
    • ResizeImages a rendszerképet a megadott méretre (ebben az esetben 416 x 416) skálázhatja újra.
    • ExtractPixels bitképről numerikus vektorra módosítja a kép képpontos ábrázolását.
    • ApplyOnnxModel betölti az ONNX-modellt, és a megadott adatok pontszámára használja.

    Definiálja a folyamatot a LoadModel változó alatti data metódusban.

    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 }));
    

    Itt az ideje, hogy példányosítsuk a modellt a pontozáshoz. Hívja meg a metódust Fit a folyamaton, és adja vissza további feldolgozás céljából.

    var model = pipeline.Fit(data);
    
    return model;
    

Miután betöltötte a modellt, az előrejelzések készítésére is használható. A folyamat megkönnyítése érdekében hozzon létre egy metódust PredictDataUsingModel a LoadModel metódus alatt.

private IEnumerable<float[]> PredictDataUsingModel(IDataView testData, ITransformer model)
{

}

Adja hozzá a PredictDataUsingModelkövetkező kódot a naplózáshoz.

Console.WriteLine($"Images location: {imagesFolder}");
Console.WriteLine("");
Console.WriteLine("=====Identify the objects in the images=====");
Console.WriteLine("");

Ezután használja a metódust Transform az adatok pontozására.

IDataView scoredData = model.Transform(testData);

Nyerje ki az előrejelzett valószínűségeket, és adja vissza őket további feldolgozás céljából.

IEnumerable<float[]> probabilities = scoredData.GetColumn<float[]>(TinyYoloModelSettings.ModelOutput);

return probabilities;

Most, hogy mindkét lépés be van állítva, kombinálja őket egyetlen módszerrel. PredictDataUsingModel A metódus alatt adjon hozzá egy új, úgynevezett metódustScore.

public IEnumerable<float[]> Score(IDataView data)
{
    var model = LoadModel(modelLocation);

    return PredictDataUsingModel(data, model);
}

Majdnem kész! Most itt az ideje, hogy mindent használni.

Objektumok észlelése

Most, hogy az összes beállítás befejeződött, ideje észlelni néhány objektumot.

Modellkimenetek pontszáma és elemzése

A változó létrehozása mlContext alatt adjon hozzá egy try-catch utasítást.

try
{

}
catch (Exception ex)
{
    Console.WriteLine(ex.ToString());
}

A blokkon try belül kezdje el implementálni az objektumészlelési logikát. Először töltse be az adatokat egy IDataView.

IEnumerable<ImageNetData> images = ImageNetData.ReadFromFile(imagesFolder);
IDataView imageDataView = mlContext.Data.LoadFromEnumerable(images);

Ezután hozzon létre egy példányt OnnxModelScorer , és használja a betöltött adatok pontozásához.

// Create instance of model scorer
var modelScorer = new OnnxModelScorer(imagesFolder, modelFilePath, mlContext);

// Use model to score data
IEnumerable<float[]> probabilities = modelScorer.Score(imageDataView);

Itt az idő az utófeldolgozási lépésre. Hozzon létre egy példányt YoloOutputParser , és használja a modell kimenetének feldolgozásához.

YoloOutputParser parser = new YoloOutputParser();

var boundingBoxes =
    probabilities
    .Select(probability => parser.ParseOutputs(probability))
    .Select(boxes => parser.FilterBoundingBoxes(boxes, 5, .5F));

A modellkimenet feldolgozása után ideje megrajzolni a határolókereteket a képeken.

Előrejelzések megjelenítése

Miután a modell pontozza a képeket, és a kimenetek feldolgozásra kerültek, a határolókereteket a képre kell rajzolni. Ehhez adjon hozzá egy metódust DrawBoundingBox a GetAbsolutePath Program.cs metódus alatt.

void DrawBoundingBox(string inputImageLocation, string outputImageLocation, string imageName, IList<YoloBoundingBox> filteredBoundingBoxes)
{

}

Először töltse be a képet, és kérje le a magassági és szélességi méreteket a DrawBoundingBox metódusban.

Image image = Image.FromFile(Path.Combine(inputImageLocation, imageName));

var originalImageHeight = image.Height;
var originalImageWidth = image.Width;

Ezután hozzon létre egy minden egyes ciklushoz egy-egy ismétlést a modell által észlelt minden egyes határolókeret felett.

foreach (var box in filteredBoundingBoxes)
{

}

Az egyes hurkokon belül szerezze be a határolókeret méreteit.

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);

Mivel a határolókeret méretei megfelelnek a modell bemenetének 416 x 416, skálázza a határolókeret méreteit a kép tényleges méretének megfelelően.

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;

Ezután definiáljon egy sablont az egyes határolókeretek fölött megjelenő szöveghez. A szöveg tartalmazza az objektum osztályát a megfelelő határolókereten belül, valamint a megbízhatóságot.

string text = $"{box.Label} ({(box.Confidence * 100).ToString("0")}%)";

A kép rajzolásához konvertálja objektummá Graphics .

using (Graphics thumbnailGraphic = Graphics.FromImage(image))
{

}

using A kódblokkon belül hangolja be a grafikus Graphics objektum beállításait.

thumbnailGraphic.CompositingQuality = CompositingQuality.HighQuality;
thumbnailGraphic.SmoothingMode = SmoothingMode.HighQuality;
thumbnailGraphic.InterpolationMode = InterpolationMode.HighQualityBicubic;

Alatta adja meg a szöveg és a határolókeret betűtípus- és színbeállítását.

// 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);

Hozzon létre és töltsön ki egy téglalapot a határolókeret felett, hogy a szöveg a metódus használatával szerepeljen.FillRectangle Ez segít a szöveg kontrasztosabbá tételében és az olvashatóság javításában.

thumbnailGraphic.FillRectangle(colorBrush, (int)x, (int)(y - size.Height - 1), (int)size.Width, (int)size.Height);

Ezután rajzolja meg a szöveget és a határolókeretet a képen az és DrawRectangle a DrawString metódusok használatával.

thumbnailGraphic.DrawString(text, drawFont, fontBrush, atPoint);

// Draw bounding box on image
thumbnailGraphic.DrawRectangle(pen, x, y, width, height);

Az egyes hurkokon kívül adjon hozzá kódot a képek mentéséhez a outputFolder.

if (!Directory.Exists(outputImageLocation))
{
    Directory.CreateDirectory(outputImageLocation);
}

image.Save(Path.Combine(outputImageLocation, imageName));

Ha további visszajelzést szeretne arról, hogy az alkalmazás futásidőben a vártnak megfelelően előrejelzéseket készít, adjon hozzá egy metódus alatt DrawBoundingBox található metódust LogDetectedObjects a Program.cs fájlban, amely az észlelt objektumokat a konzolra küldi.

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("");
}

Most, hogy már rendelkezik segítő módszerekkel az előrejelzésekből származó vizuális visszajelzések létrehozásához, adjon hozzá egy for-loopot az iterációhoz az egyes pontozott képeken.

for (var i = 0; i < images.Count(); i++)
{

}

A for-loopon belül kérje le a képfájl nevét és a hozzá tartozó határolókereteket.

string imageFileName = images.ElementAt(i).Label;
IList<YoloBoundingBox> detectedObjects = boundingBoxes.ElementAt(i);

Ez alatt a DrawBoundingBox módszerrel rajzolhatja meg a határolókereteket a képen.

DrawBoundingBox(imagesFolder, outputFolder, imageFileName, detectedObjects);

Végül a LogDetectedObjects metódus használatával előrejelzéseket ad ki a konzolnak.

LogDetectedObjects(imageFileName, detectedObjects);

A try-catch utasítás után adjon hozzá további logikát a folyamat futásának jelzéséhez.

Console.WriteLine("========= End of Process..Hit any Key ========");

Ennyi az egész!

EREDMÉNY

Az előző lépések végrehajtása után futtassa a konzolalkalmazást (Ctrl + F5). Az eredményeknek az alábbi kimenethez hasonlónak kell lenniük. Megjelenhetnek figyelmeztetések vagy üzenetek feldolgozása, de ezeket az üzeneteket eltávolítottuk az alábbi eredményekből az egyértelműség érdekében.

=====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 ========

Ha határolókereteket tartalmazó képeket szeretne látni, keresse meg a könyvtárat assets/images/output/ . Az alábbiakban egy minta látható az egyik feldolgozott rendszerképből.

Sample processed image of a dining room

Gratulálunk! Most sikeresen létrehozott egy gépi tanulási modellt az objektumészleléshez egy előre betanított ONNX modell ML.NET való újrafelhasználásával.

Az oktatóanyag forráskódját a dotnet/machinelearning-samples adattárban találja.

Ez az oktatóanyag bemutatta, hogyan végezheti el az alábbi műveleteket:

  • A probléma ismertetése
  • Ismerje meg, mi az ONNX, és hogyan működik ML.NET
  • A modell megismerése
  • Az előre betanított modell újrafelhasználása
  • Betöltött modellel rendelkező objektumok észlelése

Tekintse meg a Machine Tanulás GitHub-adattárat egy bővített objektumészlelési minta megismeréséhez.