Tutorial: Mengategorikan gambar dalam ML.NET dari model CUSTOM Vision ONNX

Pelajari cara menggunakan ML.NET untuk mendeteksi objek dalam gambar menggunakan model ONNX yang dilatih dalam layanan Microsoft Custom Vision.

Layanan Microsoft Custom Vision adalah layanan AI yang melatih model berdasarkan gambar yang Anda unggah. Anda kemudian dapat mengekspor model ke format ONNX dan menggunakannya dalam ML.NET untuk membuat prediksi.

Dalam tutorial ini, Anda akan belajar cara:

  • Menggunakan layanan Custom Vision untuk membuat model ONNX
  • Menggabungkan model ONNX ke dalam alur ML.NET
  • Melatih model ML.NET
  • Mendeteksi tanda berhenti dalam gambar pengujian

Prasyarat

Buatlah model

Membuat proyek Custom Vision

Masuk ke layanan Microsoft Custom Vision dan pilih Proyek Baru.

Dalam dialog Proyek Baru , isi item yang diperlukan berikut ini:

  • Atur Nama proyek Custom Vision sebagai StopSignDetection.
  • Pilih Sumber Daya yang akan Anda gunakan. Ini adalah sumber daya Azure yang akan dibuat untuk proyek Custom Vision. Jika tidak ada yang terdaftar, dapat dibuat dengan memilih tautan Buat baru.
  • Atur Jenis proyek sebagai Deteksi Objek.
  • Atur Jenis Klasifikasi sebagai Multikelas karena akan ada satu kelas per gambar.
  • Atur Domain sebagai Umum (ringkas) [S1]. Domain ringkas memungkinkan Anda mengunduh model ONNX.
  • Untuk Kemampuan ekspor, pilih Platform dasar untuk memungkinkan ekspor model ONNX.

Setelah bidang di atas diisi, pilih Buat proyek.

Menambahkan gambar

  1. Dengan proyek yang dibuat, pilih Tambahkan gambar untuk mulai menambahkan gambar agar model dapat dilatih. Pilih gambar stop-sign yang Anda unduh.
  2. Pilih gambar pertama yang ditampilkan. Anda dapat memilih objek dalam gambar yang Anda inginkan untuk dideteksi model. Pilih rambu berhenti dalam gambar. Popup menampilkan dan mengatur tag sebagai stop-sign.
  3. Ulangi untuk semua gambar yang tersisa. Beberapa gambar memiliki lebih dari satu tanda berhenti, jadi pastikan untuk menandai semua yang ada dalam gambar.

Melatih model

Dengan gambar yang diunggah dan ditandai, model sekarang dapat dilatih. Pilih Train.

Popup muncul menanyakan jenis pelatihan apa yang akan digunakan. Pilih Pelatihan cepat lalu pilih Latih.

Mengunduh model ONNX

Setelah pelatihan selesai, klik tombol Ekspor . Saat popup ditampilkan, pilih ONNX untuk mengunduh model ONNX.

Memeriksa model ONNX

Unzip file ONNX yang diunduh. Folder berisi beberapa file, tetapi dua yang akan Anda gunakan dalam tutorial ini adalah:

  • labels.txt, yang merupakan file teks yang berisi label yang ditentukan dalam layanan Custom Vision.
  • model.onnx, yang merupakan model ONNX yang akan Anda gunakan untuk membuat prediksi dalam ML.NET.

Untuk membangun alur ML.NET, Anda memerlukan nama nama kolom input dan output. Untuk mendapatkan informasi ini, gunakan Netron, aplikasi web dan desktop yang dapat menganalisis model ONNX dan menampilkan arsitekturnya.

  1. Saat menggunakan aplikasi web atau desktop Netron, buka model ONNX di aplikasi. Setelah terbuka, grafik akan ditampilkan. Grafik ini memberi tahu Anda beberapa hal yang perlu Anda buat alur ML.NET untuk prediksi.

    • Nama kolom input - Nama kolom input diperlukan saat menerapkan model ONNX di ML.NET.

      Kolom Input Netron

    • Nama kolom output - Nama kolom output yang diperlukan saat menerapkan model ONNX di ML.NET.

      Kolom Output Netron

    • Ukuran gambar - Ukuran yang diperlukan saat mengubah ukuran gambar dalam alur ML.NET.

      Ukuran Gambar Netron

