Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
O Windows ML suporta carga de alto desempenho e execução de cadeias de modelos otimizando cuidadosamente seu caminho de GPU. As cadeias de modelos são definidas por dois ou mais modelos que são executados sequencialmente, onde as saídas de um modelo se tornam as entradas para o próximo modelo ao longo da cadeia.
Para explicar como encadear modelos de forma eficiente com o Windows ML, vamos usar um modelo ONNX de transferência de estilo FNS-Candy como um exemplo simplificado. Você pode encontrar esse tipo de modelo na pasta de exemplo FNS-Candy Style Transfer em nosso GitHub.
Digamos que queremos executar uma cadeia que é composta por duas instâncias do mesmo modelo FNS-Candy, aqui chamado mosaic.onnx. O código do aplicativo passaria uma imagem para o primeiro modelo da cadeia, deixaria ele calcular as saídas e, em seguida, passaria essa imagem transformada para outra instância do FNS-Candy, produzindo uma imagem final.
As etapas a seguir ilustram como fazer isso usando o Windows ML.
Observação
Em um cenário de palavras reais, você provavelmente usaria dois modelos diferentes, mas isso deve ser suficiente para ilustrar os conceitos.
- Primeiro, vamos carregar o modelo mosaic.onnx para que possamos usá-lo.
std::wstring filePath = L"path\\to\\mosaic.onnx";
LearningModel model = LearningModel::LoadFromFilePath(filePath);
string filePath = "path\\to\\mosaic.onnx";
LearningModel model = LearningModel.LoadFromFilePath(filePath);
- Em seguida, vamos criar duas sessões idênticas na GPU padrão do dispositivo usando o mesmo modelo como parâmetro de entrada.
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));
Observação
Para colher os benefícios de desempenho do encadeamento, você precisa criar sessões de GPU idênticas para todos os seus modelos. Não fazer isso resultaria em movimentação de dados adicionais para fora da GPU e para a CPU, o que reduziria o desempenho.
- As seguintes linhas de código criarão associações para cada sessão:
LearningModelBinding binding1(session1);
LearningModelBinding binding2(session2);
LearningModelBinding binding1 = new LearningModelBinding(session1);
LearningModelBinding binding2 = new LearningModelBinding(session2);
- Em seguida, vincularemos uma entrada para o nosso primeiro modelo. Vamos passar uma imagem que está localizada no mesmo diretório que o nosso modelo. Neste exemplo, a imagem é chamada de "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");
}
- Para que o próximo modelo na cadeia use as saídas da avaliação do primeiro modelo, precisamos criar um tensor de saída vazio e ligar a saída para que tenhamos um marcador para encadear com:
//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);
Observação
Você deve usar o tipo de dados TensorFloat ao vincular a saída. Isso evitará que a destensorização ocorra assim que a avaliação do primeiro modelo for concluída, evitando também filas adicionais de GPU para operações de carga e ligação para o segundo modelo.
- Agora, executamos a avaliação do primeiro modelo e vinculamos suas saídas à entrada do próximo modelo:
//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, "");
- Finalmente, vamos recuperar a saída final produzida após a execução de ambos os modelos usando a seguinte linha de código.
auto finalOutput = session2AsyncOp.get().Outputs().First().Current().Value();
var finalOutput = results.Outputs.First().Value;
É isso! Ambos os modelos agora podem ser executados sequencialmente, aproveitando ao máximo os recursos de GPU disponíveis.
Observação
Use os seguintes recursos para obter ajuda com o Windows ML:
- Para fazer ou responder a perguntas técnicas sobre o Windows ML, use a tag windows-machine-learning no Stack Overflow.
- Para relatar um bug, registre um problema em nosso GitHub.