Dela via


Köra flera ML-modeller i en kedja

Windows ML stöder högpresterande belastning och körning av modellkedjor genom att noggrant optimera dess GPU-sökväg. Modellkedjor definieras av två eller flera modeller som körs sekventiellt, där utdata från en modell blir indata till nästa modell längre ned i kedjan.

För att förklara hur du effektivt kedjar modeller med Windows ML ska vi använda en FNS-Candy STYLE Transfer ONNX-modell som ett leksaksexempel. Du hittar den här typen av modell i exempelmappen FNS-Candy Style Transfer i vår GitHub.

Anta att vi vill köra en kedja som består av två instanser av samma FNS-Candy modell, som här kallas mosaic.onnx. Programkoden skickar en bild till den första modellen i kedjan, låter den beräkna utdata och skickar sedan den transformerade avbildningen till en annan instans av FNS-Candy, vilket ger en slutlig avbildning.

Följande steg visar hur du gör det med hjälp av Windows ML.

Anmärkning

I ett verkligt ordscenario skulle du förmodligen använda två olika modeller, men det bör vara tillräckligt för att illustrera begreppen.

  1. Först ska vi läsa in modellen mosaic.onnx så att vi kan använda den.
std::wstring filePath = L"path\\to\\mosaic.onnx"; 
LearningModel model = LearningModel::LoadFromFilePath(filePath);
string filePath = "path\\to\\mosaic.onnx";
LearningModel model = LearningModel.LoadFromFilePath(filePath);
  1. Sedan ska vi skapa två identiska sessioner på enhetens standard-GPU med samma modell som indataparametern.
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));

Anmärkning

För att kunna dra nytta av prestandafördelarna med länkning måste du skapa identiska GPU-sessioner för alla dina modeller. Om du inte gör det skulle det leda till ytterligare dataförflyttning från GPU:n och till processorn, vilket skulle minska prestandan.

  1. Följande kodrader skapar bindningar för varje session:
LearningModelBinding binding1(session1);
LearningModelBinding binding2(session2);
LearningModelBinding binding1 = new LearningModelBinding(session1);
LearningModelBinding binding2 = new LearningModelBinding(session2);
  1. Därefter binder vi indata för vår första modell. Vi skickar in en bild som finns i samma sökväg som vår modell. I det här exemplet kallas bilden "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");
}
  1. För att nästa modell i kedjan ska kunna använda utdata från utvärderingen av den första modellen måste vi skapa en tom utdata tensor och binda utdata så att vi har en markör att kedja med:
//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);

Anmärkning

Du måste använda Datatypen TensorFloat när du binder utdata. Detta förhindrar att de-tensorization inträffar när utvärderingen för den första modellen har slutförts, vilket också undviker ytterligare GPU-köer för belastnings- och bindningsåtgärder för den andra modellen.

  1. Nu kör vi utvärderingen av den första modellen och binder dess utdata till nästa modells indata:
//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, "");
  1. Slutligen hämtar vi de slutliga utdata som genereras efter att båda modellerna har körts med hjälp av följande kodrad.
auto finalOutput = session2AsyncOp.get().Outputs().First().Current().Value();
var finalOutput = results.Outputs.First().Value;

Det var allt! Båda modellerna kan nu köras sekventiellt genom att utnyttja de tillgängliga GPU-resurserna.

Anmärkning

Använd följande resurser för hjälp med Windows ML:

  • Om du vill ställa eller besvara tekniska frågor om Windows ML använder du taggen windows-machine-learningStack Overflow-.
  • Om du vill rapportera en bugg, skicka in en felrapport på vår GitHub-sida .