Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Interfejsy API uczenia maszynowego systemu Windows mogą być używane do łatwej interakcji z modelami uczenia maszynowego w aplikacjach klasycznych języka C++ (Win32). Korzystając z trzech kroków ładowania, wiązania i oceniania, aplikacja może korzystać z możliwości uczenia maszynowego.
Utworzymy nieco uproszczoną wersję próbki wykrywania obiektów SqueezeNet, która jest dostępna w witrynie GitHub. Kompletny przykład możesz pobrać, jeśli chcesz zobaczyć, jak będzie wyglądać po zakończeniu.
Użyjemy języka C++/WinRT, aby uzyskać dostęp do interfejsów API WinML. Aby uzyskać więcej informacji, zobacz C++/WinRT .
W tym poradniku dowiesz się, jak:
- Ładowanie modelu uczenia maszynowego
- Załaduj obraz jako VideoFrame
- Wiązanie danych wejściowych i wyjściowych modelu
- Ocenianie modelu i drukowanie znaczących wyników
Wymagania wstępne
- Visual Studio 2019 (lub Visual Studio 2017 , wersja 15.7.4 lub nowsza)
- Windows 10, wersja 1809 lub nowsza
- Zestaw Windows SDK, kompilacja 17763 lub nowsza
- Rozszerzenie programu Visual Studio dla języka C++/WinRT
- W programie Visual Studio wybierz pozycję Rozszerzenia i aktualizacje narzędzi>.
- Wybierz pozycję Online w okienku po lewej stronie i wyszukaj ciąg "WinRT" przy użyciu pola wyszukiwania po prawej stronie.
- Wybierz pozycję C++/WinRT, kliknij pozycję Pobierz i zamknij program Visual Studio.
- Postępuj zgodnie z instrukcjami instalacji, a następnie ponownie otwórz program Visual Studio.
- Windows:Machine-Learning repozytorium na Githubie (możesz pobrać go jako plik ZIP lub sklonować na swój komputer)
Tworzenie projektu
Najpierw utworzymy projekt w programie Visual Studio:
- Wybierz pozycję Plik > Nowy > Projekt, aby otworzyć okno Nowy Projekt.
- W okienku po lewej stronie wybierz pozycję Zainstalowany > program Visual C++ > Windows Desktop, a w środku wybierz pozycję Aplikacja konsolowa systemu Windows (C++/WinRT).
- Nadaj projektowi nazwę i lokalizację, a następnie kliknij przycisk OK.
- W oknie Nowy projekt platformy uniwersalnej systemu Windows ustaw wartość docelową i minimalną wersje na kompilację 17763 lub nowszą, a następnie kliknij przycisk OK.
- Upewnij się, że menu rozwijane na górnym pasku narzędzi są ustawione na Debugowanie i x64 lub x86 w zależności od architektury komputera.
- Naciśnij Ctrl+F5 , aby uruchomić program bez debugowania. Terminal powinien zostać otwarty z tekstem "Hello world". Naciśnij dowolny klawisz, aby go zamknąć.
Ładowanie modelu
Następnie załadujemy model ONNX do naszego programu przy użyciu metody LearningModel.LoadFromFilePath:
W pliku pch.h (w folderze Pliki nagłówka ) dodaj następujące
includeinstrukcje (umożliwiają one dostęp do wszystkich potrzebnych interfejsów API):#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>W main.cpp (w folderze Pliki źródłowe ) dodaj następujące
usinginstrukcje: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;Dodaj następujące deklaracje zmiennych po instrukcjach
using:// 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;Dodaj następujące deklaracje wyprzedzające po twoich zmiennych globalnych.
// Forward declarations void LoadModel(); VideoFrame LoadImageFile(hstring filePath); void BindModel(); void EvaluateModel(); void PrintResults(IVectorView<float> results); void LoadLabels();W main.cpp usuń kod "Hello world" (wszystko po
mainw funkcjiinit_apartment).Znajdź plik SqueezeNet.onnx w lokalnym klonie repozytorium Windows-Machine-Learning . Powinien on znajdować się w folderze \Windows-Machine-Learning\SharedContent\models.
Skopiuj ścieżkę pliku i przypisz ją do
modelPathzmiennej, w której ją zdefiniowaliśmy u góry. Pamiętaj, aby poprzedzić ciąg ciągiemL, aby był on ciągiem znaków szeroki, tak aby działał prawidłowo z elementemhstring, i aby uniknąć ukośników odwrotnych (\) z dodatkowym ukośnikiem odwrotnym. Przykład:hstring modelPath = L"C:\\Repos\\Windows-Machine-Learning\\SharedContent\\models\\SqueezeNet.onnx";Najpierw zaimplementujemy metodę
LoadModel. Dodaj następującą metodę po metodziemain. Ta metoda ładuje model i podaje, jak długo to trwało: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); }Na koniec wywołaj tę metodę z
mainmetody :LoadModel();Uruchom program bez debugowania. Powinien zostać wyświetlony komunikat o pomyślnym załadowaniu modelu.
Ładowanie obrazu
Następnie załadujemy plik obrazu do naszego programu:
Dodaj następującą metodę. Ta metoda załaduje obraz z podanej ścieżki i utworzy z niej ramkę wideo :
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; }Dodaj wywołanie do tej metody w metodzie
main:imageFrame = LoadImageFile(imagePath);Znajdź folder multimedialny w lokalnym klonie repozytorium Windows-Machine-Learning . Powinien on znajdować się w folderze \Windows-Machine-Learning\SharedContent\media.
Wybierz jeden z obrazów w tym folderze i przypisz jego ścieżkę pliku do
imagePathzmiennej, w której ją zdefiniowaliśmy u góry. Pamiętaj, aby poprzedzić go znakiem ,Laby był on ciągiem znaków szeroki i aby uniknąć ukośników odwrotnych za pomocą innego ukośnika odwrotnego. Przykład:hstring imagePath = L"C:\\Repos\\Windows-Machine-Learning\\SharedContent\\media\\kitten_224.png";Uruchom program bez debugowania. Powinieneś zobaczyć, że obraz został pomyślnie załadowany!
Wiązanie danych wejściowych i wyjściowych
Następnie utworzymy sesję na podstawie modelu i powiążemy dane wejściowe i wyjściowe z sesji przy użyciu elementu LearningModelBinding.Bind. Aby uzyskać więcej informacji na temat powiązania, zobacz Wiązanie modelu.
Zaimplementuj metodę
BindModel. Spowoduje to utworzenie sesji na podstawie modelu i urządzenia oraz powiązania na podstawie tej sesji. Następnie powiążemy dane wejściowe i wyjściowe ze zmiennymi utworzonymi przy użyciu ich nazw. Z wyprzedzeniem wiemy, że funkcja wprowadzania nosi nazwę "data_0", a funkcja danych wyjściowych nosi nazwę "softmaxout_1". Te właściwości można wyświetlić dla dowolnego modelu, otwierając je w narzędziu Netron do wizualizacji modelu 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); }Dodaj wywołanie do
BindModelz metodymain.BindModel();Uruchom program bez debugowania. Dane wejściowe i wyjściowe modelu powinny zostać pomyślnie powiązane. Jesteśmy prawie tam!
Ocena modelu
Jesteśmy teraz w ostatnim kroku na diagramie na początku tego samouczka Evaluate. Ocenimy model przy użyciu modelu LearningModelSession.Evaluate:
Zaimplementuj metodę
EvaluateModel. Ta metoda pobiera sesję i ocenia ją przy użyciu powiązania i identyfikatora korelacji. Identyfikator korelacji to coś, czego moglibyśmy użyć później, aby dopasować określone wywołanie oceny do wyników wyjściowych. Ponownie wiemy wcześniej, że nazwa danych wyjściowych to "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); }Teraz zaimplementujmy
PrintResults. Ta metoda pobiera trzy pierwsze prawdopodobieństwa dla tego, jaki obiekt może znajdować się na obrazie, i drukuje je: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]); } }Musimy również zaimplementować metodę
LoadLabels. Ta metoda otwiera plik etykiet, który zawiera wszystkie różne obiekty, które model może rozpoznać, i analizuje go: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; } }Znajdź plik Labels.txt w lokalnym klonie repozytorium Windows-Machine-Learning . Powinien on znajdować się w folderze \Windows-Machine-Learning\Samples\SqueezeNetObjectDetection\Desktop\cpp.
Przypisz tę ścieżkę pliku do zmiennej
labelsFilePath, w której ją zdefiniowaliśmy u góry. Pamiętaj, aby uniknąć ukośników odwrotnych z innym ukośnikiem odwrotnym. Przykład:string labelsFilePath = "C:\\Repos\\Windows-Machine-Learning\\Samples\\SqueezeNetObjectDetection\\Desktop\\cpp\\Labels.txt";Dodaj wywołanie metody
EvaluateModelw metodziemain:EvaluateModel();Uruchom program bez debugowania. Powinna ona teraz poprawnie rozpoznać zawartość obrazu! Oto przykład danych wyjściowych:
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
Dalsze kroki
Hurra, udało się uruchomić działające wykrywanie obiektów w aplikacji na komputer C++! Następnie możesz spróbować użyć argumentów wiersza polecenia, aby wprowadzić pliki modelu i obrazu zamiast zakodowywać je na stałe, podobnie jak w przypadku przykładu na GitHubie. Możesz również spróbować uruchomić ocenę na innym urządzeniu, jak procesor GPU, aby zobaczyć, jak różni się wydajność.
Pobaw się z innymi przykładami na GitHubie i rozszerz je tak, jak chcesz!
Zobacz także
- Przykłady uczenia maszynowego systemu Windows (GitHub)
- Przestrzeń nazw Windows.AI.MachineLearning
- Język maszynowy dla systemu Windows
Uwaga / Notatka
Skorzystaj z następujących zasobów, aby uzyskać pomoc dotyczącą uczenia maszynowego z systemem Windows:
- Aby zadać lub odpowiedzieć na pytania techniczne dotyczące uczenia maszynowego z systemem Windows, użyj tagu windows-machine-learning w witrynie Stack Overflow.
- Aby zgłosić usterkę, popełnij zgłoszenie na GitHubie .