Membuat proyek konsol C#

  1. Di Visual Studio, buat Aplikasi Konsol C# yang disebut "StopSignDetection". Pilih .NET 8 sebagai kerangka kerja target.

  2. Instal paket NuGet berikut untuk proyek:

    • Microsoft.ML
    • Microsoft.ML.ImageAnalytics
    • Microsoft.Onnx.Transformer

    Nota

    Sampel ini menggunakan versi stabil terbaru dari paket NuGet yang disebutkan kecuali dinyatakan lain.

Mereferensikan model ONNX

Temukan dua file dari model ONNX (labels.txt dan model.onnx) di Penjelajah Solusi Visual Studio. Klik kanan mereka dan, di jendela Properti, atur Salin ke direktori output ke Salin jika lebih baru.

Membuat kelas input dan prediksi

  1. Tambahkan kelas baru ke proyek Anda dan beri nama StopSignInput. Kemudian, tambahkan struktur berikut ke kelas :

    public struct ImageSettings
    {
        public const int imageHeight = 320;
        public const int imageWidth = 320;
    }
    
  2. Selanjutnya, tambahkan properti berikut ke kelas .

    public class StopSignInput
    {
        [ImageType(ImageSettings.imageHeight, ImageSettings.imageWidth)]
        public Bitmap Image { get; set; }
    }
    

    Properti Image berisi bitmap gambar yang digunakan untuk prediksi. Atribut ImageType menginformasikan ML.NET bahwa properti adalah gambar dengan dimensi 320 kali 320, yang ditentukan menggunakan Netron.

  3. Tambahkan kelas lain ke proyek Anda dan beri nama StopSignPrediction. Kemudian, tambahkan properti berikut ke kelas .

    public class StopSignPrediction
    {
        [ColumnName("detected_classes")]
        public long[] PredictedLabels { get; set; }
    
        [ColumnName("detected_boxes")]
        public float[] BoundingBoxes { get; set; }
    
        [ColumnName("detected_scores")]
        public float[] Scores { get; set; }
    }
    

    Properti PredictedLabels berisi prediksi label untuk setiap objek yang terdeteksi. Jenisnya adalah array float, sehingga setiap item dalam array adalah prediksi setiap label. Atribut ColumnName memberi tahu ML.NET bahwa kolom ini dalam model adalah nama yang diberikan, yaitu detected_classes.

    Properti BoundingBoxes berisi kotak pembatas (bounding boxes) untuk setiap objek yang terdeteksi. Jenisnya adalah array float dan setiap objek yang terdeteksi memiliki empat item dalam array yang berfungsi sebagai kotak pembatas. Atribut ColumnName memberi tahu ML.NET bahwa kolom ini dalam model adalah nama yang diberikan, yaitu detected_boxes.

    Properti Scores berisi skor keyakinan dari setiap objek yang diprediksi dan labelnya. Tipe datanya adalah array float, sehingga setiap item dalam array adalah skor kepercayaan dari setiap label. Atribut ColumnName memberi tahu ML.NET bahwa kolom ini dalam model adalah nama yang diberikan, yaitu detected_scores.

Menggunakan model untuk membuat prediksi

Tambahkan direktif penggunaan

Dalam file Program.cs , tambahkan arahan berikut using ke bagian atas file.

using Microsoft.ML;
using Microsoft.ML.Transforms.Image;
using System.Drawing;
using WeatherRecognition;

Membuat objek

  1. MLContext Buat objek.

    var context = new MLContext();
    
  2. IDataView Buat dengan daftar kosong StopSignInput baru.

    var data = context.Data.LoadFromEnumerable(new List<StopSignInput>());
    
  3. Untuk konsistensi, simpan gambar yang diprediksi ke jalur perakitan.

    var root = new FileInfo(typeof(Program).Assembly.Location);
    var assemblyFolderPath = root.Directory.FullName;
    

Membangun alur

