#include "testPch.h" #include "filehelpers.h" #include "imageTestHelper.h" #include "robuffer.h" #include #include #include #include #ifndef BUILD_GOOGLE_TEST #error Must use googletest for value-parameterized tests #endif using namespace winrt; using namespace winml; using namespace wfc; using namespace wm; using namespace wgi; using namespace wgdx; using namespace ws; using namespace wss; enum BindingLocation { CPU, GPU }; class ImageTests : public ::testing::Test { protected: winml::LearningModel m_model = nullptr; winml::LearningModelDevice m_device = nullptr; winml::LearningModelSession m_session = nullptr; winml::LearningModelBinding m_model_binding = nullptr; winml::LearningModelEvaluationResult m_result = nullptr; static void SetUpTestSuite() { init_apartment(); #ifdef BUILD_INBOX winrt_activation_handler = WINRT_RoGetActivationFactory; #endif } void LoadModel(const std::wstring& model_path) { std::wstring full_path = FileHelpers::GetModulePath() + model_path; WINML_EXPECT_NO_THROW(m_model = LearningModel::LoadFromFilePath(full_path)); } void ImageTests::PrepareModelSessionBinding( const std::wstring& model_file_name, LearningModelDeviceKind device_kind, std::optional optimized_batch_size) { LoadModel(std::wstring(model_file_name)); WINML_EXPECT_NO_THROW(m_device = LearningModelDevice(device_kind)); if (optimized_batch_size.has_value()) { LearningModelSessionOptions options; options.BatchSizeOverride(optimized_batch_size.value()); WINML_EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device, options)); } else { WINML_EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device)); } WINML_EXPECT_NO_THROW(m_model_binding = LearningModelBinding(m_session)); } bool BindInputValue( const std::wstring& image_file_name, const std::wstring& input_pixel_format, const std::wstring& model_pixel_format, InputImageSource input_image_source, LearningModelDeviceKind device_kind ) { std::wstring full_image_path = FileHelpers::GetModulePath() + image_file_name; StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); BitmapDecoder bitmap_decoder = BitmapDecoder::CreateAsync(stream).get(); SoftwareBitmap software_bitmap = bitmap_decoder.GetSoftwareBitmapAsync().get(); // Convert the input image to PixelFormat specified software_bitmap = SoftwareBitmap::Convert( software_bitmap, ImageTestHelper::GetPixelFormat(input_pixel_format)); auto input_feature = m_model.InputFeatures().First(); if (InputImageSource::FromImageFeatureValue == input_image_source) { VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); ImageFeatureValue image_input_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature.Current().Name(), image_input_tensor)); } else if (InputImageSource::FromVideoFrame == input_image_source) { VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature.Current().Name(), frame)); } else if (InputImageSource::FromCPUResource == input_image_source) { TensorFloat tensor_float = ImageTestHelper::LoadInputImageFromCPU(software_bitmap, model_pixel_format); WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature.Current().Name(), tensor_float)); } else if (InputImageSource::FromGPUResource == input_image_source) { TensorFloat tensor_float = ImageTestHelper::LoadInputImageFromGPU(software_bitmap, model_pixel_format); if (LearningModelDeviceKind::Cpu == device_kind) { WINML_EXPECT_THROW_SPECIFIC(m_model_binding.Bind(input_feature.Current().Name(), tensor_float), winrt::hresult_error, [](const winrt::hresult_error& e) -> bool { return e.code() == WINML_ERR_INVALID_BINDING; }); return false; } WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature.Current().Name(), tensor_float)); } return true; } VideoFrame BindImageOutput( ModelInputOutputType model_input_output_type, OutputBindingStrategy output_binding_strategy, const std::wstring& model_pixel_format) { std::wstring output_data_binding_name = std::wstring(m_model.OutputFeatures().First().Current().Name()); VideoFrame frame = nullptr; if (OutputBindingStrategy::Bound == output_binding_strategy) { if (ModelInputOutputType::Image == model_input_output_type) { ImageFeatureDescriptor output_image_descriptor = nullptr; WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(output_image_descriptor)); SoftwareBitmap bitmap( ImageTestHelper::GetPixelFormat(model_pixel_format), output_image_descriptor.Height(), output_image_descriptor.Width()); frame = VideoFrame::CreateWithSoftwareBitmap(bitmap); } else if (ModelInputOutputType::Tensor == model_input_output_type) { TensorFeatureDescriptor output_tensor_descriptor = nullptr; WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(output_tensor_descriptor)); auto output_tensor_shape = output_tensor_descriptor.Shape(); SoftwareBitmap bitmap( ImageTestHelper::GetPixelFormat(model_pixel_format), static_cast(output_tensor_shape.GetAt(3)), static_cast(output_tensor_shape.GetAt(2))); frame = VideoFrame::CreateWithSoftwareBitmap(bitmap); } auto output_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); WINML_EXPECT_NO_THROW(m_model_binding.Bind(output_data_binding_name, output_tensor)); } // Else for Unbound return frame; } IVector BindImageOutput( ModelInputOutputType model_input_output_type, OutputBindingStrategy output_binding_strategy, VideoFrameSource output_video_frame_source, const std::wstring& model_pixel_format, const uint32_t& batch_size) { std::wstring output_data_binding_name = std::wstring(m_model.OutputFeatures().First().Current().Name()); uint32_t width = 0, height = 0; if (ModelInputOutputType::Image == model_input_output_type) { ImageFeatureDescriptor output_image_descriptor = nullptr; WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(output_image_descriptor)); width = output_image_descriptor.Width(); height = output_image_descriptor.Height(); } else { TensorFeatureDescriptor output_tensor_descriptor = nullptr; WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(output_tensor_descriptor)); auto output_tensor_shape = output_tensor_descriptor.Shape(); width = static_cast(output_tensor_shape.GetAt(3)); height = static_cast(output_tensor_shape.GetAt(2)); } IVector output_video_frames; if (OutputBindingStrategy::Bound == output_binding_strategy) { std::vector output_frames = {}; for (uint32_t i = 0; i < batch_size; ++i) { VideoFrame video_frame = nullptr; if (VideoFrameSource::FromSoftwareBitmap == output_video_frame_source) { video_frame = VideoFrame::CreateWithSoftwareBitmap(SoftwareBitmap(ImageTestHelper::GetPixelFormat(model_pixel_format), width, height)); } else if (VideoFrameSource::FromDirect3DSurface == output_video_frame_source) { video_frame = VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8A8UIntNormalized, width, height); } else if (VideoFrameSource::FromUnsupportedD3DSurface == output_video_frame_source) { video_frame = VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8X8UIntNormalized, width, height); } output_frames.emplace_back(video_frame); } output_video_frames = winrt::single_threaded_vector(std::move(output_frames)); WINML_EXPECT_NO_THROW(m_model_binding.Bind(output_data_binding_name, output_video_frames)); } // Else for Unbound return output_video_frames; } void VerifyResults( VideoFrame output_tensor, const std::wstring& bm_image_path, const std::wstring& model_pixel_format) { SoftwareBitmap bm_software_bitmap = FileHelpers::GetSoftwareBitmapFromFile(bm_image_path); bm_software_bitmap = SoftwareBitmap::Convert( bm_software_bitmap, ImageTestHelper::GetPixelFormat(model_pixel_format)); VideoFrame bm_video_frame = VideoFrame::CreateWithSoftwareBitmap(bm_software_bitmap); WINML_EXPECT_TRUE(ImageTestHelper::VerifyHelper(output_tensor, bm_video_frame)); } void EvaluateTest(EvaluationStrategy strategy) { if (EvaluationStrategy::Async == strategy) { WINML_EXPECT_NO_THROW(m_result = m_session.EvaluateAsync(m_model_binding, L"").get()); } else if (EvaluationStrategy::Sync == strategy) { WINML_EXPECT_NO_THROW(m_result = m_session.Evaluate(m_model_binding, L"")); } } bool ShouldSkip( const std::wstring& model_file_name, const std::wstring& image_file_name, const InputImageSource input_image_source ) { // Case that the tensor's shape doesn't match model's shape should be skiped if ((L"1080.jpg" == image_file_name || L"kitten_224.png" == image_file_name) && (InputImageSource::FromGPUResource == input_image_source || InputImageSource::FromCPUResource == input_image_source)) { return true; } // Case that the images's shape doesn't match model's shape which expects free dimension should be skiped. // Because the fns-candy is not real model that can handle free dimensional input if ((L"1080.jpg" == image_file_name || L"kitten_224.png" == image_file_name) && L"fns-candy_Bgr8_freeDimInput.onnx" == model_file_name) { return true; } return false; } void ValidateOutputImageMetaData(const std::wstring& path, BitmapAlphaMode expected_mode, BitmapPixelFormat expected_format, bool supported) { WINML_EXPECT_NO_THROW(LoadModel(path)); //input does not have image metadata and output does WINML_EXPECT_TRUE(m_model.OutputFeatures().First().HasCurrent()); std::wstring name(m_model.OutputFeatures().First().Current().Name()); std::wstring expected_tensor_name = L"add_3"; WINML_EXPECT_EQUAL(name, expected_tensor_name); ImageFeatureDescriptor image_descriptor = nullptr; if (supported) { WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(image_descriptor)); WINML_EXPECT_TRUE(image_descriptor != nullptr); auto tensor_name = image_descriptor.Name(); WINML_EXPECT_EQUAL(tensor_name, expected_tensor_name); auto model_data_kind = image_descriptor.Kind(); WINML_EXPECT_EQUAL(model_data_kind, LearningModelFeatureKind::Image); WINML_EXPECT_TRUE(image_descriptor.IsRequired()); WINML_EXPECT_EQUAL(image_descriptor.Width(), 1920u); WINML_EXPECT_EQUAL(image_descriptor.Height(), 1080u); WINML_EXPECT_EQUAL(image_descriptor.BitmapAlphaMode(), expected_mode); WINML_EXPECT_EQUAL(image_descriptor.BitmapPixelFormat(), expected_format); } else { //not an image descriptor. a regular tensor WINML_EXPECT_THROW_SPECIFIC(m_model.OutputFeatures().First().Current().as(image_descriptor), winrt::hresult_no_interface , [](const winrt::hresult_no_interface& e) -> bool { return e.code() == E_NOINTERFACE; }); TensorFeatureDescriptor tensor_descriptor = nullptr; WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(tensor_descriptor)); // Make sure we fail binding ImageFeatureValue LearningModelSession session(m_model); LearningModelBinding binding(session); auto ifv = FileHelpers::LoadImageFeatureValue(L"1080.jpg"); WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"add_3", ifv), winrt::hresult_error, [](const winrt::hresult_error& e) -> bool { return e.code() == WINML_ERR_INVALID_BINDING; } ); } } void RunConsecutiveImageBindingOnGpu(ImageFeatureValue & image1, ImageFeatureValue & image2) { static const wchar_t* model_file_name = L"Add_ImageNet1920.onnx"; std::wstring module_path = FileHelpers::GetModulePath(); // WinML model creation LearningModel model(nullptr); std::wstring full_model_path = module_path + model_file_name; WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); LearningModelDeviceKind device_kind = LearningModelDeviceKind::DirectX; LearningModelSession model_session(model, LearningModelDevice(device_kind)); LearningModelBinding model_binding(model_session); //Input Binding auto feature = model.InputFeatures().First(); WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), image1)); feature.MoveNext(); WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), image2)); } static ImageFeatureValue CreateImageFeatureValue(const std::wstring& full_image_path) { StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); ImageFeatureValue image_input_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); return image_input_tensor; } }; // MNIST model expects 28x28 data with class MnistImageTest : public ImageTests, public testing::WithParamInterface> {}; TEST_P(MnistImageTest, Evaluates) { GPUTEST; PrepareModelSessionBinding(L"mnist.onnx", LearningModelDeviceKind::Cpu, std::nullopt); std::wstring filename; unsigned int label; std::tie(filename, label) = GetParam(); auto image_feature_value = FileHelpers::LoadImageFeatureValue(std::wstring(filename)); m_model_binding.Bind(L"Input3", image_feature_value); auto result = m_session.EvaluateAsync(m_model_binding, L"0").get(); auto vector = result.Outputs().Lookup(L"Plus214_Output_0").as().GetAsVectorView(); unsigned int max_label = 0; float max_val = 0; for (unsigned int i = 0; i < vector.Size(); ++i) { float val = vector.GetAt(i); if (val > max_val) { max_val = val; max_label = i; } } std::cerr << "Expected Label " << label; std::cerr << "Evaluated Label " << max_label; WINML_EXPECT_TRUE(max_label == label); } INSTANTIATE_TEST_SUITE_P(MnistInputOutput, MnistImageTest, testing::Values( std::make_pair(L"vertical-crop.png", 5), std::make_pair(L"horizontal-crop.png", 2), std::make_pair(L"big.png", 8), std::make_pair(L"RGB_5.png", 5) )); #if defined(NDEBUG) || defined(RUN_MODELTEST_IN_DEBUG_MODE) typedef std::tuple, std::wstring, std::wstring, InputImageSource, EvaluationStrategy, OutputBindingStrategy, LearningModelDeviceKind> ImageTestParamTuple; struct ImageTestParam { std::wstring model_file_name, model_pixel_format, image_file_name, input_pixel_format; ModelInputOutputType model_input_output_type; InputImageSource input_image_source; EvaluationStrategy evaluation_strategy; OutputBindingStrategy output_binding_strategy; LearningModelDeviceKind device_kind; ImageTestParam(ImageTestParamTuple param) { std::tuple model_info; tie(model_info, image_file_name, input_pixel_format, input_image_source, evaluation_strategy, output_binding_strategy, device_kind) = param; tie(model_file_name, model_input_output_type, model_pixel_format) = model_info; } }; class ImageTest : public ImageTests, public testing::WithParamInterface {}; TEST_P(ImageTest, ImageTest) { const auto param = ImageTestParam(GetParam()); if (ShouldSkip(param.model_file_name, param.image_file_name, param.input_image_source)) { GTEST_SKIP() << "This test is disabled"; } if (LearningModelDeviceKind::Cpu != param.device_kind || InputImageSource::FromGPUResource == param.input_image_source) { GPUTEST; } PrepareModelSessionBinding(param.model_file_name, param.device_kind, {}); bool toContinue = BindInputValue( param.image_file_name, param.input_pixel_format, param.model_pixel_format, param.input_image_source, param.device_kind); if (!toContinue) return; VideoFrame output_video_frame = BindImageOutput( param.model_input_output_type, param.output_binding_strategy, std::wstring(param.model_pixel_format)); EvaluateTest(param.evaluation_strategy); // benchmark used to compare with the output from model std::wstring benchmark_file_name = std::wstring( param.model_pixel_format + L'_' + param.input_pixel_format + L'_' + param.image_file_name); // Verify the output by comparing with the benchmark image std::wstring bm_image_path = FileHelpers::GetModulePath() + L"groundTruth\\" + benchmark_file_name; if (OutputBindingStrategy::Unbound == param.output_binding_strategy) { std::wstring output_data_binding_name = std::wstring(m_model.OutputFeatures().First().Current().Name()); auto image_FV = m_result.Outputs().Lookup(output_data_binding_name).try_as(); if (image_FV == nullptr) { return; } output_video_frame = image_FV.VideoFrame(); } VerifyResults(output_video_frame, bm_image_path, param.model_pixel_format); } INSTANTIATE_TEST_SUITE_P(ImageTest, ImageTest, testing::Combine( testing::Values( std::make_tuple(L"fns-candy_Bgr8.onnx", Image, L"Bgr8"), std::make_tuple(L"fns-candy_Rgb8.onnx", Image, L"Rgb8"), std::make_tuple(L"fns-candy_tensor.onnx", Tensor, L"Bgr8"), std::make_tuple(L"fns-candy_Bgr8_freeDimInput.onnx", Image, L"Bgr8")), testing::Values(L"1080.jpg", L"kitten_224.png", L"fish_720.png", L"fish_720_Gray.png"), testing::Values(L"Bgra8", L"Rgba8", L"Gray8"), testing::Values(FromVideoFrame, FromImageFeatureValue, FromCPUResource, FromGPUResource), testing::Values(Async, Sync), testing::Values(Bound, Unbound), testing::Values(LearningModelDeviceKind::DirectX, LearningModelDeviceKind::Cpu) )); typedef std::tuple, int, bool>, OutputBindingStrategy, EvaluationStrategy, VideoFrameSource, VideoFrameSource, LearningModelDeviceKind> BatchTestParamTuple; struct BatchTestParam { std::wstring model_file_name, model_pixel_format, image_file_name, input_pixel_format; ModelInputOutputType model_input_output_type; std::vector input_images; int batch_size; bool use_session_options; OutputBindingStrategy output_binding_strategy; EvaluationStrategy evaluation_strategy; VideoFrameSource video_frame_source, output_video_frame_source; LearningModelDeviceKind device_kind; BatchTestParam(BatchTestParamTuple param) { std::tuple, int, bool> model_info; tie(model_info, output_binding_strategy, evaluation_strategy, video_frame_source, output_video_frame_source, device_kind) = param; tie(model_file_name, model_input_output_type, input_images, batch_size, use_session_options) = model_info; } }; class BatchTest : public ImageTests, public testing::WithParamInterface {}; TEST_P(BatchTest, BatchSupport) { const auto param = BatchTestParam(GetParam()); std::optional optimized_batch_size; if (param.use_session_options) { optimized_batch_size = param.use_session_options; } if (VideoFrameSource::FromDirect3DSurface == param.video_frame_source && LearningModelDeviceKind::Cpu == param.device_kind) { return; } if (LearningModelDeviceKind::Cpu != param.device_kind || VideoFrameSource::FromDirect3DSurface == param.video_frame_source || VideoFrameSource::FromDirect3DSurface == param.output_video_frame_source || VideoFrameSource::FromUnsupportedD3DSurface == param.output_video_frame_source) { GPUTEST; } // create model, device and session PrepareModelSessionBinding(param.model_file_name, param.device_kind, optimized_batch_size); // create the input video_frames std::vector input_frames = {}; if (param.input_images.empty()) { for (int i = 0; i < param.batch_size; ++i) { if (VideoFrameSource::FromDirect3DSurface == param.video_frame_source) { VideoFrame video_frame = VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8X8UIntNormalized, 720, 720); input_frames.emplace_back(video_frame); } else { VideoFrame video_frame = VideoFrame::CreateWithSoftwareBitmap(SoftwareBitmap(BitmapPixelFormat::Bgra8, 720, 720)); input_frames.emplace_back(video_frame); } } } else { for (int i = 0; i < param.batch_size; ++i) { std::wstring full_image_path = FileHelpers::GetModulePath() + param.input_images[i]; StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); if (VideoFrameSource::FromDirect3DSurface == param.video_frame_source) { uint32_t width = software_bitmap.PixelWidth(); uint32_t height = software_bitmap.PixelHeight(); auto D3D_video_frame = VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8X8UIntNormalized, width, height); frame.CopyToAsync(D3D_video_frame); input_frames.emplace_back(D3D_video_frame); } else { input_frames.emplace_back(frame); } } } auto video_frames = winrt::single_threaded_vector(std::move(input_frames)); auto input_feature_descriptor = m_model.InputFeatures().First(); WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature_descriptor.Current().Name(), video_frames)); auto output_video_frames = BindImageOutput( param.model_input_output_type, param.output_binding_strategy, param.output_video_frame_source, L"Bgra8", param.batch_size); EvaluateTest(param.evaluation_strategy); // benchmark used to compare with the output from model if (OutputBindingStrategy::Unbound == param.output_binding_strategy) { std::wstring output_data_binding_name = std::wstring(m_model.OutputFeatures().First().Current().Name()); output_video_frames = m_result.Outputs().Lookup(output_data_binding_name).try_as>(); if (output_video_frames == nullptr) { return; } } if (!param.input_images.empty()) { for (int i = 0; i < param.batch_size; ++i) { std::wstring bm_image_path = FileHelpers::GetModulePath() + L"batchGroundTruth\\" + param.input_images[i]; if (VideoFrameSource::FromSoftwareBitmap != param.output_video_frame_source && OutputBindingStrategy::Unbound != param.output_binding_strategy) { VideoFrame D3D_video_frame = output_video_frames.GetAt(i); VideoFrame SB_video_frame(BitmapPixelFormat::Bgra8, 720, 720); D3D_video_frame.as().CopyToAsync(SB_video_frame).get(); VerifyResults(SB_video_frame, bm_image_path, L"Bgra8"); } else { VerifyResults(output_video_frames.GetAt(i), bm_image_path, L"Bgra8"); } } } } INSTANTIATE_TEST_SUITE_P(BatchTest, BatchTest, testing::Combine( testing::Values( std::make_tuple(L"fns-candy_Bgr8_Batch2.onnx", Image, std::vector({L"fish_720.png", L"fish_720.png"}), 2, false), std::make_tuple(L"fns-candy_Bgr8_Batch2.onnx", Image, std::vector({L"1080.jpg", L"fish_720.png"}), 2, false), std::make_tuple(L"fns-candy_Bgr8_Batch2.onnx", Image, std::vector({L"fish_720_Gray.png", L"fish_720.png"}), 2, false), std::make_tuple(L"fns-candy_Bgr8_Batch3.onnx", Image, std::vector({L"1080.jpg", L"fish_720_Gray.png", L"fish_720.png"}), 3, false), std::make_tuple(L"fns-candy_Bgr8_Batch3.onnx", Image, std::vector({L"1080.jpg", L"kitten_224.png", L"fish_720.png"}), 3, false), std::make_tuple(L"fns-candy_Bgr8_tensor_Batch3.onnx", Tensor, std::vector({L"1080.jpg", L"fish_720_Gray.png", L"fish_720.png"}), 3, false), std::make_tuple(L"fns-candy_Bgr8_freeDimInput_Batch10.onnx", Image, std::vector({}), 10, false), std::make_tuple(L"fns-candy_Bgr8.onnx", Image, std::vector({L"1080.jpg", L"fish_720_Gray.png", L"fish_720.png"}), 3, false), std::make_tuple(L"fns-candy_Bgr8.onnx", Image, std::vector({L"1080.jpg", L"fish_720_Gray.png", L"fish_720.png"}), 3, true)), testing::Values(Bound, Unbound), testing::Values(Async, Sync), testing::Values(FromSoftwareBitmap, FromDirect3DSurface), testing::Values(FromSoftwareBitmap, FromDirect3DSurface, FromUnsupportedD3DSurface), testing::Values(LearningModelDeviceKind::DirectX, LearningModelDeviceKind::Cpu) )); #endif TEST_F(ImageTests, LoadBindEvalModelWithoutImageMetadata) { GPUTEST; LoadModel(L"squeezenet_tensor_input.onnx"); auto feature_value = FileHelpers::LoadImageFeatureValue(L"227x227.png"); LearningModelSession model_session(m_model); LearningModelBinding model_binding(model_session); model_binding.Bind(L"data", feature_value); auto result = model_session.Evaluate(model_binding, L""); } TEST_F(ImageTests, LoadBindModelWithoutImageMetadata) { GPUTEST; // Model expecting a tensor instead of an image LoadModel(L"squeezenet_tensor_input.onnx"); LearningModelSession model_session(m_model); LearningModelBinding model_binding(model_session); // Should work on images (by falling back to RGB8) auto feature_value = FileHelpers::LoadImageFeatureValue(L"227x227.png"); model_binding.Bind(L"data", feature_value); // Should work on tensors auto tensor = TensorFloat::CreateFromIterable({ 1, 3, 227, 227 }, winrt::single_threaded_vector(std::vector(3 * 227 * 227))); model_binding.Bind(L"data", tensor); } TEST_F(ImageTests, LoadInvalidBindModelWithoutImageMetadata) { GPUTEST; LoadModel(L"squeezenet_tensor_input.onnx"); LearningModelSession model_session(m_model); LearningModelBinding model_binding(model_session); // expect not fail if image dimensions are bigger than required auto feature_value = FileHelpers::LoadImageFeatureValue(L"1080.jpg"); WINML_EXPECT_NO_THROW(model_binding.Bind(L"data", feature_value)); // expect fail if tensor is of wrong type auto tensor_uint8 = TensorUInt8Bit::CreateFromIterable({ 1, 3, 227, 227 }, winrt::single_threaded_vector(std::vector(3 * 227 * 227))); WINML_EXPECT_THROW_SPECIFIC(model_binding.Bind(L"data", tensor_uint8), winrt::hresult_error, [](const winrt::hresult_error& e) -> bool { return e.code() == WINML_ERR_INVALID_BINDING; }); // Should fail if tensor has smaller dimensions/type auto tensor = TensorFloat::CreateFromIterable({ 1, 3, 22, 22 }, winrt::single_threaded_vector(std::vector(3 * 22 * 22))); WINML_EXPECT_THROW_SPECIFIC(model_binding.Bind(L"data", tensor), winrt::hresult_error, [](const winrt::hresult_error& e) -> bool { return e.code() == WINML_ERR_SIZE_MISMATCH; }); } TEST_F(ImageTests, ImageMetaDataTest) { // supported image metadata ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_0_255.onnx", BitmapAlphaMode::Premultiplied, BitmapPixelFormat::Bgra8, true); ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataRgb8_SRGB_0_255.onnx", BitmapAlphaMode::Premultiplied, BitmapPixelFormat::Rgba8, true); ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_0_1.onnx", BitmapAlphaMode::Premultiplied, BitmapPixelFormat::Bgra8, true); ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_1_1.onnx", BitmapAlphaMode::Premultiplied, BitmapPixelFormat::Bgra8, true); // unsupported image metadata ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataBgra8_SRGB_0_255.onnx", BitmapAlphaMode::Straight, BitmapPixelFormat::Bgra8, false); ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataRgba8_SRGB_0_255.onnx", BitmapAlphaMode::Straight, BitmapPixelFormat::Rgba8, false); ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_16_235.onnx", BitmapAlphaMode::Straight, BitmapPixelFormat::Bgra8, false); ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataBgr8_LINEAR_0_255.onnx", BitmapAlphaMode::Straight, BitmapPixelFormat::Bgra8, false); } //Tests if GPU will throw TDR if the same image feature value is binded back to back for two different inputs to a model TEST_F(ImageTests, ImageBindingTwiceSameFeatureValueOnGpu) { GPUTEST; std::wstring module_path = FileHelpers::GetModulePath(); static const wchar_t* input_data_image_filename = L"1080.jpg"; std::wstring full_image_path = module_path + input_data_image_filename; ImageFeatureValue input_norm = CreateImageFeatureValue(full_image_path); RunConsecutiveImageBindingOnGpu(input_norm, input_norm); } //Tests if GPU will throw TDR if 2 different image feature values are binded back to back for two different inputs to a model TEST_F(ImageTests, ImageBindingTwiceDifferentFeatureValueOnGpu) { GPUTEST; std::wstring module_path = FileHelpers::GetModulePath(); static const wchar_t* input_data_image_filename = L"1080.jpg"; std::wstring full_image_path = module_path + input_data_image_filename; ImageFeatureValue input_norm = CreateImageFeatureValue(full_image_path); ImageFeatureValue input_norm_1 = CreateImageFeatureValue(full_image_path); RunConsecutiveImageBindingOnGpu(input_norm, input_norm_1); } static void RunImageBindingInputAndOutput(bool bindInputAsIInspectable) { static const wchar_t* model_file_name = L"Add_ImageNet1920.onnx"; std::wstring module_path = FileHelpers::GetModulePath(); static const wchar_t* input_data_image_filename = L"1080.jpg"; static const wchar_t* output_data_image_filename = L"out_Add_ImageNet_1080.jpg"; // WinML model creation LearningModel model(nullptr); std::wstring full_model_path = module_path + model_file_name; WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); LearningModelDeviceKind device_kind = LearningModelDeviceKind::DirectX; LearningModelSession model_session(model, LearningModelDevice(device_kind)); LearningModelBinding model_binding(model_session); std::wstring full_image_path = module_path + input_data_image_filename; StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); if (bindInputAsIInspectable) { auto feature = model.InputFeatures().First(); WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), frame)); feature.MoveNext(); WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), frame)); } else { ImageFeatureValue input_image_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); auto feature = model.InputFeatures().First(); WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), input_image_tensor)); feature.MoveNext(); WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), input_image_tensor)); } auto output_tensor_descriptor = model.OutputFeatures().First().Current().as(); auto output_tensor_shape = output_tensor_descriptor.Shape(); VideoFrame output_image(BitmapPixelFormat::Rgba8, static_cast(output_tensor_shape.GetAt(3)), static_cast(output_tensor_shape.GetAt(2))); ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); WINML_EXPECT_NO_THROW(model_binding.Bind(model.OutputFeatures().First().Current().Name(), output_tensor)); // Evaluate the model winrt::hstring correlation_id; model_session.EvaluateAsync(model_binding, correlation_id).get(); //check the output video frame object StorageFolder current_folder = StorageFolder::GetFolderFromPathAsync(module_path).get(); StorageFile out_image_file = current_folder.CreateFileAsync(output_data_image_filename, CreationCollisionOption::ReplaceExisting).get(); IRandomAccessStream write_stream = out_image_file.OpenAsync(FileAccessMode::ReadWrite).get(); BitmapEncoder encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), write_stream).get(); // Set the software bitmap encoder.SetSoftwareBitmap(output_image.SoftwareBitmap()); encoder.FlushAsync().get(); BYTE* data = nullptr; UINT32 ui_capacity = 0; wgi::BitmapBuffer bitmap_buffer(output_image.SoftwareBitmap().LockBuffer(wgi::BitmapBufferAccessMode::Read)); wf::IMemoryBufferReference reference = bitmap_buffer.CreateReference(); auto spByteAccess = reference.as<::Windows::Foundation::IMemoryBufferByteAccess>(); WINML_EXPECT_HRESULT_SUCCEEDED(spByteAccess->GetBuffer(&data, &ui_capacity)); WINML_EXPECT_NOT_EQUAL(data[0], 0); } TEST_F(ImageTests, ImageBindingInputAndOutput) { GPUTEST; RunImageBindingInputAndOutput(false /*bindInputAsIInspectable*/); } TEST_F(ImageTests, ImageBindingInputAndOutput_BindInputTensorAsInspectable) { GPUTEST; RunImageBindingInputAndOutput(true /*bindInputAsIInspectable*/); } static void TestImageBindingStyleTransfer(const wchar_t* model_file_name, const wchar_t* input_data_image_filename, wchar_t* output_data_image_filename) { GPUTEST; //this test only checks that the operation completed successfully without crashing std::wstring module_path = FileHelpers::GetModulePath(); // WinML model creation LearningModel model(nullptr); std::wstring full_model_path = module_path + model_file_name; WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); LearningModelDeviceKind device_kind = LearningModelDeviceKind::DirectX; LearningModelDevice device = nullptr; WINML_EXPECT_NO_THROW(device = LearningModelDevice(device_kind)); LearningModelSession model_session = nullptr; WINML_EXPECT_NO_THROW(model_session = LearningModelSession(model, device)); LearningModelBinding model_binding = nullptr; WINML_EXPECT_NO_THROW(model_binding = LearningModelBinding(model_session)); std::wstring full_image_path = module_path + input_data_image_filename; StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); //aizBUG:3762 Cannot bind the same tensor to 2 different input. will deal with this in a later check in ImageFeatureValue input_1_image_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); auto feature = model.InputFeatures().First(); WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), input_1_image_tensor)); auto output_tensor_descriptor = model.OutputFeatures().First().Current().as(); auto output_tensor_shape = output_tensor_descriptor.Shape(); VideoFrame output_image(BitmapPixelFormat::Rgba8, static_cast(output_tensor_shape.GetAt(3)), static_cast(output_tensor_shape.GetAt(2))); ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); WINML_EXPECT_NO_THROW(model_binding.Bind(model.OutputFeatures().First().Current().Name(), output_tensor)); // Evaluate the model winrt::hstring correlation_id; WINML_EXPECT_NO_THROW(model_session.EvaluateAsync(model_binding, correlation_id).get()); //check the output video frame object StorageFolder current_folder = StorageFolder::GetFolderFromPathAsync(module_path).get(); StorageFile out_image_file = current_folder.CreateFileAsync(output_data_image_filename, CreationCollisionOption::ReplaceExisting).get(); IRandomAccessStream write_stream = out_image_file.OpenAsync(FileAccessMode::ReadWrite).get(); BitmapEncoder encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), write_stream).get(); // Set the software bitmap encoder.SetSoftwareBitmap(output_image.SoftwareBitmap()); encoder.FlushAsync().get(); } TEST_F(ImageTests, ImageBindingStyleTransfer) { //this test only checks that the operation completed successfully without crashing TestImageBindingStyleTransfer(L"fns-candy.onnx", L"fish_720.png", L"out_fish_720_StyleTransfer.jpg"); } TEST_F(ImageTests, ImageBindingAsGPUTensor) { GPUTEST; static const wchar_t* model_file_name = L"fns-candy.onnx"; std::wstring module_path = FileHelpers::GetModulePath(); static const wchar_t* input_data_image_filename = L"fish_720.png"; static const wchar_t* output_data_image_filename = L"out_fish_720_StyleTransfer.jpg"; // WinML model creation LearningModel model(nullptr); std::wstring full_model_path = module_path + model_file_name; WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); ID3D12Device* D3D12_device = nullptr; WINML_EXPECT_NO_THROW(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), reinterpret_cast(&D3D12_device))); ID3D12CommandQueue* dx_queue = nullptr; D3D12_COMMAND_QUEUE_DESC command_queue_desc = {}; command_queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; D3D12_device->CreateCommandQueue(&command_queue_desc, __uuidof(ID3D12CommandQueue), reinterpret_cast(&dx_queue)); auto device_factory = get_activation_factory(); auto tensor_factory = get_activation_factory(); com_ptr<::IUnknown> p_unk; device_factory->CreateFromD3D12CommandQueue(dx_queue, p_unk.put()); LearningModelDevice dml_device_custom = nullptr; WINML_EXPECT_NO_THROW(p_unk.as(dml_device_custom)); LearningModelSession dml_session_custom = nullptr; WINML_EXPECT_NO_THROW(dml_session_custom = LearningModelSession(model, dml_device_custom)); LearningModelBinding model_binding(dml_session_custom); std::wstring full_image_path = module_path + input_data_image_filename; StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); UINT64 buffer_byte_size = software_bitmap.PixelWidth()*software_bitmap.PixelHeight() * 3 * sizeof(float); D3D12_HEAP_PROPERTIES heap_properties = { D3D12_HEAP_TYPE_DEFAULT, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_UNKNOWN, 0, 0 }; D3D12_RESOURCE_DESC resource_desc = { D3D12_RESOURCE_DIMENSION_BUFFER, 0, buffer_byte_size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, { 1, 0 }, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS }; com_ptr GPU_resource = nullptr; D3D12_device->CreateCommittedResource( &heap_properties, D3D12_HEAP_FLAG_NONE, &resource_desc, D3D12_RESOURCE_STATE_COMMON, nullptr, __uuidof(ID3D12Resource), GPU_resource.put_void() ); com_ptr<::IUnknown> sp_unk_tensor; TensorFloat input_1_image_tensor(nullptr); __int64 shape[4] = { 1,3, software_bitmap.PixelWidth(), software_bitmap.PixelHeight() }; tensor_factory->CreateFromD3D12Resource(GPU_resource.get(), shape, 4, sp_unk_tensor.put()); sp_unk_tensor.try_as(input_1_image_tensor); auto feature = model.InputFeatures().First(); WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), input_1_image_tensor)); auto output_tensor_descriptor = model.OutputFeatures().First().Current().as(); auto output_tensor_shape = output_tensor_descriptor.Shape(); VideoFrame output_image(BitmapPixelFormat::Rgba8, static_cast(output_tensor_shape.GetAt(3)), static_cast(output_tensor_shape.GetAt(2))); ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); WINML_EXPECT_NO_THROW(model_binding.Bind(model.OutputFeatures().First().Current().Name(), output_tensor)); // Evaluate the model winrt::hstring correlation_id; dml_session_custom.EvaluateAsync(model_binding, correlation_id).get(); //check the output video frame object StorageFolder current_folder = StorageFolder::GetFolderFromPathAsync(module_path).get(); StorageFile out_image_file = current_folder.CreateFileAsync(output_data_image_filename, CreationCollisionOption::ReplaceExisting).get(); IRandomAccessStream write_stream = out_image_file.OpenAsync(FileAccessMode::ReadWrite).get(); BitmapEncoder encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), write_stream).get(); // Set the software bitmap encoder.SetSoftwareBitmap(output_image.SoftwareBitmap()); encoder.FlushAsync().get(); } static void GetCleanSession(LearningModelDeviceKind device_kind, std::wstring modelFilePath, LearningModelDevice &device, LearningModelSession &session) { LearningModel model(nullptr); std::wstring full_model_path = modelFilePath; WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); WINML_EXPECT_NO_THROW(device = LearningModelDevice(device_kind)); WINML_EXPECT_NO_THROW(session = LearningModelSession(model, device)); } static void BindInputToSession(BindingLocation bind_location, std::wstring input_data_location, LearningModelSession& session, LearningModelBinding& binding) { StorageFile image_file = StorageFile::GetFileFromPathAsync(input_data_location).get(); IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); VideoFrame cpu_video_frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); if (bind_location == BindingLocation::CPU) { ImageFeatureValue input_image_feature_value = ImageFeatureValue::CreateFromVideoFrame(cpu_video_frame); WINML_EXPECT_NO_THROW(binding.Bind(session.Model().InputFeatures().First().Current().Name(), input_image_feature_value)); } else { DirectXPixelFormat format = DirectXPixelFormat::B8G8R8X8UIntNormalized; VideoFrame gpu_video_frame = VideoFrame::CreateAsDirect3D11SurfaceBacked(format, software_bitmap.PixelWidth(), software_bitmap.PixelHeight(), session.Device().Direct3D11Device()); cpu_video_frame.CopyToAsync(gpu_video_frame).get(); ImageFeatureValue input_image_feature_value = ImageFeatureValue::CreateFromVideoFrame(gpu_video_frame); WINML_EXPECT_NO_THROW(binding.Bind(session.Model().InputFeatures().First().Current().Name(), input_image_feature_value)); } } static void BindOutputToSession(BindingLocation bind_location, LearningModelSession& session, LearningModelBinding& binding) { auto output_tensor_descriptor = session.Model().OutputFeatures().First().Current().as(); auto output_tensor_shape = output_tensor_descriptor.Shape(); if (bind_location == BindingLocation::CPU) { VideoFrame output_image(BitmapPixelFormat::Rgba8, static_cast(output_tensor_shape.GetAt(3)), static_cast(output_tensor_shape.GetAt(2))); ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); WINML_EXPECT_NO_THROW(binding.Bind(session.Model().OutputFeatures().First().Current().Name(), output_tensor)); } else { VideoFrame output_image = VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8X8UIntNormalized, static_cast(output_tensor_shape.GetAt(3)), static_cast(output_tensor_shape.GetAt(2))); ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); WINML_EXPECT_NO_THROW(binding.Bind(session.Model().OutputFeatures().First().Current().Name(), output_tensor)); } } static void SynchronizeGPUWorkloads(const wchar_t* model_file_name, const wchar_t* input_data_image_filename) { //this test only checks that the operations complete successfully without crashing GPUTEST; std::wstring module_path = FileHelpers::GetModulePath(); LearningModelDevice device = nullptr; LearningModelSession session = nullptr; LearningModelBinding binding = nullptr; /* * lazy dx11 loading scenarios: */ // Scenario 1 GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); // input: CPU, output: CPU WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); BindOutputToSession(BindingLocation::CPU, session, binding); WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); // ---> verify that 11 stack is not initialized WINML_EXPECT_FALSE(device.as()->SharedHandleInitialized()); // input: CPU, output: GPU WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); BindOutputToSession(BindingLocation::GPU, session, binding); WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); // Scenario 2 GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); // input: CPU, output: CPU WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); BindOutputToSession(BindingLocation::CPU, session, binding); WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); // ---> verify that 11 stack is not initialized WINML_EXPECT_FALSE(device.as()->SharedHandleInitialized()); // input: GPU, output: CPU WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); BindInputToSession(BindingLocation::GPU, module_path + input_data_image_filename, session, binding); BindOutputToSession(BindingLocation::CPU, session, binding); WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); // ---> verify that 11 stack is initialized WINML_EXPECT_TRUE(device.as()->SharedHandleInitialized()); // Scenario 3 GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); // input: CPU, output: CPU WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); BindOutputToSession(BindingLocation::CPU, session, binding); WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); // ---> verify that 11 stack is not initialized WINML_EXPECT_FALSE(device.as()->SharedHandleInitialized()); // input: GPU, output: GPU WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); BindInputToSession(BindingLocation::GPU, module_path + input_data_image_filename, session, binding); BindOutputToSession(BindingLocation::GPU, session, binding); WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); // ---> verify that 11 stack is initialized WINML_EXPECT_TRUE(device.as()->SharedHandleInitialized()); /* * non lazy dx11 loading scenarios: */ // Scenario 1 GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); // input: GPU, output: CPU WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); BindInputToSession(BindingLocation::GPU, module_path + input_data_image_filename, session, binding); BindOutputToSession(BindingLocation::CPU, session, binding); WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); // ---> verify that 11 stack is initialized WINML_EXPECT_TRUE(device.as()->SharedHandleInitialized()); // input : CPU, output : CPU WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); BindOutputToSession(BindingLocation::CPU, session, binding); WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); // Scenario 2 GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); // input: CPU, output: GPU WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); BindOutputToSession(BindingLocation::GPU, session, binding); WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); // input : CPU, output : CPU WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); BindOutputToSession(BindingLocation::CPU, session, binding); WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); } TEST_F(ImageTests, SynchronizeGPUWorkloads) { SynchronizeGPUWorkloads(L"fns-candy.onnx", L"fish_720.png"); }