在鏈結中執行多個 ML 模型
Windows ML 透過仔細優化其 GPU 路徑,支援高效能載入和執行模型鏈結。 模型鏈結是由循序執行的兩個或多個模型所定義,其中一個模型的輸出會成為鏈結下一個模型的輸入。
為了說明如何使用 Windows ML 有效率地鏈結模型,讓我們使用FNS-Candy樣式傳送 ONNX 模型作為 Toy 範例。 您可以在 GitHub的 [FNS-Candy樣式傳輸範例] 資料夾中找到這種類型的模型。
假設我們想要執行鏈結,此鏈結是由相同FNS-Candy模型的兩個實例所組成,稱為 FNS-Candy.onnx。 應用程式程式碼會將影像傳遞至鏈結中的第一個模型,讓它計算輸出,然後將該轉換的影像傳遞至另一個 FNS-Candy 實例,產生最終影像。
下列步驟說明如何使用 Windows ML 來完成該作業。
注意
在真實字組案例中,您最有可能使用兩個不同的模型,但這應該足以說明概念。
- 首先,讓我們載入 .onnx 模型,讓我們可以使用它。
std::wstring filePath = L"path\\to\\mosaic.onnx";
LearningModel model = LearningModel::LoadFromFilePath(filePath);
string filePath = "path\\to\\mosaic.onnx";
LearningModel model = LearningModel.LoadFromFilePath(filePath);
- 然後,讓我們使用與輸入參數相同的模型,在裝置的預設 GPU 上建立兩個相同的會話。
LearningModelSession session1(model, LearningModelDevice(LearningModelDeviceKind::DirectX));
LearningModelSession session2(model, LearningModelDevice(LearningModelDeviceKind::DirectX));
LearningModelSession session1 =
new LearningModelSession(model, new LearningModelDevice(LearningModelDeviceKind.DirectX));
LearningModelSession session2 =
new LearningModelSession(model, new LearningModelDevice(LearningModelDeviceKind.DirectX));
注意
若要獲得鏈結的效能優勢,您必須為所有模型建立相同的 GPU 會話。 不這麼做會導致額外的資料從 GPU 移出並移入 CPU,進而降低效能。
- 下列幾行程式碼會為每個會話建立系結:
LearningModelBinding binding1(session1);
LearningModelBinding binding2(session2);
LearningModelBinding binding1 = new LearningModelBinding(session1);
LearningModelBinding binding2 = new LearningModelBinding(session2);
- 接下來,我們會系結第一個模型的輸入。 我們會傳入位於模型相同路徑的影像。 在此範例中,映射稱為「fish_720.png」。
//get the input descriptor
ILearningModelFeatureDescriptor input = model.InputFeatures().GetAt(0);
//load a SoftwareBitmap
hstring imagePath = L"path\\to\\fish_720.png";
// Get the image and bind it to the model's input
try
{
StorageFile file = StorageFile::GetFileFromPathAsync(imagePath).get();
IRandomAccessStream stream = file.OpenAsync(FileAccessMode::Read).get();
BitmapDecoder decoder = BitmapDecoder::CreateAsync(stream).get();
SoftwareBitmap softwareBitmap = decoder.GetSoftwareBitmapAsync().get();
VideoFrame videoFrame = VideoFrame::CreateWithSoftwareBitmap(softwareBitmap);
ImageFeatureValue image = ImageFeatureValue::CreateFromVideoFrame(videoFrame);
binding1.Bind(input.Name(), image);
}
catch (...)
{
printf("Failed to load/bind image\n");
}
//get the input descriptor
ILearningModelFeatureDescriptor input = model.InputFeatures[0];
//load a SoftwareBitmap
string imagePath = "path\\to\\fish_720.png";
// Get the image and bind it to the model's input
try
{
StorageFile file = await StorageFile.GetFileFromPathAsync(imagePath);
IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
SoftwareBitmap softwareBitmap = await decoder.GetSoftwareBitmapAsync();
VideoFrame videoFrame = VideoFrame.CreateWithSoftwareBitmap(softwareBitmap);
ImageFeatureValue image = ImageFeatureValue.CreateFromVideoFrame(videoFrame);
binding1.Bind(input.Name, image);
}
catch
{
Console.WriteLine("Failed to load/bind image");
}
- 為了讓鏈結中的下一個模型使用第一個模型的評估輸出,我們需要建立空的輸出張量並系結輸出,以便我們有要鏈結的標記:
//get the output descriptor
ILearningModelFeatureDescriptor output = model.OutputFeatures().GetAt(0);
//create an empty output tensor
std::vector<int64_t> shape = {1, 3, 720, 720};
TensorFloat outputValue = TensorFloat::Create(shape);
//bind the (empty) output
binding1.Bind(output.Name(), outputValue);
//get the output descriptor
ILearningModelFeatureDescriptor output = model.OutputFeatures[0];
//create an empty output tensor
List<long> shape = new List<long> { 1, 3, 720, 720 };
TensorFloat outputValue = TensorFloat.Create(shape);
//bind the (empty) output
binding1.Bind(output.Name, outputValue);
注意
系結輸出時,您必須使用 TensorFloat 資料類型。 這可防止在完成第一個模型的評估後發生解除張量,因此也避免針對第二個模型的載入和系結作業進行額外的 GPU 佇列。
- 現在,我們會執行第一個模型的評估,並將其輸出系結至下一個模型的輸入:
//run session1 evaluation
session1.EvaluateAsync(binding1, L"");
//bind the output to the next model input
binding2.Bind(input.Name(), outputValue);
//run session2 evaluation
auto session2AsyncOp = session2.EvaluateAsync(binding2, L"");
//run session1 evaluation
await session1.EvaluateAsync(binding1, "");
//bind the output to the next model input
binding2.Bind(input.Name, outputValue);
//run session2 evaluation
LearningModelEvaluationResult results = await session2.EvaluateAsync(binding2, "");
- 最後,讓我們使用下列程式程式碼來擷取執行這兩個模型之後所產生的最終輸出。
auto finalOutput = session2AsyncOp.get().Outputs().First().Current().Value();
var finalOutput = results.Outputs.First().Value;
就這麼簡單! 這兩個模型現在都可以藉由充分利用可用的 GPU 資源,以循序執行。
注意
使用下列資源取得 Windows ML 的說明:
- 如需詢問或回答有關 Windows ML 的技術問題,請使用 Stack Overflow 上的 windows-machine-learning 標籤。
- 如需回報錯誤 (bug),請在 GitHub 上提出問題。