Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Windows ML поддерживает высокопроизводительную нагрузку и выполнение цепочек моделей, тщательно оптимизируя путь к GPU. Цепочки моделей определяются двумя или более моделями, которые выполняются последовательно, где выходные данные одной модели становятся входными данными для следующей модели вниз по цепочке.
Чтобы объяснить, как эффективно связывать модели с помощью Windows ML, давайте используем модель FNS-Candy Style Transfer ONNX в качестве игрушечного примера. Этот тип модели можно найти в папке FNS-Candy Style Transfer в нашем GitHub.
Предположим, что мы хотим выполнить цепочку, состоящую из двух экземпляров одной и той же модели FNS-Candy, здесь называется mosaic.onnx. Код приложения передает изображение первой модели в цепочке, позволяет вычислить выходные данные, а затем передать преобразованное изображение другому экземпляру FNS-Candy, создав окончательный образ.
Ниже показано, как сделать это с помощью Windows ML.
Замечание
В реальном сценарии слова вы, скорее всего, будете использовать две разные модели, но это должно быть достаточно, чтобы проиллюстрировать концепции.
- Сначала давайте загрузим модель mosaic.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 в центральный процессор, что приведет к снижению производительности.
- Следующие строки кода создают привязки для каждого сеанса:
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;
Вот и все! Оба ваших модели теперь могут выполняться последовательно, максимально эффективно используя доступные ресурсы графического процессора.
Замечание
Используйте следующие ресурсы, чтобы получить помощь по Windows ML.
- Чтобы задать или ответить на технические вопросы о Windows ML, используйте тег windows-machine-learning в Stack Overflow.
- Чтобы сообщить об ошибке, отправьте сообщение о проблеме на сайте GitHub.