Setelah elemen kosong IDataView dibuat, pipeline dapat dibangun untuk memprediksi gambar baru apa pun. Alur terdiri dari beberapa langkah:

  1. Mengubah ukuran gambar masuk.

    Gambar yang dikirim ke model untuk prediksi akan sering berada dalam rasio aspek yang berbeda dengan gambar yang dilatih pada model. Agar gambar tetap konsisten untuk prediksi yang akurat, mengubah ukuran gambar menjadi 320x320. Untuk melakukannya, gunakan ResizeImages metode dan atur imageColumnName sebagai nama StopSignInput.Image properti .

    var pipeline = context.Transforms.ResizeImages(resizing: ImageResizingEstimator.ResizingKind.Fill, outputColumnName: "image_tensor", imageWidth: ImageSettings.imageWidth, imageHeight: ImageSettings.imageHeight, inputColumnName: nameof(StopSignInput.Image))
    
  2. Ekstrak piksel gambar.

    Setelah gambar diubah ukurannya, Anda perlu mengekstrak piksel dari gambar. Tambahkan metode ExtractPixels ke alur kerja Anda dan tentukan nama kolom untuk mengeluarkan piksel menggunakan parameter outputColumnName.

    .Append(context.Transforms.ExtractPixels(outputColumnName: "image_tensor"))
    
  3. Terapkan model ONNX ke gambar untuk membuat prediksi. Ini membutuhkan beberapa parameter:

    • modelFile - Jalur ke file model ONNX
    • outputColumnNames - Array string yang berisi nama semua nama kolom output, yang dapat ditemukan saat menganalisis model ONNX di Netron.
    • inputColumnNames - Array string yang berisi nama semua nama kolom input, yang juga dapat ditemukan saat menganalisis model ONNX di Netron.

    Important

    Hanya terapkan model dari sumber tepercaya. Menerapkan model dari sumber yang tidak tepercaya adalah risiko keamanan.

    .Append(context.Transforms.ApplyOnnxModel(outputColumnNames: new string[] { "detected_boxes", "detected_scores", "detected_classes" }, inputColumnNames: new string[] { "image_tensor" }, modelFile: "./Model/model.onnx"));
    

Paskan model

Setelah menentukan alur, Anda dapat menggunakannya untuk membangun model ML.NET. Fit Gunakan metode pada alur dan teruskan dalam kosong IDataView.

var model = pipeline.Fit(data);

Selanjutnya, untuk membuat prediksi, gunakan model untuk membuat mesin prediksi. Ini adalah metode generik, jadi dibutuhkan di StopSignInput kelas dan StopSignPrediction yang dibuat sebelumnya.

var predictionEngine = context.Model.CreatePredictionEngine<StopSignInput, StopSignPrediction>(model);

Mengekstrak label

Untuk memetakan output model ke labelnya, Anda perlu mengekstrak label yang disediakan oleh Custom Vision. Label ini berada dalam file labels.txt yang disertakan dalam file zip dengan model ONNX.

ReadAllLines Panggil metode untuk membaca semua label dari file.

var labels = File.ReadAllLines("./model/labels.txt");

Memprediksi pada gambar pengujian

Sekarang Anda dapat menggunakan model untuk memprediksi gambar baru. Dalam proyek, ada folder pengujian yang dapat Anda gunakan untuk membuat prediksi. Folder ini berisi dua gambar acak dengan rambu berhenti di dalamnya dari Unsplash. Satu gambar memiliki tanda berhenti sementara yang lain memiliki dua tanda berhenti. GetFiles Gunakan metode untuk membaca jalur file gambar di direktori.

var testFiles = Directory.GetFiles("./test");

