Tutorial: Membuat aplikasi Windows Pembelajaran Mesin Desktop (C++)
API ML Windows dapat dimanfaat untuk berinteraksi dengan model pembelajaran mesin dengan mudah dalam aplikasi desktop C++ (Win32). Dengan menggunakan tiga langkah memuat, mengikat, dan mengevaluasi, aplikasi Anda dapat memperoleh manfaat dari kekuatan pembelajaran mesin.
Kami akan membuat versi sampel Deteksi Objek SqueezeNet yang agak disederhanakan, yang tersedia di GitHub. Anda dapat mengunduh sampel lengkap jika Anda ingin melihat seperti apa tampilannya setelah selesai.
Kita akan menggunakan C++/WinRT untuk mengakses API WinML. Lihat C++/WinRT untuk informasi selengkapnya.
Dalam tutorial ini, Anda akan mempelajari cara:
- Memuat model pembelajaran mesin
- Memuat gambar sebagai VideoFrame
- Mengikat input dan output model
- Mengevaluasi model dan mencetak hasil yang bermakna
Prasyarat
- Visual Studio 2019 (atau Visual Studio 2017, versi 15.7.4 atau yang lebih baru)
- Windows 10, versi 1809 atau yang lebih baru
- Windows SDK, build 17763 atau yang lebih baru
- Ekstensi Visual Studio untuk C++/WinRT
- Di Visual Studio, pilih > Ekstensi alat dan Pembaruan.
- Pilih Online di panel kiri dan cari "WinRT" menggunakan kotak pencarian di sebelah kanan.
- Pilih C++/WinRT, klik Unduh, dan tutup Visual Studio.
- Ikuti petunjuk penginstalan, lalu buka kembali Visual Studio.
- Repositori Windows-Machine-Pembelajaran Github (Anda dapat mengunduhnya sebagai file ZIP atau mengkloning ke komputer Anda)
Membuat proyek
Pertama, kita akan membuat proyek di Visual Studio:
- Pilih File > Proyek Baru > untuk membuka jendela Proyek Baru.
- Di panel kiri, pilih Visual C++ > Windows Desktop terinstal>, dan di tengah, pilih Aplikasi Konsol Windows (C++/WinRT).
- Beri nama dan Lokasi pada proyek Anda, lalu klik OK.
- Di jendela Proyek Platform Windows Universal Baru, atur Versi Target dan Minimum untuk membangun 17763 atau yang lebih baru, dan klik OK.
- Pastikan menu dropdown di toolbar atas diatur ke Debug dan x64 atau x86 bergantung pada arsitektur komputer Anda.
- Tekan Ctrl+F5 untuk menjalankan program tanpa penelusuran kesalahan. Terminal harus terbuka dengan beberapa teks "Halo dunia". Tekan tombol apa pun untuk menutupnya.
Memuat model
Selanjutnya, kita akan memuat model ONNX ke dalam program kita menggunakan Pembelajaran Model.LoadFromFilePath:
Di pch.h (di folder File Header), tambahkan pernyataan berikut
include
(ini memberi kami akses ke semua API yang akan kita butuhkan):#include <winrt/Windows.AI.MachineLearning.h> #include <winrt/Windows.Foundation.Collections.h> #include <winrt/Windows.Graphics.Imaging.h> #include <winrt/Windows.Media.h> #include <winrt/Windows.Storage.h> #include <string> #include <fstream> #include <Windows.h>
Di main.cpp (di folder File Sumber), tambahkan pernyataan berikut
using
:using namespace Windows::AI::MachineLearning; using namespace Windows::Foundation::Collections; using namespace Windows::Graphics::Imaging; using namespace Windows::Media; using namespace Windows::Storage; using namespace std;
Tambahkan deklarasi variabel berikut setelah
using
pernyataan:// Global variables hstring modelPath; string deviceName = "default"; hstring imagePath; LearningModel model = nullptr; LearningModelDeviceKind deviceKind = LearningModelDeviceKind::Default; LearningModelSession session = nullptr; LearningModelBinding binding = nullptr; VideoFrame imageFrame = nullptr; string labelsFilePath; vector<string> labels;
Tambahkan deklarasi penerusan berikut setelah variabel global Anda:
// Forward declarations void LoadModel(); VideoFrame LoadImageFile(hstring filePath); void BindModel(); void EvaluateModel(); void PrintResults(IVectorView<float> results); void LoadLabels();
Dalam main.cpp, hapus kode "Halo dunia" (semuanya dalam
main
fungsi setelahinit_apartment
).Temukan file SqueezeNet.onnx di klon lokal repositori Windows-Machine-Pembelajaran Anda. Ini harus terletak di \Windows-Machine-Pembelajaran\SharedContent\models.
Salin jalur file dan tetapkan ke variabel Anda
modelPath
di mana kami mendefinisikannya di bagian atas. Ingatlah untuk mengawali string denganL
untuk menjadikannya string karakter yang lebar sehingga berfungsi dengan baik denganhstring
, dan untuk menghindari garis miring terbalik (\
) dengan garis miring terbalik tambahan. Contohnya:hstring modelPath = L"C:\\Repos\\Windows-Machine-Learning\\SharedContent\\models\\SqueezeNet.onnx";
Pertama, kita akan menerapkan metode .
LoadModel
Tambahkan metode berikut setelahmain
metode . Metode ini memuat model dan output berapa lama waktu yang dibutuhkan:void LoadModel() { // load the model printf("Loading modelfile '%ws' on the '%s' device\n", modelPath.c_str(), deviceName.c_str()); DWORD ticks = GetTickCount(); model = LearningModel::LoadFromFilePath(modelPath); ticks = GetTickCount() - ticks; printf("model file loaded in %d ticks\n", ticks); }
Terakhir, panggil metode ini dari
main
metode :LoadModel();
Jalankan program Anda tanpa penelusuran kesalahan. Anda akan melihat bahwa model Anda berhasil dimuat!
Muat gambar
Selanjutnya, kita akan memuat file gambar ke dalam program kita:
Tambahkan metode berikut. Metode ini akan memuat gambar dari jalur yang diberikan dan membuat VideoFrame darinya:
VideoFrame LoadImageFile(hstring filePath) { printf("Loading the image...\n"); DWORD ticks = GetTickCount(); VideoFrame inputImage = nullptr; try { // open the file StorageFile file = StorageFile::GetFileFromPathAsync(filePath).get(); // get a stream on it auto stream = file.OpenAsync(FileAccessMode::Read).get(); // Create the decoder from the stream BitmapDecoder decoder = BitmapDecoder::CreateAsync(stream).get(); // get the bitmap SoftwareBitmap softwareBitmap = decoder.GetSoftwareBitmapAsync().get(); // load a videoframe from it inputImage = VideoFrame::CreateWithSoftwareBitmap(softwareBitmap); } catch (...) { printf("failed to load the image file, make sure you are using fully qualified paths\r\n"); exit(EXIT_FAILURE); } ticks = GetTickCount() - ticks; printf("image file loaded in %d ticks\n", ticks); // all done return inputImage; }
Tambahkan panggilan ke metode ini dalam
main
metode :imageFrame = LoadImageFile(imagePath);
Temukan folder media di klon lokal repositori Windows-Machine-Pembelajaran Anda. Ini harus terletak di \Windows-Machine-Pembelajaran\SharedContent\media.
Pilih salah satu gambar di folder tersebut, dan tetapkan jalur filenya ke
imagePath
variabel tempat kami menentukannya di bagian atas. Ingatlah untuk mengawalinya dengan untukL
menjadikannya string karakter yang lebar, dan untuk menghindari garis miring terbalik dengan garis miring terbalik lainnya. Contohnya:hstring imagePath = L"C:\\Repos\\Windows-Machine-Learning\\SharedContent\\media\\kitten_224.png";
Jalankan program tanpa penelusuran kesalahan. Anda akan melihat gambar berhasil dimuat!
Mengikat input dan output
Selanjutnya, kita akan membuat sesi berdasarkan model dan mengikat input dan output dari sesi menggunakan Pembelajaran ModelBinding.Bind. Untuk informasi selengkapnya tentang pengikatan, lihat Mengikat model.
Mengimplementasikan metode
BindModel
. Ini membuat sesi berdasarkan model dan perangkat, dan pengikatan berdasarkan sesi tersebut. Kami kemudian mengikat input dan output ke variabel yang telah kami buat menggunakan namanya. Kami kebetulan tahu sebelumnya bahwa fitur input diberi nama "data_0" dan fitur output diberi nama "softmaxout_1". Anda dapat melihat properti ini untuk model apa pun dengan membukanya di Netron, alat visualisasi model online.void BindModel() { printf("Binding the model...\n"); DWORD ticks = GetTickCount(); // now create a session and binding session = LearningModelSession{ model, LearningModelDevice(deviceKind) }; binding = LearningModelBinding{ session }; // bind the intput image binding.Bind(L"data_0", ImageFeatureValue::CreateFromVideoFrame(imageFrame)); // bind the output vector<int64_t> shape({ 1, 1000, 1, 1 }); binding.Bind(L"softmaxout_1", TensorFloat::Create(shape)); ticks = GetTickCount() - ticks; printf("Model bound in %d ticks\n", ticks); }
Tambahkan panggilan ke
BindModel
darimain
metode :BindModel();
Jalankan program tanpa penelusuran kesalahan. Input dan output model harus berhasil diikat. Kami hampir sampai!
Evaluasi model
Kita sekarang pada langkah terakhir dalam diagram di awal tutorial ini, Evaluasi. Kami akan mengevaluasi model menggunakan Pembelajaran ModelSession.Evaluate:
Mengimplementasikan metode
EvaluateModel
. Metode ini mengambil sesi kami dan mengevaluasinya menggunakan pengikatan dan ID korelasi kami. ID korelasi adalah sesuatu yang mungkin dapat kita gunakan nanti untuk mencocokkan panggilan evaluasi tertentu dengan hasil output. Sekali lagi, kita tahu sebelumnya bahwa nama output adalah "softmaxout_1".void EvaluateModel() { // now run the model printf("Running the model...\n"); DWORD ticks = GetTickCount(); auto results = session.Evaluate(binding, L"RunId"); ticks = GetTickCount() - ticks; printf("model run took %d ticks\n", ticks); // get the output auto resultTensor = results.Outputs().Lookup(L"softmaxout_1").as<TensorFloat>(); auto resultVector = resultTensor.GetAsVectorView(); PrintResults(resultVector); }
Sekarang mari kita terapkan
PrintResults
. Metode ini mendapatkan tiga probabilitas teratas untuk objek apa yang bisa ada dalam gambar, dan mencetaknya:void PrintResults(IVectorView<float> results) { // load the labels LoadLabels(); // Find the top 3 probabilities vector<float> topProbabilities(3); vector<int> topProbabilityLabelIndexes(3); // SqueezeNet returns a list of 1000 options, with probabilities for each, loop through all for (uint32_t i = 0; i < results.Size(); i++) { // is it one of the top 3? for (int j = 0; j < 3; j++) { if (results.GetAt(i) > topProbabilities[j]) { topProbabilityLabelIndexes[j] = i; topProbabilities[j] = results.GetAt(i); break; } } } // Display the result for (int i = 0; i < 3; i++) { printf("%s with confidence of %f\n", labels[topProbabilityLabelIndexes[i]].c_str(), topProbabilities[i]); } }
Kita juga perlu mengimplementasikan
LoadLabels
. Metode ini membuka file label yang berisi semua objek berbeda yang dapat dikenali model, dan mengurainya:void LoadLabels() { // Parse labels from labels file. We know the file's entries are already sorted in order. ifstream labelFile{ labelsFilePath, ifstream::in }; if (labelFile.fail()) { printf("failed to load the %s file. Make sure it exists in the same folder as the app\r\n", labelsFilePath.c_str()); exit(EXIT_FAILURE); } std::string s; while (std::getline(labelFile, s, ',')) { int labelValue = atoi(s.c_str()); if (labelValue >= labels.size()) { labels.resize(labelValue + 1); } std::getline(labelFile, s); labels[labelValue] = s; } }
Temukan file Labels.txt di klon lokal repositori Windows-Machine-Pembelajaran Anda. Ini harus dalam \Windows-Machine-Pembelajaran\Samples\SqueezeNetObjectDetection\Desktop\cpp.
Tetapkan jalur file ini ke
labelsFilePath
variabel tempat kami mendefinisikannya di bagian atas. Pastikan untuk menghindari garis miring terbelakang dengan garis miring terbelakang lainnya. Contohnya:string labelsFilePath = "C:\\Repos\\Windows-Machine-Learning\\Samples\\SqueezeNetObjectDetection\\Desktop\\cpp\\Labels.txt";
Tambahkan panggilan ke
EvaluateModel
main
dalam metode :EvaluateModel();
Jalankan program tanpa penelusuran kesalahan. Sekarang harus mengenali dengan benar apa yang ada dalam gambar! Berikut adalah contoh apa yang mungkin dihasilkannya:
Loading modelfile 'C:\Repos\Windows-Machine-Learning\SharedContent\models\SqueezeNet.onnx' on the 'default' device model file loaded in 250 ticks Loading the image... image file loaded in 78 ticks Binding the model...Model bound in 15 ticks Running the model... model run took 16 ticks tabby, tabby cat with confidence of 0.931461 Egyptian cat with confidence of 0.065307 Persian cat with confidence of 0.000193
Langkah berikutnya
Hore, Anda memiliki deteksi objek yang berfungsi di aplikasi desktop C++! Selanjutnya, Anda dapat mencoba menggunakan argumen baris perintah untuk memasukkan model dan file gambar daripada hardcoding, mirip dengan apa yang dilakukan sampel di GitHub. Anda juga dapat mencoba menjalankan evaluasi pada perangkat yang berbeda, seperti GPU, untuk melihat perbedaan performanya.
Bermain-main dengan sampel lain di GitHub dan memperluasnya sesuka Anda!
Lihat juga
Catatan
Gunakan sumber daya berikut untuk bantuan dengan Windows ML:
- Untuk mengajukan atau menjawab pertanyaan teknis tentang Windows ML, silakan gunakan tag windows-machine-learning di Stack Overflow.
- Untuk melaporkan bug, silakan ajukan masalah di GitHub kami.