Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O Windows ML dá suporte à 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, em que as saídas de um modelo se tornam as entradas para o próximo modelo na cadeia.
Para explicar como encadear modelos com eficiência usando o Windows ML, vamos usar um modelo de ONNX de transferência de estilo FNS-Candy como um exemplo. Você pode encontrar esse tipo de modelo na pasta de exemplo de Transferência de Estilo FNS-Candy em nosso GitHub.
Digamos que queremos executar uma cadeia composta por duas instâncias do mesmo modelo de FNS-Candy, aqui chamada mosaic.onnx. O código do aplicativo passaria uma imagem para o primeiro modelo da cadeia, permitiria computar 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 palavra real, você provavelmente usaria dois modelos diferentes, mas isso deve ser suficiente para ilustrar os conceitos.
- Primeiro, vamos carregar o modelo mosaico.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 que o 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, associaremos uma entrada para nosso primeiro modelo. Passaremos uma imagem que está localizada no mesmo caminho 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 associar 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 associar a saída. Isso impedirá que a des tensorização ocorra depois que a avaliação do primeiro modelo for concluída, evitando também filas de GPU adicionais para operações de carga e associação para o segundo modelo.
- Agora, executamos a avaliação do primeiro modelo e associamos 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, "");
- Por fim, vamos recuperar a saída final produzida depois de executar 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! Os dois 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 perguntas ou responder a perguntas técnicas sobre o Windows ML, use a marca windows-machine-learning no Stack Overflow.
- Para relatar um bug, registre um problema em nosso GitHub.