Telusuri jalur file untuk membuat prediksi dengan model dan keluarkan hasilnya.

  1. Buat perulangan foreach untuk mengulangi gambar pengujian.

    Bitmap testImage;
    
    foreach (var image in testFiles)
    {
    
    }
    
  2. Dalam perulangan foreach , hasilkan nama gambar yang diprediksi berdasarkan nama gambar pengujian asli.

    var predictedImage = $"{Path.GetFileName(image)}-predicted.jpg";
    
  3. Dalam perulangan foreach juga, buat FileStream dari gambar dan ubah menjadi Bitmap.

    using (var stream = new FileStream(image, FileMode.Open))
    {
        testImage = (Bitmap)Image.FromStream(stream);
    }
    
  4. Juga dalam perulangan foreach , panggil Predict metode pada mesin prediksi.

    var prediction = predictionEngine.Predict(new StopSignInput { Image = testImage });
    
  5. Dengan prediksi, Anda bisa mendapatkan kotak pembatas. Chunk Gunakan metode untuk menentukan berapa banyak objek yang telah terdeteksi oleh model. Lakukan ini dengan menghitung jumlah kotak pembatas yang diprediksi dan membaginya dengan jumlah label yang diprediksi. Misalnya, jika Anda memiliki tiga objek yang terdeteksi dalam gambar, akan ada 12 item dalam BoundingBoxes array dan tiga label yang diprediksi. Metode ini Chunk kemudian akan memberi Anda tiga array, masing-masing terdiri dari empat elemen yang mewakili kotak pembatas untuk setiap objek.

    var boundingBoxes = prediction.BoundingBoxes.Chunk(prediction.BoundingBoxes.Count() / prediction.PredictedLabels.Count());
    
  6. Selanjutnya, ambil lebar dan tinggi asli gambar yang digunakan untuk prediksi.

    var originalWidth = testImage.Width;
    var originalHeight = testImage.Height;
    
  7. Hitung di mana dalam gambar untuk menggambar kotak. Untuk itu, buat perulangan for berdasarkan jumlah gugus kotak pembatas.

    for (int i = 0; i < boundingBoxes.Count(); i++)
    {
    }
    
  8. Dalam perulangan for , hitung posisi koordinat x dan y serta lebar dan tinggi kotak untuk menggambar gambar. Hal pertama yang perlu Anda lakukan adalah mendapatkan set kotak pembatas menggunakan metode ElementAt.

    var boundingBox = boundingBoxes.ElementAt(i);
    
  9. Dengan kotak pembatas saat ini, Anda sekarang dapat menghitung posisi untuk menggambar kotak. Gunakan lebar gambar asli untuk elemen pertama dan ketiga dari kotak pembatas, dan tinggi gambar asli untuk elemen kedua dan keempat.

    var left = boundingBox[0] * originalWidth;
    var top = boundingBox[1] * originalHeight;
    var right = boundingBox[2] * originalWidth;
    var bottom = boundingBox[3] * originalHeight;
    
  10. Hitung lebar dan tinggi kotak untuk menggambar di sekitar objek yang terdeteksi dalam gambar. Item x dan y adalah left variabel dan top dari perhitungan sebelumnya. Math.Abs Gunakan metode untuk mendapatkan nilai absolut dari perhitungan lebar dan tinggi jika negatif.

    var x = left;
    var y = top;
    var width = Math.Abs(right - left);
    var height = Math.Abs(top - bottom);
    
  11. Selanjutnya, dapatkan label yang diprediksi dari array label.

    var label = labels[prediction.PredictedLabels[i]];
    
  12. Buat grafik berdasarkan gambar pengujian menggunakan Graphics.FromImage metode .

    using var graphics = Graphics.FromImage(testImage);
    
  13. Gambar gambar menggunakan informasi kotak pembatas. Pertama, gambar persegi panjang di sekitar objek yang terdeteksi menggunakan metode DrawRectangle yang menerima objek Pen untuk menentukan warna dan lebar persegi panjang, dan oper variabel x, y, width, dan height.

    graphics.DrawRectangle(new Pen(Color.NavajoWhite, 8), x, y, width, height);
    
  14. Kemudian, tampilkan label yang diprediksi di dalam kotak menggunakan metode DrawString yang menerima string untuk dicetak dan objek Font untuk menentukan cara menggambar string dan di mana menempatkannya.

    graphics.DrawString(label, new Font(FontFamily.Families[0], 18f), Brushes.NavajoWhite, x + 5, y + 5);
    
  15. Setelah perulangan for , periksa apakah file yang diprediksi sudah ada. Jika ya, hapus. Kemudian, simpan ke jalur output yang ditentukan.

    if (File.Exists(predictedImage))
    {
        File.Delete(predictedImage);
    }
    
    testImage.Save(Path.Combine(assemblyFolderPath, predictedImage));
    

Langkah selanjutnya

Coba salah satu tutorial klasifikasi gambar lainnya: