Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Windows ML-APIs können verwendet werden, um problemlos mit Machine Learning-Modellen in C++-Desktopanwendungen (Win32) zu interagieren. Mit den drei Schritten zum Laden, Binden und Auswerten kann Ihre Anwendung von der Leistungsfähigkeit des maschinellen Lernens profitieren.
Wir werden eine etwas vereinfachte Version des SqueezeNet Object Detection-Beispiels erstellen, das auf GitHub verfügbar ist. Sie können das vollständige Beispiel herunterladen, wenn Sie sehen möchten, wie es aussieht, wenn Sie fertig sind.
Wir verwenden C++/WinRT, um auf die WinML-APIs zuzugreifen. Weitere Informationen finden Sie unter C++/WinRT .
In diesem Tutorial lernen Sie, wie Sie:
- Laden eines Machine Learning-Modells
- Laden eines Bilds als VideoFrame
- Eingaben und Ausgaben des Modells binden
- Auswerten des Modells und Drucken aussagekräftiger Ergebnisse
Voraussetzungen
- Visual Studio 2019 (oder Visual Studio 2017, Version 15.7.4 oder höher)
- Windows 10, Version 1809 oder höher
- Windows SDK, Build 17763 oder höher
- Visual Studio-Erweiterung für C++/WinRT
- Wählen Sie in Visual Studio Werkzeuge > Erweiterungen und Aktualisierungen aus.
- Wählen Sie im linken Bereich "Online " aus, und suchen Sie mithilfe des Suchfelds auf der rechten Seite nach "WinRT".
- Wählen Sie C++/WinRT aus, klicken Sie auf "Herunterladen", und schließen Sie Visual Studio.
- Folgen Sie den Installationsanweisungen, und öffnen Sie Visual Studio erneut.
- Windows-Machine-Learning GitHub-Repository (Sie können es entweder als ZIP-Datei herunterladen oder auf Ihren Computer klonen)
Erstelle das Projekt
Zunächst erstellen wir das Projekt in Visual Studio:
- Wählen Sie „Datei > Neues > Projekt“, um das Fenster „Neues Projekt“ zu öffnen.
- Wählen Sie im linken Bereich "Installierter > Visual C++ > -Windows-Desktop" aus, und wählen Sie in der Mitte Die Windows-Konsolenanwendung (C++/WinRT) aus.
- Geben Sie Ihrem Projekt einen Namen und einen Speicherort, und klicken Sie dann auf "OK".
- Legen Sie im Fenster " Neues Projekt für die universelle Windows-Plattform " das Ziel und die Mindestversion auf Build 17763 oder höher fest, und klicken Sie auf "OK".
- Stellen Sie sicher, dass die Dropdownmenüs in der oberen Symbolleiste abhängig von der Architektur Ihres Computers auf "Debuggen" und entweder auf "x64 " oder "x86 " festgelegt sind.
- Drücken Sie STRG+F5 , um das Programm ohne Debugging auszuführen. Ein Terminal sollte mit einigen "Hello world"-Text geöffnet werden. Drücken Sie eine beliebige Taste, um sie zu schließen.
Laden des Modells
Als Nächstes laden wir das ONNX-Modell mithilfe von LearningModel.LoadFromFilePath in unser Programm:
Fügen Sie in "pch.h " (im Ordner "Headerdateien ") die folgenden
include
Anweisungen hinzu (diese geben uns Zugriff auf alle APIs, die wir benötigen):#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>
Fügen Sie in main.cpp (im Ordner " Quelldateien ") die folgenden
using
Anweisungen hinzu: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;
Fügen Sie die folgenden Variablendeklarationen nach den
using
Anweisungen hinzu:// 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;
Fügen Sie die folgenden Vorwärtsdeklarationen nach Ihren globalen Variablen hinzu:
// Forward declarations void LoadModel(); VideoFrame LoadImageFile(hstring filePath); void BindModel(); void EvaluateModel(); void PrintResults(IVectorView<float> results); void LoadLabels();
Entfernen Sie in main.cpp den Code "Hello world" (alles in der
main
Funktion nachinit_apartment
).Suchen Sie die Datei "SqueezeNet.onnx " in Ihrem lokalen Klon des Windows-Machine-Learning-Repositorys . Sie sollte sich in \Windows-Machine-Learning\SharedContent\models befinden.
Kopieren Sie den Dateipfad, und weisen Sie ihn Ihrer
modelPath
Variablen zu, wo sie oben definiert wurde. Denken Sie daran, der Zeichenfolge einL
als Präfix voranzustellen, um sie zu einer Breitzeichenfolge zu machen, damit sie mithstring
ordnungsgemäß funktioniert, und versehen Sie etwaige umgekehrte Schrägstriche (\
) mit einem zusätzlichen umgekehrten Schrägstrich als Escapezeichen. Beispiel:hstring modelPath = L"C:\\Repos\\Windows-Machine-Learning\\SharedContent\\models\\SqueezeNet.onnx";
Zunächst implementieren wir die
LoadModel
Methode. Fügen Sie die folgende Methode nach dermain
Methode hinzu. Diese Methode lädt das Modell und gibt aus, wie lange es dauerte: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); }
Rufen Sie schließlich diese Methode aus der
main
Methode auf:LoadModel();
Führen Sie Ihr Programm ohne Debugging aus. Sie sollten sehen, dass das Modell erfolgreich geladen wird.
Laden des Bilds
Als Nächstes laden wir die Bilddatei in unser Programm:
Fügen Sie die folgende Methode hinzu. Mit dieser Methode wird das Bild aus dem angegebenen Pfad geladen und ein VideoFrame daraus erstellt:
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; }
Fügen Sie einen Aufruf dieser Methode in der
main
Methode hinzu.imageFrame = LoadImageFile(imagePath);
Suchen Sie den Medienordner im lokalen Klon des Windows-Machine-Learning-Repositorys . Er sollte sich unter \Windows-Machine-Learning\SharedContent\media befinden.
Wählen Sie ein Bild aus dem Ordner aus und weisen Sie seinen Dateipfad der Variablen
imagePath
zu, die wir oben definiert haben. Denken Sie daran, ihm einL
als Präfix voranzustellen, um die Zeichenfolge zu einer Breitzeichenfolge zu machen, und versehen Sie etwaige umgekehrte Schrägstriche mit einem zusätzlichen umgekehrten Schrägstrich als Escapezeichen. Beispiel:hstring imagePath = L"C:\\Repos\\Windows-Machine-Learning\\SharedContent\\media\\kitten_224.png";
Führen Sie das Programm ohne Debugging aus. Das Bild sollte erfolgreich geladen werden!
Binden Sie die Eingabe und Ausgabe
Als Nächstes erstellen wir eine Sitzung basierend auf dem Modell und binden die Eingabe und Ausgabe aus der Sitzung mithilfe von LearningModelBinding.Bind. Weitere Informationen zur Bindung finden Sie unter Binden eines Modells.
Implementieren Sie die
BindModel
-Methode. Dadurch wird eine Sitzung basierend auf dem Modell und dem Gerät und eine Bindung basierend auf dieser Sitzung erstellt. Anschließend binden wir die Eingaben und Ausgaben an Variablen, die wir mit ihren Namen erstellt haben. Wir wissen im Voraus, dass das Eingabefeature "data_0" heißt und das Ausgabefeature "softmaxout_1" heißt. Sie können diese Eigenschaften für jedes Modell anzeigen, indem Sie sie in Netron, einem Onlinemodellvisualisierungstool, öffnen.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); }
Fügen Sie einen Aufruf von
BindModel
aus dermain
-Methode hinzu:BindModel();
Führen Sie das Programm ohne Debugging aus. Die Eingaben und Ausgaben des Modells sollten erfolgreich gebunden werden. Wir sind fast da!
Auswerten des Modells
Wir befinden uns jetzt im letzten Schritt der Abbildung am Anfang dieses Tutorials: Auswerten. Wir bewerten das Modell mithilfe von LearningModelSession.Evaluate:
Implementieren Sie die
EvaluateModel
-Methode. Diese Methode verwendet unsere Sitzung und wertet sie anhand unserer Bindung und einer Korrelations-ID aus. Die Korrelations-ID könnten wir möglicherweise später verwenden, um einen bestimmten Auswertungsaufruf mit den Ausgabeergebnissen abzugleichen. Auch hier wissen wir vorab, dass der Name der Ausgabe "softmaxout_1" lautet.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); }
Lasst uns jetzt
PrintResults
implementieren. Diese Methode ruft die drei wichtigsten Wahrscheinlichkeiten für das Objekt im Bild ab und druckt sie: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]); } }
Wir müssen auch
LoadLabels
implementieren. Diese Methode öffnet die Bezeichnungsdatei, die alle verschiedenen Objekte enthält, die vom Modell erkannt werden können, und analysiert sie: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; } }
Suchen Sie die Labels.txt Datei im lokalen Klon des Windows-Machine-Learning-Repositorys . Er sollte sich in \Windows-Machine-Learning\Samples\SqueezeNetObjectDetection\Desktop\cpp befinden.
Weisen Sie diesen Dateipfad der Variablen
labelsFilePath
zu, die wir oben definiert haben. Stellen Sie sicher, dass alle umgekehrten Schrägstriche mit einem weiteren umgekehrten Schrägstrich als Escapezeichen versehen werden. Beispiel:string labelsFilePath = "C:\\Repos\\Windows-Machine-Learning\\Samples\\SqueezeNetObjectDetection\\Desktop\\cpp\\Labels.txt";
Fügen Sie einen Aufruf von
EvaluateModel
in dermain
-Methode hinzu:EvaluateModel();
Führen Sie das Programm ohne Debugging aus. Es sollte nun richtig erkennen, was im Bild ist! Hier ist ein Beispiel für das, was möglicherweise ausgegeben wird:
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
Nächste Schritte
Hurra, die Objekterkennung funktioniert in Ihrer C++-Desktopanwendung! Als Nächstes können Sie die Befehlszeilenargumente verwenden, um die Modell- und Bilddateien einzugeben, anstatt sie zu hartcodieren, ähnlich wie das Beispiel auf GitHub. Sie können auch versuchen, die Auswertung auf einem anderen Gerät wie der GPU auszuführen, um zu sehen, wie sich die Leistung unterscheidet.
Spielen Sie mit den anderen Beispielen auf GitHub herum, und erweitern Sie sie, wie Sie möchten!
Siehe auch
Hinweis
Verwenden Sie die folgenden Ressourcen für Hilfe zu Windows ML:
- Um technische Fragen zu Windows ML zu stellen oder zu beantworten, verwenden Sie bitte das Windows-Machine-Learning-Tag auf Stack Overflow.
- Um einen Fehler zu melden, reichen Sie bitte ein Issue auf unserem GitHub ein.