Merge branch 'windowsai' into jeffbloo/MergeMasterToWindowsAI

This commit is contained in:
Ryan Lai 2020-01-15 16:52:12 -08:00
commit 0b1b40077f
22 changed files with 878 additions and 608 deletions

View file

@ -20,19 +20,17 @@ if (NOT onnxruntime_USE_CUSTOM_DIRECTML)
set(NUGET_CONFIG ${PROJECT_SOURCE_DIR}/../NuGet.config)
set(PACKAGES_CONFIG ${PROJECT_SOURCE_DIR}/../packages.config)
set(PACKAGES_DIR ${CMAKE_CURRENT_BINARY_DIR}/packages)
set(DML_PACKAGE_DIR ${PACKAGES_DIR}/DirectML.0.0.1)
# Restore nuget packages, which will pull down the DirectML redist package
add_custom_command(
OUTPUT restore_packages.stamp
OUTPUT ${DML_PACKAGE_DIR}/bin/x64/DirectML.lib ${DML_PACKAGE_DIR}/bin/x86/DirectML.lib
DEPENDS ${PACKAGES_CONFIG} ${NUGET_CONFIG}
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/nuget/src/nuget restore ${PACKAGES_CONFIG} -PackagesDirectory ${PACKAGES_DIR} -ConfigFile ${NUGET_CONFIG}
COMMAND ${CMAKE_COMMAND} -E touch restore_packages.stamp
VERBATIM)
add_custom_target(RESTORE_PACKAGES ALL DEPENDS restore_packages.stamp)
add_custom_target(RESTORE_PACKAGES ALL DEPENDS ${DML_PACKAGE_DIR}/bin/x64/DirectML.lib ${DML_PACKAGE_DIR}/bin/x86/DirectML.lib)
add_dependencies(RESTORE_PACKAGES nuget)
list(APPEND onnxruntime_EXTERNAL_DEPENDENCIES RESTORE_PACKAGES)
else()
include_directories(${dml_INCLUDE_DIR})
endif()

View file

@ -44,6 +44,22 @@ else()
endif()
endif()
if(CMAKE_GENERATOR_PLATFORM)
# Multi-platform generator
set(onnxruntime_target_platform ${CMAKE_GENERATOR_PLATFORM})
else()
set(onnxruntime_target_platform ${CMAKE_SYSTEM_PROCESSOR})
endif()
if(onnxruntime_target_platform STREQUAL "ARM64")
set(onnxruntime_target_platform "ARM64")
elseif(onnxruntime_target_platform STREQUAL "ARM" OR CMAKE_GENERATOR MATCHES "ARM")
set(onnxruntime_target_platform "ARM")
elseif(onnxruntime_target_platform STREQUAL "x64" OR onnxruntime_target_platform STREQUAL "x86_64" OR onnxruntime_target_platform STREQUAL "AMD64" OR CMAKE_GENERATOR MATCHES "Win64")
set(onnxruntime_target_platform "x64")
elseif(onnxruntime_target_platform STREQUAL "x86" OR onnxruntime_target_platform STREQUAL "i386" OR onnxruntime_target_platform STREQUAL "i686")
set(onnxruntime_target_platform "x86")
endif()
file(GLOB onnxruntime_common_src CONFIGURE_DEPENDS
${onnxruntime_common_src_patterns}
)

View file

@ -19,7 +19,7 @@ set(mlas_common_srcs
)
if(MSVC)
if(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64")
if(onnxruntime_target_platform STREQUAL "ARM64")
set(asm_filename ${ONNXRUNTIME_ROOT}/core/mlas/lib/arm64/SgemmKernelNeon.asm)
set(pre_filename ${CMAKE_CURRENT_BINARY_DIR}/SgemmKernelNeon.i)
set(obj_filename ${CMAKE_CURRENT_BINARY_DIR}/SgemmKernelNeon.obj)
@ -38,11 +38,11 @@ if(MSVC)
armasm64.exe ${ARMASM_FLAGS} ${pre_filename} ${obj_filename}
)
set(mlas_platform_srcs ${obj_filename})
elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM" OR CMAKE_GENERATOR MATCHES "ARM")
elseif(onnxruntime_target_platform STREQUAL "ARM")
set(mlas_platform_srcs
${ONNXRUNTIME_ROOT}/core/mlas/lib/arm/sgemmc.cpp
)
elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "x64" OR CMAKE_GENERATOR MATCHES "Win64")
elseif(onnxruntime_target_platform STREQUAL "x64")
enable_language(ASM_MASM)
set(mlas_platform_srcs

View file

@ -217,7 +217,7 @@ if (onnxruntime_USE_TENSORRT)
if ( CMAKE_COMPILER_IS_GNUCC )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-missing-field-initializers")
endif()
set(CXX_VERSION_DEFINED TRUE)
set(CXX_VERSION_DEFINED TRUE)
add_subdirectory(${ONNXRUNTIME_ROOT}/../cmake/external/onnx-tensorrt)
set(CMAKE_CXX_FLAGS ${OLD_CMAKE_CXX_FLAGS})
if (WIN32)
@ -303,7 +303,7 @@ if (onnxruntime_USE_OPENVINO)
if(WIN32)
set(OPENVINO_LIB_DIR $ENV{INTEL_OPENVINO_DIR}/deployment_tools/inference_engine/lib/intel64/Release)
set(OPENVINO_TBB_DIR $ENV{INTEL_OPENVINO_DIR}/deployment_tools/inference_engine/lib/intel64/Release)
set(OPENVINO_MKL_TINY_DIR $ENV{INTEL_OPENVINO_DIR}/deployment_tools/inference_engine/bin/intel64/Release)
set(OPENVINO_MKL_TINY_DIR $ENV{INTEL_OPENVINO_DIR}/deployment_tools/inference_engine/bin/intel64/Release)
else()
set(OPENVINO_LIB_DIR $ENV{INTEL_OPENVINO_DIR}/deployment_tools/inference_engine/lib/intel64/)
set(OPENVINO_TBB_DIR $ENV{INTEL_OPENVINO_DIR}/deployment_tools/inference_engine/external/tbb/lib)
@ -327,9 +327,9 @@ if (onnxruntime_USE_OPENVINO)
else()
target_include_directories(onnxruntime_providers_openvino SYSTEM PUBLIC ${ONNXRUNTIME_ROOT} ${eigen_INCLUDE_DIRS} ${OPENVINO_INCLUDE_DIR} ${OPENVINO_EXTENSIONS_DIR} ${OPENVINO_LIB_DIR} ${OPENVINO_TBB_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS})
endif()
if (WIN32)
string(REPLACE "include" "libs" PYTHON_LIB ${PYTHON_INCLUDE_DIRS})
if (WIN32)
string(REPLACE "include" "libs" PYTHON_LIB ${PYTHON_INCLUDE_DIRS})
find_package(InferenceEngine 2.1 REQUIRED)
set(PYTHON_LIBRARIES ${PYTHON_LIB})
set(OPENVINO_CPU_EXTENSION_DIR ${onnxruntime_BINARY_DIR}/ie_cpu_extension/${CMAKE_BUILD_TYPE})
@ -430,22 +430,37 @@ if (onnxruntime_USE_DML)
onnxruntime_add_include_to_target(onnxruntime_providers_dml onnxruntime_common onnxruntime_framework onnx onnx_proto protobuf::libprotobuf)
add_dependencies(onnxruntime_providers_dml ${onnxruntime_EXTERNAL_DEPENDENCIES})
target_include_directories(onnxruntime_providers_dml PRIVATE ${ONNXRUNTIME_ROOT} ${ONNXRUNTIME_ROOT}/../cmake/external/wil/include)
target_link_libraries(onnxruntime_providers_dml ${CMAKE_CURRENT_BINARY_DIR}/packages/DirectML.0.0.1/build/DirectML.targets)
target_link_libraries(onnxruntime_providers_dml d3d12.lib dxgi.lib)
if(NOT onnxruntime_target_platform STREQUAL "x86" AND NOT onnxruntime_target_platform STREQUAL "x64")
message(FATAL_ERROR "Target platform ${onnxruntime_target_platform} is not supported by DML")
endif()
foreach(file "DirectML.dll" "DirectML.pdb" "DirectML.Debug.dll" "DirectML.Debug.pdb")
add_custom_command(TARGET onnxruntime_providers_dml
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${DML_PACKAGE_DIR}/bin/${onnxruntime_target_platform}/${file}" $<TARGET_FILE_DIR:onnxruntime_providers_dml>)
endforeach()
function(target_add_dml target)
target_link_libraries(${target} PRIVATE "${DML_PACKAGE_DIR}/bin/${onnxruntime_target_platform}/DirectML.lib")
target_include_directories(${target} PRIVATE "${DML_PACKAGE_DIR}/include")
endfunction()
target_add_dml(onnxruntime_providers_dml)
target_link_libraries(onnxruntime_providers_dml PRIVATE d3d12.lib dxgi.lib delayimp.lib)
list(APPEND ONNXRUNTIME_LINKER_FLAGS "/DELAYLOAD:DirectML.dll /DELAYLOAD:d3d12.dll /DELAYLOAD:dxgi.dll")
# The DML EP requires C++17
set_target_properties(onnxruntime_providers_dml PROPERTIES CXX_STANDARD 17)
set_target_properties(onnxruntime_providers_dml PROPERTIES CXX_STANDARD_REQUIRED ON)
target_compile_definitions(onnxruntime_providers_dml PRIVATE ONNX_NAMESPACE=onnx ONNX_ML LOTUS_LOG_THRESHOLD=2 LOTUS_ENABLE_STDERR_LOGGING PLATFORM_WINDOWS)
target_compile_definitions(onnxruntime_providers_dml PRIVATE UNICODE _UNICODE NOMINMAX)
if (MSVC)
target_compile_definitions(onnxruntime_providers_dml PRIVATE _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING)
target_compile_options(onnxruntime_providers_dml PRIVATE "/W3")
endif()
install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/dml DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers)
set_target_properties(onnxruntime_providers_dml PROPERTIES LINKER_LANGUAGE CXX)

View file

@ -44,7 +44,7 @@ function(AddTest)
endif()
if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS AND onnxruntime_ENABLE_PYTHON)
target_compile_definitions(${_UT_TARGET} PRIVATE ENABLE_LANGUAGE_INTEROP_OPS)
endif()
endif()
if (WIN32)
if (onnxruntime_USE_CUDA)
# disable a warning from the CUDA headers about unreferenced local functions
@ -318,7 +318,7 @@ if (onnxruntime_USE_DNNL)
target_compile_definitions(onnxruntime_test_utils_for_framework PUBLIC USE_DNNL=1)
endif()
if (onnxruntime_USE_DML)
target_link_libraries(onnxruntime_test_utils_for_framework PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/packages/DirectML.0.0.1/build/DirectML.targets)
target_add_dml(onnxruntime_test_utils_for_framework)
endif()
add_dependencies(onnxruntime_test_utils_for_framework ${onnxruntime_EXTERNAL_DEPENDENCIES})
target_include_directories(onnxruntime_test_utils_for_framework PUBLIC "${TEST_SRC_DIR}/util/include" PRIVATE ${eigen_INCLUDE_DIRS} ${ONNXRUNTIME_ROOT})
@ -336,7 +336,7 @@ if (onnxruntime_USE_DNNL)
target_compile_definitions(onnxruntime_test_utils PUBLIC USE_DNNL=1)
endif()
if (onnxruntime_USE_DML)
target_link_libraries(onnxruntime_test_utils PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/packages/DirectML.0.0.1/build/DirectML.targets)
target_add_dml(onnxruntime_test_utils)
endif()
add_dependencies(onnxruntime_test_utils ${onnxruntime_EXTERNAL_DEPENDENCIES})
target_include_directories(onnxruntime_test_utils PUBLIC "${TEST_SRC_DIR}/util/include" PRIVATE ${eigen_INCLUDE_DIRS} ${ONNXRUNTIME_ROOT})

View file

@ -2,8 +2,7 @@
# header name as input. The function will generate a .cpp file that includes the header and is used
# to generate the precompiled header; this source file is added to the target's sources.
function(target_precompiled_header target_name header_name)
if (MSVC)
if (MSVC AND CMAKE_VS_PLATFORM_TOOLSET)
# The input precompiled header source (i.e. the '.h' file used for the precompiled header).
set(pch_header_path ${header_name})
get_filename_component(header_base_name ${header_name} NAME_WE)
@ -14,14 +13,14 @@ function(target_precompiled_header target_name header_name)
set(pch_source_content "// THIS FILE IS GENERATED BY CMAKE\n#include \"${pch_header_path}\"")
file(WRITE ${pch_source_path} ${pch_source_content})
set_source_files_properties(${pch_source_path} PROPERTIES COMPILE_FLAGS "/Yc${pch_header_path}")
# The target's C++ sources use the precompiled header (/Yu). Source-level properties will
# take precedence over target-level properties, so this will not change the generated source
# take precedence over target-level properties, so this will not change the generated source
# file's property to create the precompiled header (/Yc).
target_compile_options(${target_name} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:/Yu${header_name}>)
# Append generated precompiled source to target's sources.
target_sources(${target_name} PRIVATE ${pch_source_path})
endif(MSVC)
endfunction()
endif()
endfunction()

View file

@ -132,7 +132,7 @@ list(APPEND winml_adapter_files
${winml_adapter_dir}/WinMLAdapter.cpp
${winml_adapter_dir}/WinMLAdapter.h
${winml_adapter_dir}/ZeroCopyInputStreamWrapper.cpp
${winml_adapter_dir}/ZeroCopyInputStreamWrapper.h
${winml_adapter_dir}/ZeroCopyInputStreamWrapper.h
)
if (onnxruntime_USE_DML)
@ -159,6 +159,7 @@ add_dependencies(winml_adapter ${onnxruntime_EXTERNAL_DEPENDENCIES})
target_precompiled_header(winml_adapter pch.h)
# Includes
target_include_directories(winml_adapter PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) # windows machine learning generated component headers
target_include_directories(winml_adapter PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/winml_api) # windows machine learning generated component headers
target_include_directories(winml_adapter PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/winml_api/comp_generated) # windows machine learning generated component headers
target_include_directories(winml_adapter PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/winml/sdk/cppwinrt/include) # sdk cppwinrt headers
@ -181,11 +182,11 @@ add_dependencies(winml_adapter winml_api_native_internal)
# Link libraries
target_link_libraries(winml_adapter PRIVATE wil)
if (onnxruntime_USE_DML)
target_link_libraries(winml_adapter PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/packages/DirectML.0.0.1/build/DirectML.targets)
target_add_dml(winml_adapter)
endif(onnxruntime_USE_DML)
# add it to the onnxruntime shared library
set(onnxruntime_winml windowsapp.lib winml_adapter)
set(onnxruntime_winml winml_adapter)
list(APPEND onnxruntime_EXTERNAL_DEPENDENCIES winml_adapter)
###########################
@ -230,6 +231,7 @@ target_compile_definitions(winml_lib_image PRIVATE _SCL_SECURE_NO_WARNINGS)
target_precompiled_header(winml_lib_image pch.h)
# Includes
target_include_directories(winml_lib_image PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) # windows machine learning generated component headers
target_include_directories(winml_lib_image PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/winml_api) # windows machine learning generated component headers
target_include_directories(winml_lib_image PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/winml_api/comp_generated) # windows machine learning generated component headers
target_include_directories(winml_lib_image PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/winml/sdk/cppwinrt/include) # sdk cppwinrt headers
@ -258,7 +260,7 @@ add_dependencies(winml_lib_image winml_api_native_internal)
# Link libraries
target_link_libraries(winml_lib_image PRIVATE wil)
if (onnxruntime_USE_DML)
target_link_libraries(winml_lib_image PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/packages/DirectML.0.0.1/build/DirectML.targets)
target_add_dml(winml_lib_image)
endif(onnxruntime_USE_DML)
@ -360,7 +362,7 @@ add_dependencies(winml_lib_api winml_api_native_internal)
# Link libraries
target_link_libraries(winml_lib_api PRIVATE wil)
if (onnxruntime_USE_DML)
target_link_libraries(winml_lib_api PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/packages/DirectML.0.0.1/build/DirectML.targets)
target_add_dml(winml_lib_api)
endif(onnxruntime_USE_DML)
@ -438,10 +440,17 @@ if (onnxruntime_USE_DML)
set(delayload_dml "/DELAYLOAD:directml.dll")
endif(onnxruntime_USE_DML)
# The default libraries to link with in Windows are kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib
# Remove them and use the onecore umbrella library instead
set(CMAKE_C_STANDARD_LIBRARIES "onecoreuap_apiset.lib")
set(CMAKE_CXX_STANDARD_LIBRARIES "onecoreuap_apiset.lib")
foreach(default_lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdgl32.lib advapi32.lib)
set(removed_libs "${removed_libs} /NODEFAULTLIB:${default_lib}")
endforeach()
set_target_properties(winml_dll
PROPERTIES
LINK_FLAGS
"/DEF:${WINML_DIR}/windows.ai.machinelearning.def ${os_component_link_flags} /DELAYLOAD:d3d12.dll /DELAYLOAD:d3d11.dll /DELAYLOAD:dxgi.dll ${delayload_dml}")
"/DEF:${WINML_DIR}/windows.ai.machinelearning.def ${os_component_link_flags} /DELAYLOAD:d3d12.dll /DELAYLOAD:d3d11.dll /DELAYLOAD:dxgi.dll ${delayload_dml} ${removed_libs}")
set_target_properties(winml_dll
@ -467,11 +476,10 @@ endif("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
target_link_libraries(winml_dll PRIVATE onnxruntime)
target_link_libraries(winml_dll PRIVATE re2)
target_link_libraries(winml_dll PRIVATE wil)
#target_link_libraries(winml_dll PRIVATE windowsapp.lib)
target_link_libraries(winml_dll PRIVATE winml_lib_api)
target_link_libraries(winml_dll PRIVATE winml_lib_image)
target_link_libraries(winml_dll PRIVATE winml_lib_telemetry)
target_link_libraries(winml_dll PRIVATE onecoreuap_apiset.lib)
target_link_libraries(winml_dll PRIVATE delayimp.lib)
target_link_libraries(winml_dll PRIVATE ${DBGHELP})
# 1 of 3 projects that fail in link with 'failed to do memory mapped file I/O' (Only release)
@ -483,6 +491,7 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
set_target_properties(winml_dll PROPERTIES VS_GLOBAL_PreferredToolArchitecture "x64")
endif("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
option(onnxruntime_BUILD_WINML_TESTS "Build WinML tests" ON)
if (onnxruntime_BUILD_WINML_TESTS)
include(winml_unittests.cmake)
endif()

View file

@ -102,7 +102,7 @@ function(target_cppwinrt
# Get directory
get_filename_component(idl_source_directory ${file} DIRECTORY)
set(target_outputs ${CMAKE_CURRENT_BINARY_DIR}/${target_name})
set(target_outputs ${CMAKE_CURRENT_BINARY_DIR}/${target_name})
convert_forward_slashes_to_back(${target_outputs}/comp output_dir_back_slash)
convert_forward_slashes_to_back(${target_outputs}/temp temp_dir_back_slash)
convert_forward_slashes_to_back(${target_outputs}/comp_generated generated_dir_back_slash)
@ -126,50 +126,53 @@ function(target_cppwinrt
/tlb ${tlb_filename}
${idl_file_forward_slash}
COMMAND
${cppwinrt_exe} -in \"${winmd_filename}\" -comp \"${output_dir_back_slash}\" -ref \"${sdk_metadata_directory}\" -out \"${generated_dir_back_slash}\" -verbose
${cppwinrt_exe} -in ${winmd_filename} -comp ${output_dir_back_slash} -ref ${sdk_metadata_directory} -out ${generated_dir_back_slash} -verbose
COMMAND
# copy the generated component files into a temporary directory where headers exclusions will be applied
xcopy \"${output_dir_back_slash}\" \"${temp_dir_back_slash}\\\" /Y /D
xcopy ${output_dir_back_slash} ${temp_dir_back_slash}\\ /Y /D
COMMAND
# for each file in the temp directory, ensure it is not in the exclusions list.
# if it is, then we need to delete it.
for /f %%I in ('dir /b \"${temp_dir_back_slash}\"')
do
(
for /f %%E in (${CPPWINRT_COMPONENT_EXCLUSION_LIST})
do
(
if %%E == %%I
(
del \"${temp_dir_back_slash}\\%%I\"
)
)
)
cmd /C "@echo off \
for /f %I in ('dir /b ${temp_dir_back_slash}') \
do \
( \
for /f %E in (${CPPWINRT_COMPONENT_EXCLUSION_LIST}) \
do \
( \
if %E == %I \
( \
del ${temp_dir_back_slash}\\%I \
) \
) \
)"
COMMAND
# for each file in the temp directory, copy the file back into the source tree
# unless the file already exists
for /f %%I in ('dir /b \"${temp_dir_back_slash}\"')
do
(
if not exist \"${out_sources_folder}\\%%I\"
(
xcopy \"${temp_dir_back_slash}\\%%I\" \"${out_sources_folder}\\%%I\"
)
)
cmd /C "@echo off \
for /f %I in ('dir /b ${temp_dir_back_slash}') \
do \
( \
if not exist ${out_sources_folder}\\%I \
( \
copy ${temp_dir_back_slash}\\%I ${out_sources_folder}\\%I \
) \
)"
COMMAND
# open the generated module.g.cpp and strip all the includes (lines) containing excluded headers
# write the new file out to module.g.excl.cpp.
powershell -Command \"& {
$exclusions = get-content '${CPPWINRT_COMPONENT_EXCLUSION_LIST}'\;
(get-content '${module_g_cpp_back_slash}')
| where {
$str = $_\;
$matches = ($exclusions | where { $str -match $_ }) \;
$matches.Length -eq 0 }
| Out-File '${module_g_ecxl_cpp_back_slash}'
}\"
powershell -Command "& { \
$exclusions = get-content '${CPPWINRT_COMPONENT_EXCLUSION_LIST}'; \
(get-content '${module_g_cpp_back_slash}') \
| where { \
$str = $_; \
$matches = ($exclusions | where { $str -match $_ }); \
$matches.Length -eq 0 } \
| Out-File '${module_g_ecxl_cpp_back_slash}' \
}"
BYPRODUCTS
${generated_dir_back_slash}/module.g.excl.cpp
VERBATIM
)
add_custom_target(
@ -214,4 +217,4 @@ function(add_generate_cppwinrt_sdk_headers_target
set_target_properties(${target_name} PROPERTIES FOLDER ${folder_name})
endif()
endfunction()
endfunction()

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0)
# utility
# utility
function(convert_forward_slashes_to_back input output)
string(REGEX REPLACE "/" "\\\\" backwards ${input})
set(${output} ${backwards} PARENT_SCOPE)
@ -16,7 +16,23 @@ function(get_installed_sdk
set(${sdk_folder} ${win10_sdk_root} PARENT_SCOPE)
# return the sdk version
set(${output_sdk_version} ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION} PARENT_SCOPE)
if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION)
set(${output_sdk_version} ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION} PARENT_SCOPE)
else()
# choose the SDK matching the system version, or fallback to the latest
file(GLOB win10_sdks RELATIVE "${win10_sdk_root}/UnionMetadata" "${win10_sdk_root}/UnionMetadata/*.*.*.*")
list(GET win10_sdks 0 latest_sdk)
foreach(sdk IN LISTS win10_sdks)
string(FIND ${sdk} ${CMAKE_SYSTEM_VERSION} is_system_version)
if(NOT ${is_system_version} EQUAL -1)
set(${output_sdk_version} ${sdk} PARENT_SCOPE)
return()
elseif(sdk VERSION_GREATER latest_sdk)
set(latest_sdk ${sdk})
endif()
endforeach()
set(${output_sdk_version} ${latest_sdk} PARENT_SCOPE)
endif()
endfunction()
# current sdk binary directory
@ -95,7 +111,7 @@ function(get_sdk
set(${output_sdk_version} ${winml_WINDOWS_SDK_VERSION_OVERRIDE} PARENT_SCOPE)
else()
message(
FATAL_ERROR
FATAL_ERROR
"Options winml_WINDOWS_SDK_DIR_OVERRIDE and winml_WINDOWS_SDK_VERSION_OVERRIDE must be defined together, or not at all.")
endif()
endfunction()
endfunction()

View file

@ -44,7 +44,7 @@ function(add_winml_test)
if (_UT_DEPENDS)
add_dependencies(${_UT_TARGET} ${_UT_DEPENDS})
endif()
target_link_libraries(${_UT_TARGET} PRIVATE ${_UT_LIBS} gtest windowsapp winml_lib_image ${onnxruntime_EXTERNAL_LIBRARIES} winml_lib_telemetry)
target_link_libraries(${_UT_TARGET} PRIVATE ${_UT_LIBS} gtest windowsapp winml_lib_image ${onnxruntime_EXTERNAL_LIBRARIES} winml_lib_telemetry winml_lib_api onnxruntime)
add_test(NAME ${_UT_TARGET}
COMMAND ${_UT_TARGET}
@ -69,6 +69,7 @@ add_winml_test(
SOURCES ${winml_test_api_src}
LIBS winml_test_common
)
target_compile_definitions(winml_test_api PRIVATE BUILD_GOOGLE_TEST)
target_precompiled_header(winml_test_api testPch.h)
if (onnxruntime_USE_DML)

View file

@ -232,12 +232,8 @@ Memory_LeakCheck::~Memory_LeakCheck() {
_snprintf_s(buffer, _TRUNCATE, "%d bytes of memory leaked in %d allocations", leaked_bytes, leak_count);
string.append(buffer);
// If we're being actively debugged, show a message box to get the dev's attention
if (IsDebuggerPresent())
MessageBoxA(nullptr, string.c_str(), "Warning", MB_OK | MB_ICONWARNING);
else {
// If we're on the command line (like on a build machine), output to the console and exit(-1)
std::cout << "\n----- MEMORY LEAKS: " << string.c_str() << "\n";
std::cout << "\n----- MEMORY LEAKS: " << string.c_str() << "\n";
if (!IsDebuggerPresent()) {
exit(-1);
}

View file

@ -9,6 +9,7 @@
#include <d3d11on12.h>
#include <wil/winrt.h>
#include "inc/DeviceHelpers.h"
#include "LearningModelDevice.h"
namespace DeviceHelpers {
constexpr uint32_t c_intelVendorId = 0x8086;
@ -133,6 +134,10 @@ static HRESULT IsFloat16Blocked(ID3D12Device& device, bool* isBlocked) {
}
bool IsFloat16Supported(const winrt::Windows::AI::MachineLearning::LearningModelDevice& device) {
auto modelImpl = device.as<winmlp::LearningModelDevice>();
if (modelImpl->IsCpuDevice()) {
return true;
}
winrt::com_ptr<ID3D12Device> d3d12Device;
if (FAILED(GetD3D12Device(device, d3d12Device.put()))) {
return false;

View file

@ -5,37 +5,25 @@
//-----------------------------------------------------------------------------
#pragma once
#include <gtest/gtest.h>
class APITest : public ::testing::Test
{
protected:
void LoadModel(const std::wstring& modelPath)
{
std::wstring fullPath = FileHelpers::GetModulePath() + modelPath;
m_model = winrt::Windows::AI::MachineLearning::LearningModel::LoadFromFilePath(fullPath);
}
winrt::Windows::AI::MachineLearning::LearningModel m_model = nullptr;
winrt::Windows::AI::MachineLearning::LearningModelDevice m_device = nullptr;
winrt::Windows::AI::MachineLearning::LearningModelSession m_session = nullptr;
uint64_t GetAdapterIdQuadPart()
{
LARGE_INTEGER id;
id.LowPart = m_device.AdapterId().LowPart;
id.HighPart = m_device.AdapterId().HighPart;
return id.QuadPart;
};
_LUID GetAdapterIdAsLUID()
{
_LUID id;
id.LowPart = m_device.AdapterId().LowPart;
id.HighPart = m_device.AdapterId().HighPart;
return id;
}
bool m_runGPUTests = true;
#include "fileHelpers.h"
namespace APITest {
static void LoadModel(const std::wstring& modelPath,
winrt::Windows::AI::MachineLearning::LearningModel& learningModel) {
std::wstring fullPath = FileHelpers::GetModulePath() + modelPath;
learningModel = winrt::Windows::AI::MachineLearning::LearningModel::LoadFromFilePath(fullPath);
};
static uint64_t GetAdapterIdQuadPart(winrt::Windows::AI::MachineLearning::LearningModelDevice& device) {
LARGE_INTEGER id;
id.LowPart = device.AdapterId().LowPart;
id.HighPart = device.AdapterId().HighPart;
return id.QuadPart;
};
static _LUID GetAdapterIdAsLUID(winrt::Windows::AI::MachineLearning::LearningModelDevice& device) {
_LUID id;
id.LowPart = device.AdapterId().LowPart;
id.HighPart = device.AdapterId().HighPart;
return id;
}
}; // namespace APITest

View file

@ -1,7 +1,6 @@
#include "testPch.h"
#include "LearningModelAPITest.h"
#include "APITest.h"
#include <winrt/Windows.Graphics.Imaging.h>
#include <winrt/Windows.Media.h>
#include <winrt/Windows.Storage.h>
@ -15,107 +14,96 @@ using namespace winrt::Windows::Media;
using namespace winrt::Windows::Storage;
using namespace winrt::Windows::Storage::Streams;
class LearningModelAPITest : public APITest
{
protected:
LearningModelAPITest() {
init_apartment();
m_model = nullptr;
m_device = nullptr;
m_session = nullptr;
}
};
class LearningModelAPITestGpu : public LearningModelAPITest
{
protected:
void SetUp() override
{
GPUTEST
}
};
TEST_F(LearningModelAPITest, CreateModelFromFilePath)
{
EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx"));
static void LearningModelAPITestSetup() {
init_apartment();
}
TEST_F(LearningModelAPITest, CreateModelFromIStorage)
{
std::wstring path = FileHelpers::GetModulePath() + L"squeezenet_modifiedforruntimestests.onnx";
auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get();
EXPECT_NO_THROW(m_model = LearningModel::LoadFromStorageFileAsync(storageFile).get());
EXPECT_TRUE(m_model != nullptr);
// check the author so we know the model was populated correctly.
std::wstring author(m_model.Author());
EXPECT_EQ(L"onnx-caffe2", author);
static void LearningModelAPITestGpuSetup() {
GPUTEST;
init_apartment();
}
TEST_F(LearningModelAPITest, CreateModelFromIStorageOutsideCwd)
{
std::wstring path = FileHelpers::GetModulePath() + L"ModelSubdirectory\\ModelInSubdirectory.onnx";
auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get();
EXPECT_NO_THROW(m_model = LearningModel::LoadFromStorageFileAsync(storageFile).get());
EXPECT_TRUE(m_model != nullptr);
// check the author so we know the model was populated correctly.
std::wstring author(m_model.Author());
EXPECT_EQ(L"onnx-caffe2", author);
static void CreateModelFromFilePath() {
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel));
}
TEST_F(LearningModelAPITest, CreateModelFromIStream)
{
std::wstring path = FileHelpers::GetModulePath() + L"squeezenet_modifiedforruntimestests.onnx";
auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get();
winrt::Windows::Storage::Streams::IRandomAccessStreamReference streamref;
storageFile.as(streamref);
static void CreateModelFromIStorage() {
std::wstring path = FileHelpers::GetModulePath() + L"squeezenet_modifiedforruntimestests.onnx";
auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get();
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromStorageFileAsync(storageFile).get());
WINML_EXPECT_TRUE(learningModel != nullptr);
EXPECT_NO_THROW(m_model = LearningModel::LoadFromStreamAsync(streamref).get());
EXPECT_TRUE(m_model != nullptr);
// check the author so we know the model was populated correctly.
std::wstring author(m_model.Author());
EXPECT_EQ(L"onnx-caffe2", author);
// check the author so we know the model was populated correctly.
std::wstring author(learningModel.Author());
WINML_EXPECT_EQUAL(L"onnx-caffe2", author);
}
TEST_F(LearningModelAPITest, GetAuthor)
{
EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx"));
std::wstring author(m_model.Author());
EXPECT_EQ(L"onnx-caffe2", author);
static void CreateModelFromIStorageOutsideCwd() {
std::wstring path = FileHelpers::GetModulePath() + L"ModelSubdirectory\\ModelInSubdirectory.onnx";
auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get();
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromStorageFileAsync(storageFile).get());
WINML_EXPECT_TRUE(learningModel != nullptr);
// check the author so we know the model was populated correctly.
std::wstring author(learningModel.Author());
WINML_EXPECT_EQUAL(L"onnx-caffe2", author);
}
TEST_F(LearningModelAPITest, GetName)
{
EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx"));
std::wstring name(m_model.Name());
EXPECT_EQ(L"squeezenet_old", name);
static void CreateModelFromIStream() {
std::wstring path = FileHelpers::GetModulePath() + L"squeezenet_modifiedforruntimestests.onnx";
auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get();
winrt::Windows::Storage::Streams::IRandomAccessStreamReference streamref;
storageFile.as(streamref);
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromStreamAsync(streamref).get());
WINML_EXPECT_TRUE(learningModel != nullptr);
// check the author so we know the model was populated correctly.
std::wstring author(learningModel.Author());
WINML_EXPECT_EQUAL(L"onnx-caffe2", author);
}
TEST_F(LearningModelAPITest, GetDomain)
{
EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx"));
std::wstring domain(m_model.Domain());
EXPECT_EQ(L"test-domain", domain);
static void ModelGetAuthor() {
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel));
std::wstring author(learningModel.Author());
WINML_EXPECT_EQUAL(L"onnx-caffe2", author);
}
TEST_F(LearningModelAPITest, GetDescription)
{
EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx"));
std::wstring description(m_model.Description());
EXPECT_EQ(L"test-doc_string", description);
static void ModelGetName() {
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel));
std::wstring name(learningModel.Name());
WINML_EXPECT_EQUAL(L"squeezenet_old", name);
}
TEST_F(LearningModelAPITest, GetVersion)
{
EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx"));
int64_t version(m_model.Version());
(void)(version);
static void ModelGetDomain() {
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel));
std::wstring domain(learningModel.Domain());
WINML_EXPECT_EQUAL(L"test-domain", domain);
}
static void ModelGetDescription() {
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel));
std::wstring description(learningModel.Description());
WINML_EXPECT_EQUAL(L"test-doc_string", description);
}
static void ModelGetVersion() {
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel));
int64_t version(learningModel.Version());
(void)(version);
}
typedef std::vector<std::pair<std::wstring, std::wstring>> Metadata;
/*
class MetadataTest : public LearningModelAPITest, public testing::WithParamInterface<std::pair<std::wstring, Metadata>>
{};
@ -125,16 +113,16 @@ TEST_P(MetadataTest, GetMetaData)
std::vector<std::pair<std::wstring, std::wstring>> keyValuePairs;
tie(fileName, keyValuePairs) = GetParam();
EXPECT_NO_THROW(LoadModel(fileName.c_str()));
EXPECT_TRUE(m_model.Metadata() != nullptr);
EXPECT_EQ(keyValuePairs.size(), m_model.Metadata().Size());
WINML_EXPECT_NO_THROW(LoadModel(fileName.c_str()));
WINML_EXPECT_TRUE(m_model.Metadata() != nullptr);
WINML_EXPECT_EQUAL(keyValuePairs.size(), m_model.Metadata().Size());
auto iter = m_model.Metadata().First();
for (auto& keyValue : keyValuePairs)
{
EXPECT_TRUE(iter.HasCurrent());
EXPECT_EQ(keyValue.first, std::wstring(iter.Current().Key()));
EXPECT_EQ(keyValue.second, std::wstring(iter.Current().Value()));
WINML_EXPECT_TRUE(iter.HasCurrent());
WINML_EXPECT_EQUAL(keyValue.first, std::wstring(iter.Current().Key()));
WINML_EXPECT_EQUAL(keyValue.second, std::wstring(iter.Current().Value()));
iter.MoveNext();
}
}
@ -147,122 +135,141 @@ INSTANTIATE_TEST_SUITE_P(
std::pair(L"modelWithMetaData.onnx", Metadata{{L"thisisalongkey", L"thisisalongvalue"}}),
std::pair(L"modelWith2MetaData.onnx", Metadata{{L"thisisalongkey", L"thisisalongvalue"}, {L"key2", L"val2"}})
));
*/
TEST_F(LearningModelAPITest, EnumerateInputs)
{
EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx"));
static void EnumerateInputs() {
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel));
// purposely don't cache "InputFeatures" in order to exercise calling it multiple times
EXPECT_TRUE(m_model.InputFeatures().First().HasCurrent());
// purposely don't cache "InputFeatures" in order to exercise calling it multiple times
WINML_EXPECT_TRUE(learningModel.InputFeatures().First().HasCurrent());
std::wstring name(m_model.InputFeatures().First().Current().Name());
EXPECT_EQ(L"data_0", name);
std::wstring name(learningModel.InputFeatures().First().Current().Name());
WINML_EXPECT_EQUAL(L"data_0", name);
// make sure it's either tensor or image
TensorFeatureDescriptor tensorDescriptor = nullptr;
m_model.InputFeatures().First().Current().try_as(tensorDescriptor);
if (tensorDescriptor == nullptr)
{
ImageFeatureDescriptor imageDescriptor = nullptr;
EXPECT_NO_THROW(m_model.InputFeatures().First().Current().as(imageDescriptor));
}
// make sure it's either tensor or image
TensorFeatureDescriptor tensorDescriptor = nullptr;
learningModel.InputFeatures().First().Current().try_as(tensorDescriptor);
if (tensorDescriptor == nullptr) {
ImageFeatureDescriptor imageDescriptor = nullptr;
WINML_EXPECT_NO_THROW(learningModel.InputFeatures().First().Current().as(imageDescriptor));
}
auto modelDataKind = tensorDescriptor.TensorKind();
EXPECT_EQ(TensorKind::Float, modelDataKind);
auto modelDataKind = tensorDescriptor.TensorKind();
WINML_EXPECT_EQUAL(TensorKind::Float, modelDataKind);
EXPECT_TRUE(tensorDescriptor.IsRequired());
WINML_EXPECT_TRUE(tensorDescriptor.IsRequired());
std::vector<int64_t> expectedShapes = { 1,3,224,224 };
EXPECT_EQ(expectedShapes.size(), tensorDescriptor.Shape().Size());
for (uint32_t j = 0; j < tensorDescriptor.Shape().Size(); j++)
{
EXPECT_EQ(expectedShapes.at(j), tensorDescriptor.Shape().GetAt(j));
}
std::vector<int64_t> expectedShapes = {1, 3, 224, 224};
WINML_EXPECT_EQUAL(expectedShapes.size(), tensorDescriptor.Shape().Size());
for (uint32_t j = 0; j < tensorDescriptor.Shape().Size(); j++) {
WINML_EXPECT_EQUAL(expectedShapes.at(j), tensorDescriptor.Shape().GetAt(j));
}
auto first = m_model.InputFeatures().First();
first.MoveNext();
EXPECT_FALSE(first.HasCurrent());
auto first = learningModel.InputFeatures().First();
first.MoveNext();
WINML_EXPECT_FALSE(first.HasCurrent());
}
TEST_F(LearningModelAPITest, EnumerateOutputs)
{
EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx"));
static void EnumerateOutputs() {
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel));
// purposely don't cache "OutputFeatures" in order to exercise calling it multiple times
std::wstring name(m_model.OutputFeatures().First().Current().Name());
EXPECT_EQ(L"softmaxout_1", name);
// purposely don't cache "OutputFeatures" in order to exercise calling it multiple times
std::wstring name(learningModel.OutputFeatures().First().Current().Name());
WINML_EXPECT_EQUAL(L"softmaxout_1", name);
TensorFeatureDescriptor tensorDescriptor = nullptr;
EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(tensorDescriptor));
EXPECT_TRUE(tensorDescriptor != nullptr);
TensorFeatureDescriptor tensorDescriptor = nullptr;
WINML_EXPECT_NO_THROW(learningModel.OutputFeatures().First().Current().as(tensorDescriptor));
WINML_EXPECT_TRUE(tensorDescriptor != nullptr);
auto tensorName = tensorDescriptor.Name();
EXPECT_EQ(L"softmaxout_1", tensorName);
auto tensorName = tensorDescriptor.Name();
WINML_EXPECT_EQUAL(L"softmaxout_1", tensorName);
auto modelDataKind = tensorDescriptor.TensorKind();
EXPECT_EQ(TensorKind::Float, modelDataKind);
auto modelDataKind = tensorDescriptor.TensorKind();
WINML_EXPECT_EQUAL(TensorKind::Float, modelDataKind);
EXPECT_TRUE(tensorDescriptor.IsRequired());
WINML_EXPECT_TRUE(tensorDescriptor.IsRequired());
std::vector<int64_t> expectedShapes = { 1, 1000, 1, 1 };
EXPECT_EQ(expectedShapes.size(), tensorDescriptor.Shape().Size());
for (uint32_t j = 0; j < tensorDescriptor.Shape().Size(); j++)
{
EXPECT_EQ(expectedShapes.at(j), tensorDescriptor.Shape().GetAt(j));
}
std::vector<int64_t> expectedShapes = {1, 1000, 1, 1};
WINML_EXPECT_EQUAL(expectedShapes.size(), tensorDescriptor.Shape().Size());
for (uint32_t j = 0; j < tensorDescriptor.Shape().Size(); j++) {
WINML_EXPECT_EQUAL(expectedShapes.at(j), tensorDescriptor.Shape().GetAt(j));
}
auto first = m_model.OutputFeatures().First();
first.MoveNext();
EXPECT_FALSE(first.HasCurrent());
auto first = learningModel.OutputFeatures().First();
first.MoveNext();
WINML_EXPECT_FALSE(first.HasCurrent());
}
TEST_F(LearningModelAPITest, CloseModelCheckMetadata)
{
EXPECT_NO_THROW(LoadModel(L"squeezenet_modifiedforruntimestests.onnx"));
EXPECT_NO_THROW(m_model.Close());
std::wstring author(m_model.Author());
EXPECT_EQ(L"onnx-caffe2", author);
std::wstring name(m_model.Name());
EXPECT_EQ(L"squeezenet_old", name);
std::wstring domain(m_model.Domain());
EXPECT_EQ(L"test-domain", domain);
std::wstring description(m_model.Description());
EXPECT_EQ(L"test-doc_string", description);
int64_t version(m_model.Version());
EXPECT_EQ(123456, version);
static void CloseModelCheckMetadata() {
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"squeezenet_modifiedforruntimestests.onnx", learningModel));
WINML_EXPECT_NO_THROW(learningModel.Close());
std::wstring author(learningModel.Author());
WINML_EXPECT_EQUAL(L"onnx-caffe2", author);
std::wstring name(learningModel.Name());
WINML_EXPECT_EQUAL(L"squeezenet_old", name);
std::wstring domain(learningModel.Domain());
WINML_EXPECT_EQUAL(L"test-domain", domain);
std::wstring description(learningModel.Description());
WINML_EXPECT_EQUAL(L"test-doc_string", description);
int64_t version(learningModel.Version());
WINML_EXPECT_EQUAL(123456, version);
}
TEST_F(LearningModelAPITestGpu, CloseModelCheckEval)
{
EXPECT_NO_THROW(LoadModel(L"model.onnx"));
LearningModelSession session = nullptr;
EXPECT_NO_THROW(session = LearningModelSession(m_model));
EXPECT_NO_THROW(m_model.Close());
static void CloseModelCheckEval() {
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel));
LearningModelSession session = nullptr;
WINML_EXPECT_NO_THROW(session = LearningModelSession(learningModel));
WINML_EXPECT_NO_THROW(learningModel.Close());
std::wstring fullImagePath = FileHelpers::GetModulePath() + L"kitten_224.png";
StorageFile imagefile = StorageFile::GetFileFromPathAsync(fullImagePath).get();
IRandomAccessStream stream = imagefile.OpenAsync(FileAccessMode::Read).get();
SoftwareBitmap softwareBitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get();
VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(softwareBitmap);
std::wstring fullImagePath = FileHelpers::GetModulePath() + L"kitten_224.png";
StorageFile imagefile = StorageFile::GetFileFromPathAsync(fullImagePath).get();
IRandomAccessStream stream = imagefile.OpenAsync(FileAccessMode::Read).get();
SoftwareBitmap softwareBitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get();
VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(softwareBitmap);
LearningModelBinding binding = nullptr;
EXPECT_NO_THROW(binding = LearningModelBinding(session));
EXPECT_NO_THROW(binding.Bind(m_model.InputFeatures().First().Current().Name(), frame));
LearningModelBinding binding = nullptr;
WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session));
WINML_EXPECT_NO_THROW(binding.Bind(learningModel.InputFeatures().First().Current().Name(), frame));
EXPECT_NO_THROW(session.Evaluate(binding, L""));
WINML_EXPECT_NO_THROW(session.Evaluate(binding, L""));
}
TEST_F(LearningModelAPITest, CloseModelNoNewSessions)
{
EXPECT_NO_THROW(LoadModel(L"model.onnx"));
EXPECT_NO_THROW(m_model.Close());
LearningModelSession session = nullptr;
EXPECT_THROW(
try {
session = LearningModelSession(m_model);
} catch (const winrt::hresult_error& e) {
EXPECT_EQ(E_INVALIDARG, e.code());
throw;
}
, winrt::hresult_error);
static void CloseModelNoNewSessions() {
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel));
WINML_EXPECT_NO_THROW(learningModel.Close());
LearningModelSession session = nullptr;
WINML_EXPECT_THROW_SPECIFIC(
session = LearningModelSession(learningModel);,
winrt::hresult_error,
[](const winrt::hresult_error& e) -> bool {
return e.code() == E_INVALIDARG;
});
}
const LearningModelApiTestApi& getapi() {
static constexpr LearningModelApiTestApi api =
{
LearningModelAPITestSetup,
LearningModelAPITestGpuSetup,
CreateModelFromFilePath,
CreateModelFromIStorage,
CreateModelFromIStorageOutsideCwd,
CreateModelFromIStream,
ModelGetAuthor,
ModelGetName,
ModelGetDomain,
ModelGetDescription,
ModelGetVersion,
EnumerateInputs,
EnumerateOutputs,
CloseModelCheckMetadata,
CloseModelCheckEval,
CloseModelNoNewSessions
};
return api;
}

View file

@ -0,0 +1,41 @@
#include "test.h"
struct LearningModelApiTestApi
{
SetupTest LearningModelAPITestSetup;
SetupTest LearningModelAPITestGpuSetup;
VoidTest CreateModelFromFilePath;
VoidTest CreateModelFromIStorage;
VoidTest CreateModelFromIStorageOutsideCwd;
VoidTest CreateModelFromIStream;
VoidTest ModelGetAuthor;
VoidTest ModelGetName;
VoidTest ModelGetDomain;
VoidTest ModelGetDescription;
VoidTest ModelGetVersion;
VoidTest EnumerateInputs;
VoidTest EnumerateOutputs;
VoidTest CloseModelCheckMetadata;
VoidTest CloseModelCheckEval;
VoidTest CloseModelNoNewSessions;
};
const LearningModelApiTestApi& getapi();
WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelAPITest, LearningModelAPITestSetup)
WINML_TEST(LearningModelAPITest, CreateModelFromFilePath)
WINML_TEST(LearningModelAPITest, CreateModelFromIStorage)
WINML_TEST(LearningModelAPITest, CreateModelFromIStorageOutsideCwd)
WINML_TEST(LearningModelAPITest, CreateModelFromIStream)
WINML_TEST(LearningModelAPITest, ModelGetAuthor)
WINML_TEST(LearningModelAPITest, ModelGetName)
WINML_TEST(LearningModelAPITest, ModelGetDomain)
WINML_TEST(LearningModelAPITest, ModelGetDescription)
WINML_TEST(LearningModelAPITest, ModelGetVersion)
WINML_TEST(LearningModelAPITest, EnumerateInputs)
WINML_TEST(LearningModelAPITest, EnumerateOutputs)
WINML_TEST(LearningModelAPITest, CloseModelCheckMetadata)
WINML_TEST(LearningModelAPITest, CloseModelNoNewSessions)
WINML_TEST_CLASS_END()
WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelAPITestGpu, LearningModelAPITestGpuSetup)
WINML_TEST(LearningModelAPITestGpu, CloseModelCheckEval)
WINML_TEST_CLASS_END()

View file

@ -1,13 +1,14 @@
#include "testPch.h"
#include "APITest.h"
#include "LearningModelBindingAPITest.h"
#include "SqueezeNetValidator.h"
#include <winrt/Windows.Graphics.Imaging.h>
#include <winrt/Windows.Media.h>
#include "winrt/Windows.Storage.h"
#include "DeviceHelpers.h"
#include <sstream>
using namespace winrt;
using namespace winrt::Windows::AI::MachineLearning;
using namespace winrt::Windows::Foundation::Collections;
@ -15,25 +16,22 @@ using namespace winrt::Windows::Graphics::Imaging;
using namespace winrt::Windows::Media;
using namespace winrt::Windows::Storage;
class LearningModelBindingAPITest : public APITest
{};
static void LearningModelBindingAPITestSetup() {
init_apartment();
}
class LearningModelBindingAPITestGpu : public LearningModelBindingAPITest
{
protected:
void SetUp() override
{
GPUTEST
}
};
static void LearningModelBindingAPITestGpuSetup() {
GPUTEST;
init_apartment();
}
TEST_F(LearningModelBindingAPITest, CpuSqueezeNet)
static void CpuSqueezeNet()
{
std::string cpuInstance("CPU");
WinML::Engine::Test::ModelValidator::SqueezeNet(cpuInstance, LearningModelDeviceKind::Cpu, /*dataTolerance*/ 0.00001f, false);
}
TEST_F(LearningModelBindingAPITest, CpuSqueezeNetEmptyOutputs)
static void CpuSqueezeNetEmptyOutputs()
{
std::string cpuInstance("CPU");
WinML::Engine::Test::ModelValidator::SqueezeNet(
@ -44,7 +42,7 @@ TEST_F(LearningModelBindingAPITest, CpuSqueezeNetEmptyOutputs)
OutputBindingStrategy::Empty);
}
TEST_F(LearningModelBindingAPITest, CpuSqueezeNetUnboundOutputs)
static void CpuSqueezeNetUnboundOutputs()
{
std::string cpuInstance("CPU");
WinML::Engine::Test::ModelValidator::SqueezeNet(
@ -55,7 +53,7 @@ TEST_F(LearningModelBindingAPITest, CpuSqueezeNetUnboundOutputs)
OutputBindingStrategy::Unbound);
}
TEST_F(LearningModelBindingAPITest, CpuSqueezeNetBindInputTensorAsInspectable)
static void CpuSqueezeNetBindInputTensorAsInspectable()
{
std::string cpuInstance("CPU");
WinML::Engine::Test::ModelValidator::SqueezeNet(
@ -67,27 +65,28 @@ TEST_F(LearningModelBindingAPITest, CpuSqueezeNetBindInputTensorAsInspectable)
true /* bind inputs as inspectables */);
}
TEST_F(LearningModelBindingAPITest, CastMapInt64)
static void CastMapInt64()
{
EXPECT_NO_THROW(LoadModel(L"castmap-int64.onnx"));
WINML_EXPECT_NO_THROW(LearningModel::LoadFromFilePath(FileHelpers::GetModulePath() + L"castmap-int64.onnx"));
// TODO: Check Descriptor
}
TEST_F(LearningModelBindingAPITest, DictionaryVectorizerMapInt64)
static void DictionaryVectorizerMapInt64()
{
EXPECT_NO_THROW(LoadModel(L"dictvectorizer-int64.onnx"));
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"dictvectorizer-int64.onnx", learningModel));
auto inputDescriptor = m_model.InputFeatures().First().Current();
EXPECT_TRUE(inputDescriptor.Kind() == LearningModelFeatureKind::Map);
auto inputDescriptor = learningModel.InputFeatures().First().Current();
WINML_EXPECT_TRUE(inputDescriptor.Kind() == LearningModelFeatureKind::Map);
auto mapDescriptor = inputDescriptor.as<MapFeatureDescriptor>();
EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::Int64);
EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor);
WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::Int64);
WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor);
auto tensorDescriptor = mapDescriptor.ValueDescriptor().as<TensorFeatureDescriptor>();
// empty size means tensor of scalar value
EXPECT_TRUE(tensorDescriptor.Shape().Size() == 0);
EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float);
WINML_EXPECT_TRUE(tensorDescriptor.Shape().Size() == 0);
WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float);
LearningModelSession modelSession(m_model);
LearningModelSession modelSession(learningModel);
LearningModelBinding binding(modelSession);
std::unordered_map<int64_t, float> map;
map[1] = 1.f;
@ -102,38 +101,39 @@ TEST_F(LearningModelBindingAPITest, DictionaryVectorizerMapInt64)
binding.Bind(mapInputName, abiMap);
auto mapInputInspectable = abiMap.as<winrt::Windows::Foundation::IInspectable>();
auto first = binding.First();
EXPECT_TRUE(first.Current().Key() == mapInputName);
EXPECT_TRUE(first.Current().Value() == mapInputInspectable);
EXPECT_TRUE(binding.Lookup(mapInputName) == mapInputInspectable);
WINML_EXPECT_TRUE(first.Current().Key() == mapInputName);
WINML_EXPECT_TRUE(first.Current().Value() == mapInputInspectable);
WINML_EXPECT_TRUE(binding.Lookup(mapInputName) == mapInputInspectable);
// Bind as IMapView
auto mapView = abiMap.GetView();
binding.Bind(mapInputName, mapView);
mapInputInspectable = mapView.as<winrt::Windows::Foundation::IInspectable>();
first = binding.First();
EXPECT_TRUE(first.Current().Key() == mapInputName);
EXPECT_TRUE(first.Current().Value() == mapView);
EXPECT_TRUE(binding.Lookup(mapInputName) == mapView);
WINML_EXPECT_TRUE(first.Current().Key() == mapInputName);
WINML_EXPECT_TRUE(first.Current().Value() == mapView);
WINML_EXPECT_TRUE(binding.Lookup(mapInputName) == mapView);
}
TEST_F(LearningModelBindingAPITest, DictionaryVectorizerMapString)
static void DictionaryVectorizerMapString()
{
EXPECT_NO_THROW(LoadModel(L"dictvectorizer-string.onnx"));
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"dictvectorizer-string.onnx", learningModel));
auto inputDescriptor = m_model.InputFeatures().First().Current();
EXPECT_TRUE(inputDescriptor.Kind() == LearningModelFeatureKind::Map);
auto inputDescriptor = learningModel.InputFeatures().First().Current();
WINML_EXPECT_TRUE(inputDescriptor.Kind() == LearningModelFeatureKind::Map);
auto mapDescriptor = inputDescriptor.as<MapFeatureDescriptor>();
EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::String);
EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor);
WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::String);
WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor);
auto tensorDescriptor = mapDescriptor.ValueDescriptor().as<TensorFeatureDescriptor>();
// empty size means tensor of scalar value
EXPECT_TRUE(tensorDescriptor.Shape().Size() == 0);
EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float);
WINML_EXPECT_TRUE(tensorDescriptor.Shape().Size() == 0);
WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float);
LearningModelSession modelSession(m_model);
LearningModelSession modelSession(learningModel);
LearningModelBinding binding(modelSession);
std::unordered_map<winrt::hstring, float> map;
map[L"1"] = 1.f;
@ -146,9 +146,9 @@ TEST_F(LearningModelBindingAPITest, DictionaryVectorizerMapString)
auto mapInputInspectable = abiMap.as<winrt::Windows::Foundation::IInspectable>();
auto first = binding.First();
EXPECT_TRUE(first.Current().Key() == mapInputName);
EXPECT_TRUE(first.Current().Value() == mapInputInspectable);
EXPECT_TRUE(binding.Lookup(mapInputName) == mapInputInspectable);
WINML_EXPECT_TRUE(first.Current().Key() == mapInputName);
WINML_EXPECT_TRUE(first.Current().Value() == mapInputInspectable);
WINML_EXPECT_TRUE(binding.Lookup(mapInputName) == mapInputInspectable);
}
static void RunZipMapInt64(
@ -157,15 +157,15 @@ static void RunZipMapInt64(
{
auto outputFeatures = model.OutputFeatures();
auto outputDescriptor = outputFeatures.First().Current();
EXPECT_TRUE(outputDescriptor.Kind() == LearningModelFeatureKind::Sequence);
WINML_EXPECT_TRUE(outputDescriptor.Kind() == LearningModelFeatureKind::Sequence);
auto seqDescriptor = outputDescriptor.as<SequenceFeatureDescriptor>();
auto mapDescriptor = seqDescriptor.ElementDescriptor().as<MapFeatureDescriptor>();
EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::Int64);
WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::Int64);
EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor);
WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor);
auto tensorDescriptor = mapDescriptor.ValueDescriptor().as<TensorFeatureDescriptor>();
EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float);
WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float);
LearningModelSession session(model);
LearningModelBinding binding(session);
@ -199,63 +199,66 @@ static void RunZipMapInt64(
// from output binding
const auto &out1 = abiOutput.GetAt(0);
const auto &out2 = result.Lookup(L"Y").as<IVectorView<ABIMap>>().GetAt(0);
SCOPED_TRACE((std::ostringstream() << "size: " << out1.Size()).str());
WINML_LOG_COMMENT((std::ostringstream() << "size: " << out1.Size()).str());
// check outputs
auto iter1 = out1.First();
auto iter2 = out2.First();
for (uint32_t i = 0, size = (uint32_t)inputs.size(); i < size; ++i)
{
EXPECT_TRUE(iter1.HasCurrent());
EXPECT_TRUE(iter2.HasCurrent());
WINML_EXPECT_TRUE(iter1.HasCurrent());
WINML_EXPECT_TRUE(iter2.HasCurrent());
const auto &pair1 = iter1.Current();
const auto &pair2 = iter2.Current();
SCOPED_TRACE((std::ostringstream() << "key: " << pair1.Key() << ", value: " << pair2.Value()).str());
EXPECT_TRUE(pair1.Key() == i && pair2.Key() == i);
EXPECT_TRUE(pair1.Value() == inputs[i] && pair2.Value() == inputs[i]);
WINML_LOG_COMMENT((std::ostringstream() << "key: " << pair1.Key() << ", value: " << pair2.Value()).str());
WINML_EXPECT_TRUE(pair1.Key() == i && pair2.Key() == i);
WINML_EXPECT_TRUE(pair1.Value() == inputs[i] && pair2.Value() == inputs[i]);
iter1.MoveNext();
iter2.MoveNext();
}
EXPECT_TRUE(!iter1.HasCurrent());
EXPECT_TRUE(!iter2.HasCurrent());
WINML_EXPECT_TRUE(!iter1.HasCurrent());
WINML_EXPECT_TRUE(!iter2.HasCurrent());
}
else
{
abiOutput = result.Lookup(L"Y").as<ABISequeneceOfMap>();
EXPECT_TRUE(abiOutput.Size() == 1);
WINML_EXPECT_TRUE(abiOutput.Size() == 1);
ABIMap map = abiOutput.GetAt(0);
EXPECT_TRUE(map.Size() == 3);
EXPECT_TRUE(map.Lookup(0) == 0.5);
EXPECT_TRUE(map.Lookup(1) == .25);
EXPECT_TRUE(map.Lookup(2) == .125);
WINML_EXPECT_TRUE(map.Size() == 3);
WINML_EXPECT_TRUE(map.Lookup(0) == 0.5);
WINML_EXPECT_TRUE(map.Lookup(1) == .25);
WINML_EXPECT_TRUE(map.Lookup(2) == .125);
}
}
TEST_F(LearningModelBindingAPITest, ZipMapInt64)
static void ZipMapInt64()
{
EXPECT_NO_THROW(LoadModel(L"zipmap-int64.onnx"));
RunZipMapInt64(m_model, OutputBindingStrategy::Bound);
LearningModel learningModel= nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-int64.onnx", learningModel));
RunZipMapInt64(learningModel, OutputBindingStrategy::Bound);
}
TEST_F(LearningModelBindingAPITest, ZipMapInt64Unbound)
static void ZipMapInt64Unbound()
{
EXPECT_NO_THROW(LoadModel(L"zipmap-int64.onnx"));
RunZipMapInt64(m_model, OutputBindingStrategy::Unbound);
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-int64.onnx", learningModel));
RunZipMapInt64(learningModel, OutputBindingStrategy::Unbound);
}
TEST_F(LearningModelBindingAPITest, ZipMapString)
static void ZipMapString()
{
// output constraint: "seq(map(string, float))" or "seq(map(int64, float))"
EXPECT_NO_THROW(LoadModel(L"zipmap-string.onnx"));
auto outputs = m_model.OutputFeatures();
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-string.onnx", learningModel));
auto outputs = learningModel.OutputFeatures();
auto outputDescriptor = outputs.First().Current();
EXPECT_TRUE(outputDescriptor.Kind() == LearningModelFeatureKind::Sequence);
WINML_EXPECT_TRUE(outputDescriptor.Kind() == LearningModelFeatureKind::Sequence);
auto mapDescriptor = outputDescriptor.as<SequenceFeatureDescriptor>().ElementDescriptor().as<MapFeatureDescriptor>();
EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::String);
EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor);
WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::String);
WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor);
auto tensorDescriptor = mapDescriptor.ValueDescriptor().as<TensorFeatureDescriptor>();
EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float);
WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float);
LearningModelSession session(m_model);
LearningModelSession session(learningModel);
LearningModelBinding binding(session);
std::vector<float> inputs = { 0.5f, 0.25f, 0.125f };
@ -274,27 +277,27 @@ TEST_F(LearningModelBindingAPITest, ZipMapString)
// from output binding
const auto &out1 = ABIOutput.GetAt(0);
const auto &out2 = result.Lookup(L"Y").as<IVectorView<ABIMap>>().GetAt(0);
SCOPED_TRACE((std::ostringstream() << "size: " << out1.Size()).str());
WINML_LOG_COMMENT((std::ostringstream() << "size: " << out1.Size()).str());
// single key,value pair for each map
auto iter1 = out1.First();
auto iter2 = out2.First();
for (uint32_t i = 0, size = (uint32_t)inputs.size(); i < size; ++i)
{
EXPECT_TRUE(iter2.HasCurrent());
WINML_EXPECT_TRUE(iter2.HasCurrent());
const auto &pair1 = iter1.Current();
const auto &pair2 = iter2.Current();
SCOPED_TRACE((std::ostringstream() << "key: " << pair1.Key().c_str() << ", value " << pair2.Value()).str());
EXPECT_TRUE(std::wstring(pair1.Key().c_str()).compare(labels[i]) == 0);
EXPECT_TRUE(std::wstring(pair2.Key().c_str()).compare(labels[i]) == 0);
EXPECT_TRUE(pair1.Value() == inputs[i] && pair2.Value() == inputs[i]);
WINML_LOG_COMMENT((std::ostringstream() << "key: " << pair1.Key().c_str() << ", value " << pair2.Value()).str());
WINML_EXPECT_TRUE(std::wstring(pair1.Key().c_str()).compare(labels[i]) == 0);
WINML_EXPECT_TRUE(std::wstring(pair2.Key().c_str()).compare(labels[i]) == 0);
WINML_EXPECT_TRUE(pair1.Value() == inputs[i] && pair2.Value() == inputs[i]);
iter1.MoveNext();
iter2.MoveNext();
}
EXPECT_TRUE(!iter1.HasCurrent());
EXPECT_TRUE(!iter2.HasCurrent());
WINML_EXPECT_TRUE(!iter1.HasCurrent());
WINML_EXPECT_TRUE(!iter2.HasCurrent());
}
TEST_F(LearningModelBindingAPITestGpu, GpuSqueezeNet)
static void GpuSqueezeNet()
{
std::string gpuInstance("GPU");
WinML::Engine::Test::ModelValidator::SqueezeNet(
@ -303,7 +306,7 @@ TEST_F(LearningModelBindingAPITestGpu, GpuSqueezeNet)
/*dataTolerance*/ 0.00001f);
}
TEST_F(LearningModelBindingAPITestGpu, GpuSqueezeNetEmptyOutputs)
static void GpuSqueezeNetEmptyOutputs()
{
std::string gpuInstance("GPU");
WinML::Engine::Test::ModelValidator::SqueezeNet(
@ -314,7 +317,7 @@ TEST_F(LearningModelBindingAPITestGpu, GpuSqueezeNetEmptyOutputs)
OutputBindingStrategy::Empty);
}
TEST_F(LearningModelBindingAPITestGpu, GpuSqueezeNetUnboundOutputs)
static void GpuSqueezeNetUnboundOutputs()
{
std::string gpuInstance("GPU");
WinML::Engine::Test::ModelValidator::SqueezeNet(
@ -326,44 +329,48 @@ TEST_F(LearningModelBindingAPITestGpu, GpuSqueezeNetUnboundOutputs)
}
// Validates that when the input image is the same as the model expects, the binding step is executed correctly.
TEST_F(LearningModelBindingAPITestGpu, ImageBindingDimensions)
static void ImageBindingDimensions()
{
LearningModelBinding m_binding = nullptr;
LearningModelBinding learningModelBinding = nullptr;
LearningModel learningModel = nullptr;
LearningModelSession learningModelSession = nullptr;
LearningModelDevice leraningModelDevice = nullptr;
std::wstring filePath = FileHelpers::GetModulePath() + L"model.onnx";
// load a model with expected input size: 224 x 224
EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::Default));
EXPECT_NO_THROW(m_model = LearningModel::LoadFromFilePath(filePath));
EXPECT_TRUE(m_model != nullptr);
EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device));
EXPECT_NO_THROW(m_binding = LearningModelBinding(m_session));
WINML_EXPECT_NO_THROW(leraningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default));
WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromFilePath(filePath));
WINML_EXPECT_TRUE(learningModel != nullptr);
WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, leraningModelDevice));
WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession));
// Create input images and execute bind
// Test Case 1: both width and height are larger than model expects
VideoFrame inputImage1(BitmapPixelFormat::Rgba8, 1000, 1000);
ImageFeatureValue inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage1);
EXPECT_NO_THROW(m_binding.Bind(L"data_0", inputTensor));
WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor));
// Test Case 2: only height is larger, while width is smaller
VideoFrame inputImage2(BitmapPixelFormat::Rgba8, 20, 1000);
inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage2);
EXPECT_NO_THROW(m_binding.Bind(L"data_0", inputTensor));
WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor));
// Test Case 3: only width is larger, while height is smaller
VideoFrame inputImage3(BitmapPixelFormat::Rgba8, 1000, 20);
inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage3);
EXPECT_NO_THROW(m_binding.Bind(L"data_0", inputTensor));
WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor));
// Test Case 4: both width and height are smaller than model expects
VideoFrame inputImage4(BitmapPixelFormat::Rgba8, 20, 20);
inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage4);
EXPECT_NO_THROW(m_binding.Bind(L"data_0", inputTensor));
WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor));
}
TEST_F(LearningModelBindingAPITestGpu, VerifyInvalidBindExceptions)
static void VerifyInvalidBindExceptions()
{
EXPECT_NO_THROW(LoadModel(L"zipmap-int64.onnx"));
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-int64.onnx", learningModel));
LearningModelSession session(m_model);
LearningModelSession session(learningModel);
LearningModelBinding binding(session);
std::vector<float> inputs = { 0.5f, 0.25f, 0.125f };
@ -384,47 +391,47 @@ TEST_F(LearningModelBindingAPITestGpu, VerifyInvalidBindExceptions)
// Bind invalid image as tensorfloat input
auto image = FileHelpers::LoadImageFeatureValue(L"227x227.png");
EXPECT_THROW_SPECIFIC(binding.Bind(L"X", image), winrt::hresult_error, ensureWinmlSizeMismatch);
WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", image), winrt::hresult_error, ensureWinmlSizeMismatch);
// Bind invalid map as tensorfloat input
std::unordered_map<float, float> map;
auto abiMap = winrt::single_threaded_map(std::move(map));
EXPECT_THROW_SPECIFIC(binding.Bind(L"X", abiMap), winrt::hresult_error, ensureWinmlInvalidBinding);
WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", abiMap), winrt::hresult_error, ensureWinmlInvalidBinding);
// Bind invalid sequence as tensorfloat input
std::vector<uint32_t> sequence;
auto abiSequence = winrt::single_threaded_vector(std::move(sequence));
EXPECT_THROW_SPECIFIC(binding.Bind(L"X", abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding);
WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding);
// Bind invalid tensor size as tensorfloat input
auto tensorBoolean = TensorBoolean::Create();
EXPECT_THROW_SPECIFIC(binding.Bind(L"X", tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding);
WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding);
// Bind invalid tensor shape as tensorfloat input
auto tensorInvalidShape = TensorFloat::Create(std::vector<int64_t> { 2, 3, 4 });
EXPECT_THROW_SPECIFIC(binding.Bind(L"X", tensorInvalidShape), winrt::hresult_error, ensureWinmlInvalidBinding);
WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", tensorInvalidShape), winrt::hresult_error, ensureWinmlInvalidBinding);
/*
Verify sequence bindings throw correct bind exceptions
*/
// Bind invalid image as sequence<map<int, float> output
EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", image), winrt::hresult_error, ensureWinmlInvalidBinding);
WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", image), winrt::hresult_error, ensureWinmlInvalidBinding);
// Bind invalid map as sequence<map<int, float> output
EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", abiMap), winrt::hresult_error, ensureWinmlInvalidBinding);
WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", abiMap), winrt::hresult_error, ensureWinmlInvalidBinding);
// Bind invalid sequence<int> as sequence<map<int, float> output
EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding);
WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding);
// Bind invalid tensor as sequence<map<int, float> output
EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding);
WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding);
/*
Verify image bindings throw correct bind exceptions
*/
// EXPECT_NO_THROW(LoadModel(L"fns-candy.onnx"));
// WINML_EXPECT_NO_THROW(LoadModel(L"fns-candy.onnx"));
// LearningModelSession imageSession(m_model);
// LearningModelBinding imageBinding(imageSession);
@ -432,74 +439,77 @@ TEST_F(LearningModelBindingAPITestGpu, VerifyInvalidBindExceptions)
// auto inputName = m_model.InputFeatures().First().Current().Name();
// // Bind invalid map as image input
// EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, abiMap), winrt::hresult_error, ensureWinmlInvalidBinding);
// WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, abiMap), winrt::hresult_error, ensureWinmlInvalidBinding);
// // Bind invalid sequence as image input
// EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding);
// WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding);
// // Bind invalid tensor type as image input
// EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding);
// WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding);
// // Bind invalid tensor size as image input
// auto tensorFloat = TensorFloat::Create(std::vector<int64_t> { 1, 1, 100, 100 });
// EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorFloat), winrt::hresult_error, ensureWinmlInvalidBinding);
// WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorFloat), winrt::hresult_error, ensureWinmlInvalidBinding);
// // Bind invalid tensor shape as image input
// EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorInvalidShape), winrt::hresult_error, ensureWinmlInvalidBinding);
// WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorInvalidShape), winrt::hresult_error, ensureWinmlInvalidBinding);
/*
Verify map bindings throw correct bind exceptions
*/
EXPECT_NO_THROW(LoadModel(L"dictvectorizer-int64.onnx"));
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"dictvectorizer-int64.onnx", learningModel));
LearningModelSession mapSession(m_model);
LearningModelSession mapSession(learningModel);
LearningModelBinding mapBinding(mapSession);
auto inputName = m_model.InputFeatures().First().Current().Name();
auto inputName = learningModel.InputFeatures().First().Current().Name();
// Bind invalid image as image input
auto smallImage = FileHelpers::LoadImageFeatureValue(L"100x100.png");
EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, smallImage), winrt::hresult_error, ensureWinmlInvalidBinding);
WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, smallImage), winrt::hresult_error, ensureWinmlInvalidBinding);
// Bind invalid map as image input
EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, abiMap), winrt::hresult_error, ensureWinmlInvalidBinding);
WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, abiMap), winrt::hresult_error, ensureWinmlInvalidBinding);
// Bind invalid sequence as image input
EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding);
WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding);
// Bind invalid tensor type as image input
EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding);
WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding);
}
// Verify that it throws an error when binding an invalid name.
TEST_F(LearningModelBindingAPITestGpu, BindInvalidInputName)
static void BindInvalidInputName()
{
LearningModelBinding m_binding = nullptr;
LearningModel learningModel = nullptr;
LearningModelBinding learningModelBinding = nullptr;
LearningModelDevice learningModelDevice = nullptr;
LearningModelSession learningModelSession = nullptr;
std::wstring modelPath = FileHelpers::GetModulePath() + L"Add_ImageNet1920.onnx";
EXPECT_NO_THROW(m_model = LearningModel::LoadFromFilePath(modelPath));
EXPECT_TRUE(m_model != nullptr);
EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::Default));
EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device));
EXPECT_NO_THROW(m_binding = LearningModelBinding(m_session));
WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromFilePath(modelPath));
WINML_EXPECT_TRUE(learningModel != nullptr);
WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default));
WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, learningModelDevice));
WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession));
VideoFrame iuputImage(BitmapPixelFormat::Rgba8, 1920, 1080);
ImageFeatureValue inputTensor = ImageFeatureValue::CreateFromVideoFrame(iuputImage);
auto first = m_model.InputFeatures().First();
auto first = learningModel.InputFeatures().First();
std::wstring testInvalidName = L"0";
// Verify that testInvalidName is not in model's InputFeatures
while (first.HasCurrent())
{
EXPECT_NE(testInvalidName, first.Current().Name());
WINML_EXPECT_NOT_EQUAL(testInvalidName, first.Current().Name());
first.MoveNext();
}
// Bind inputTensor to a valid input name
EXPECT_NO_THROW(m_binding.Bind(L"input_39:0", inputTensor));
WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"input_39:0", inputTensor));
// Bind inputTensor to an invalid input name
EXPECT_THROW_SPECIFIC(m_binding.Bind(testInvalidName, inputTensor),
WINML_EXPECT_THROW_SPECIFIC(learningModelBinding.Bind(testInvalidName, inputTensor),
winrt::hresult_error,
[](const winrt::hresult_error& e) -> bool
{
@ -507,15 +517,18 @@ TEST_F(LearningModelBindingAPITestGpu, BindInvalidInputName)
});
}
TEST_F(LearningModelBindingAPITest, VerifyOutputAfterEvaluateAsyncCalledTwice)
static void VerifyOutputAfterEvaluateAsyncCalledTwice()
{
LearningModelBinding m_binding = nullptr;
LearningModel learningModel = nullptr;
LearningModelBinding learningModelBinding = nullptr;
LearningModelDevice learningModelDevice = nullptr;
LearningModelSession learningModelSession = nullptr;
std::wstring filePath = FileHelpers::GetModulePath() + L"relu.onnx";
EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::Default));
EXPECT_NO_THROW(m_model = LearningModel::LoadFromFilePath(filePath));
EXPECT_TRUE(m_model != nullptr);
EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device));
EXPECT_NO_THROW(m_binding = LearningModelBinding(m_session));
WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default));
WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromFilePath(filePath));
WINML_EXPECT_TRUE(learningModel != nullptr);
WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, learningModelDevice));
WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession));
auto inputShape = std::vector<int64_t>{ 5 };
auto inputData1 = std::vector<float>{ -50.f, -25.f, 0.f, 25.f, 50.f };
@ -530,22 +543,22 @@ TEST_F(LearningModelBindingAPITest, VerifyOutputAfterEvaluateAsyncCalledTwice)
inputShape,
single_threaded_vector<float>(std::move(inputData2)).GetView());
EXPECT_NO_THROW(m_binding.Bind(L"X", inputValue1));
WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"X", inputValue1));
auto outputValue = TensorFloat::Create();
EXPECT_NO_THROW(m_binding.Bind(L"Y", outputValue));
WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"Y", outputValue));
EXPECT_NO_THROW(m_session.Evaluate(m_binding, L""));
WINML_EXPECT_NO_THROW(learningModelSession.Evaluate(learningModelBinding, L""));
auto buffer1 = outputValue.GetAsVectorView();
EXPECT_TRUE(buffer1 != nullptr);
WINML_EXPECT_TRUE(buffer1 != nullptr);
// The second evaluation
// If we don't bind output again, the output value will not change
EXPECT_NO_THROW(m_binding.Bind(L"X", inputValue2));
EXPECT_NO_THROW(m_session.Evaluate(m_binding, L""));
WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"X", inputValue2));
WINML_EXPECT_NO_THROW(learningModelSession.Evaluate(learningModelBinding, L""));
auto buffer2 = outputValue.GetAsVectorView();
EXPECT_EQ(buffer1.Size(), buffer2.Size());
WINML_EXPECT_EQUAL(buffer1.Size(), buffer2.Size());
bool isSame = true;
for (uint32_t i = 0; i < buffer1.Size(); ++i)
{
@ -555,7 +568,7 @@ TEST_F(LearningModelBindingAPITest, VerifyOutputAfterEvaluateAsyncCalledTwice)
break;
}
}
EXPECT_FALSE(isSame);
WINML_EXPECT_FALSE(isSame);
}
static VideoFrame CreateVideoFrame(const wchar_t* path)
@ -567,7 +580,7 @@ static VideoFrame CreateVideoFrame(const wchar_t* path)
return VideoFrame::CreateWithSoftwareBitmap(softwareBitmap);
}
TEST_F(LearningModelBindingAPITest, VerifyOutputAfterImageBindCalledTwice)
static void VerifyOutputAfterImageBindCalledTwice()
{
std::wstring fullModelPath = FileHelpers::GetModulePath() + L"model.onnx";
std::wstring fullImagePath1 = FileHelpers::GetModulePath() + L"kitten_224.png";
@ -575,9 +588,9 @@ TEST_F(LearningModelBindingAPITest, VerifyOutputAfterImageBindCalledTwice)
// winml model creation
LearningModel model = nullptr;
EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(fullModelPath));
WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(fullModelPath));
LearningModelSession modelSession = nullptr;
EXPECT_NO_THROW(modelSession = LearningModelSession(model, LearningModelDevice(LearningModelDeviceKind::Default)));
WINML_EXPECT_NO_THROW(modelSession = LearningModelSession(model, LearningModelDevice(LearningModelDeviceKind::Default)));
LearningModelBinding modelBinding(modelSession);
// create the tensor for the actual output
@ -587,8 +600,8 @@ TEST_F(LearningModelBindingAPITest, VerifyOutputAfterImageBindCalledTwice)
// Bind image 1 and evaluate
auto frame = CreateVideoFrame(fullImagePath1.c_str());
auto imageTensor = ImageFeatureValue::CreateFromVideoFrame(frame);
EXPECT_NO_THROW(modelBinding.Bind(L"data_0", imageTensor));
EXPECT_NO_THROW(modelSession.Evaluate(modelBinding, L""));
WINML_EXPECT_NO_THROW(modelBinding.Bind(L"data_0", imageTensor));
WINML_EXPECT_NO_THROW(modelSession.Evaluate(modelBinding, L""));
// Store 1st result
auto outputVectorView1 = output.GetAsVectorView();
@ -598,13 +611,13 @@ TEST_F(LearningModelBindingAPITest, VerifyOutputAfterImageBindCalledTwice)
// The expected result is that the videoframe will be re-tensorized at bind
auto frame2 = CreateVideoFrame(fullImagePath2.c_str());
frame2.CopyToAsync(frame).get();
EXPECT_NO_THROW(modelBinding.Bind(L"data_0", imageTensor));
EXPECT_NO_THROW(modelSession.Evaluate(modelBinding, L""));
WINML_EXPECT_NO_THROW(modelBinding.Bind(L"data_0", imageTensor));
WINML_EXPECT_NO_THROW(modelSession.Evaluate(modelBinding, L""));
// Store 2nd result
auto outputVectorView2 = output.GetAsVectorView();
EXPECT_EQ(outputVectorView1.Size(), outputVectorView2.Size());
WINML_EXPECT_EQUAL(outputVectorView1.Size(), outputVectorView2.Size());
bool isSame = true;
for (uint32_t i = 0; i < outputVectorView1.Size(); ++i)
{
@ -614,5 +627,32 @@ TEST_F(LearningModelBindingAPITest, VerifyOutputAfterImageBindCalledTwice)
break;
}
}
EXPECT_FALSE(isSame);
WINML_EXPECT_FALSE(isSame);
}
const LearningModelBindingAPITestApi& getapi() {
static constexpr LearningModelBindingAPITestApi api =
{
LearningModelBindingAPITestSetup,
LearningModelBindingAPITestGpuSetup,
CpuSqueezeNet,
CpuSqueezeNetEmptyOutputs,
CpuSqueezeNetUnboundOutputs,
CpuSqueezeNetBindInputTensorAsInspectable,
CastMapInt64,
DictionaryVectorizerMapInt64,
DictionaryVectorizerMapString,
ZipMapInt64,
ZipMapInt64Unbound,
ZipMapString,
GpuSqueezeNet,
GpuSqueezeNetEmptyOutputs,
GpuSqueezeNetUnboundOutputs,
ImageBindingDimensions,
VerifyInvalidBindExceptions,
BindInvalidInputName,
VerifyOutputAfterEvaluateAsyncCalledTwice,
VerifyOutputAfterImageBindCalledTwice
};
return api;
}

View file

@ -0,0 +1,49 @@
#include "test.h"
struct LearningModelBindingAPITestApi {
SetupTest LearningModelBindingAPITestSetup;
SetupTest LearningModelBindingAPITestGpuSetup;
VoidTest CpuSqueezeNet;
VoidTest CpuSqueezeNetEmptyOutputs;
VoidTest CpuSqueezeNetUnboundOutputs;
VoidTest CpuSqueezeNetBindInputTensorAsInspectable;
VoidTest CastMapInt64;
VoidTest DictionaryVectorizerMapInt64;
VoidTest DictionaryVectorizerMapString;
VoidTest ZipMapInt64;
VoidTest ZipMapInt64Unbound;
VoidTest ZipMapString;
VoidTest GpuSqueezeNet;
VoidTest GpuSqueezeNetEmptyOutputs;
VoidTest GpuSqueezeNetUnboundOutputs;
VoidTest ImageBindingDimensions;
VoidTest VerifyInvalidBindExceptions;
VoidTest BindInvalidInputName;
VoidTest VerifyOutputAfterEvaluateAsyncCalledTwice;
VoidTest VerifyOutputAfterImageBindCalledTwice;
};
const LearningModelBindingAPITestApi& getapi();
WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelBindingAPITest, LearningModelBindingAPITestSetup)
WINML_TEST(LearningModelBindingAPITest, CpuSqueezeNet)
WINML_TEST(LearningModelBindingAPITest, CpuSqueezeNetEmptyOutputs)
WINML_TEST(LearningModelBindingAPITest, CpuSqueezeNetUnboundOutputs)
WINML_TEST(LearningModelBindingAPITest, CpuSqueezeNetBindInputTensorAsInspectable)
WINML_TEST(LearningModelBindingAPITest, CastMapInt64)
WINML_TEST(LearningModelBindingAPITest, DictionaryVectorizerMapInt64)
WINML_TEST(LearningModelBindingAPITest, DictionaryVectorizerMapString)
WINML_TEST(LearningModelBindingAPITest, ZipMapInt64)
WINML_TEST(LearningModelBindingAPITest, ZipMapInt64Unbound)
WINML_TEST(LearningModelBindingAPITest, ZipMapString)
WINML_TEST(LearningModelBindingAPITest, VerifyOutputAfterEvaluateAsyncCalledTwice)
WINML_TEST(LearningModelBindingAPITest, VerifyOutputAfterImageBindCalledTwice)
WINML_TEST_CLASS_END()
WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelBindingAPITestGpu, LearningModelBindingAPITestGpuSetup)
WINML_TEST(LearningModelBindingAPITestGpu, GpuSqueezeNet)
WINML_TEST(LearningModelBindingAPITestGpu, GpuSqueezeNetEmptyOutputs)
WINML_TEST(LearningModelBindingAPITestGpu, GpuSqueezeNetUnboundOutputs)
WINML_TEST(LearningModelBindingAPITestGpu, ImageBindingDimensions)
WINML_TEST(LearningModelBindingAPITestGpu, VerifyInvalidBindExceptions)
WINML_TEST(LearningModelBindingAPITestGpu, BindInvalidInputName)
WINML_TEST_CLASS_END()

View file

@ -1,6 +1,6 @@
#include "testPch.h"
#include "APITest.h"
#include "LearningModelSessionAPITest.h"
#include "winrt/Windows.Storage.h"
#include "DeviceHelpers.h"
@ -16,144 +16,151 @@ using namespace winrt::Windows::Foundation::Collections;
using winrt::Windows::Foundation::IPropertyValue;
class LearningModelSessionAPITests : public APITest
{};
class LearningModelSessionAPITestsGpu : public APITest
{
protected:
void SetUp() override
{
GPUTEST
}
};
class LearningModelSessionAPITestsSkipEdgeCore : public LearningModelSessionAPITestsGpu
{
protected:
void SetUp() override
{
LearningModelSessionAPITestsGpu::SetUp();
SKIP_EDGECORE
}
};
TEST_F(LearningModelSessionAPITests, CreateSessionDeviceDefault)
{
EXPECT_NO_THROW(LoadModel(L"model.onnx"));
EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::Default));
EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device));
static void LearningModelSessionAPITestSetup() {
init_apartment();
}
TEST_F(LearningModelSessionAPITests, CreateSessionDeviceCpu)
{
EXPECT_NO_THROW(LoadModel(L"model.onnx"));
static void LearningModelSessionAPITestGpuSetup() {
GPUTEST;
init_apartment();
}
EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::Cpu));
EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device));
static void LearningModelSessionAPITestsSkipEdgeCoreSetup() {
LearningModelSessionAPITestGpuSetup();
SKIP_EDGECORE
}
static void CreateSessionDeviceDefault()
{
LearningModel learningModel = nullptr;
LearningModelDevice learningModelDevice = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel));
WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default));
WINML_EXPECT_NO_THROW(LearningModelSession(learningModel, learningModelDevice));
}
static void CreateSessionDeviceCpu()
{
LearningModel learningModel = nullptr;
LearningModelDevice learningModelDevice = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel));
WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Cpu));
WINML_EXPECT_NO_THROW(LearningModelSession(learningModel, learningModelDevice));
// for the CPU device, make sure that we get back NULL and 0 for any device properties
EXPECT_FALSE(m_device.Direct3D11Device());
WINML_EXPECT_EQUAL(learningModelDevice.Direct3D11Device(), nullptr);
LARGE_INTEGER id;
id.QuadPart = GetAdapterIdQuadPart();
EXPECT_EQ(id.LowPart, static_cast<DWORD>(0));
EXPECT_EQ(id.HighPart, 0);
id.QuadPart = APITest::GetAdapterIdQuadPart(learningModelDevice);
WINML_EXPECT_EQUAL(id.LowPart, static_cast<DWORD>(0));
WINML_EXPECT_EQUAL(id.HighPart, 0);
}
TEST_F(LearningModelSessionAPITests, CreateSessionWithModelLoadedFromStream)
static void CreateSessionWithModelLoadedFromStream()
{
LearningModel learningModel = nullptr;
LearningModelDevice learningModelDevice = nullptr;
std::wstring path = FileHelpers::GetModulePath() + L"model.onnx";
auto storageFile = winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(path).get();
EXPECT_NO_THROW(m_model = LearningModel::LoadFromStream(storageFile));
WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromStream(storageFile));
EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::Default));
EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device));
WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default));
WINML_EXPECT_NO_THROW(LearningModelSession(learningModel, learningModelDevice));
}
TEST_F(LearningModelSessionAPITestsGpu, CreateSessionDeviceDirectX)
static void CreateSessionDeviceDirectX()
{
EXPECT_NO_THROW(LoadModel(L"model.onnx"));
LearningModel learningModel = nullptr;
LearningModelDevice learningModelDevice = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel));
EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::DirectX));
EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device));
WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectX));
WINML_EXPECT_NO_THROW(LearningModelSession(learningModel, learningModelDevice));
}
TEST_F(LearningModelSessionAPITestsGpu, CreateSessionDeviceDirectXHighPerformance)
static void CreateSessionDeviceDirectXHighPerformance()
{
EXPECT_NO_THROW(LoadModel(L"model.onnx"));
LearningModel learningModel = nullptr;
LearningModelDevice learningModelDevice = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel));
EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::DirectXHighPerformance));
EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device));
WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectXHighPerformance));
WINML_EXPECT_NO_THROW(LearningModelSession(learningModel, learningModelDevice));
}
TEST_F(LearningModelSessionAPITestsGpu, CreateSessionDeviceDirectXMinimumPower)
static void CreateSessionDeviceDirectXMinimumPower()
{
EXPECT_NO_THROW(LoadModel(L"model.onnx"));
LearningModel learningModel = nullptr;
LearningModelDevice learningModelDevice = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel));
EXPECT_NO_THROW(m_device = LearningModelDevice(LearningModelDeviceKind::DirectXMinPower));
EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device));
WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectXMinPower));
WINML_EXPECT_NO_THROW(LearningModelSession(learningModel, learningModelDevice));
}
TEST_F(LearningModelSessionAPITestsSkipEdgeCore, AdapterIdAndDevice)
{
EXPECT_NO_THROW(LoadModel(L"model.onnx"));
static void AdapterIdAndDevice() {
LearningModel learningModel = nullptr;
LearningModelDevice learningModelDevice = nullptr;
LearningModelSession learningModelSession = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel));
com_ptr<IDXGIFactory6> factory;
EXPECT_HRESULT_SUCCEEDED(CreateDXGIFactory1(__uuidof(IDXGIFactory6), factory.put_void()));
WINML_EXPECT_HRESULT_SUCCEEDED(CreateDXGIFactory1(__uuidof(IDXGIFactory6), factory.put_void()));
com_ptr<IDXGIAdapter> adapter;
m_device = LearningModelDevice(LearningModelDeviceKind::DirectX);
EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapters(0, adapter.put()));
learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectX);
WINML_EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapters(0, adapter.put()));
DXGI_ADAPTER_DESC desc;
EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc));
WINML_EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc));
LARGE_INTEGER id;
id.QuadPart = GetAdapterIdQuadPart();
EXPECT_EQ(desc.AdapterLuid.LowPart, id.LowPart);
EXPECT_EQ(desc.AdapterLuid.HighPart, id.HighPart);
EXPECT_TRUE(m_device.Direct3D11Device() != nullptr);
id.QuadPart = APITest::GetAdapterIdQuadPart(learningModelDevice);
WINML_EXPECT_EQUAL(desc.AdapterLuid.LowPart, id.LowPart);
WINML_EXPECT_EQUAL(desc.AdapterLuid.HighPart, id.HighPart);
WINML_EXPECT_TRUE(learningModelDevice.Direct3D11Device() != nullptr);
m_device = LearningModelDevice(LearningModelDeviceKind::DirectXHighPerformance);
learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectXHighPerformance);
adapter = nullptr;
EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, __uuidof(IDXGIAdapter), adapter.put_void()));
EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc));
id.QuadPart = GetAdapterIdQuadPart();
EXPECT_EQ(desc.AdapterLuid.LowPart, id.LowPart);
EXPECT_EQ(desc.AdapterLuid.HighPart, id.HighPart);
EXPECT_TRUE(m_device.Direct3D11Device() != nullptr);
WINML_EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, __uuidof(IDXGIAdapter), adapter.put_void()));
WINML_EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc));
id.QuadPart = APITest::GetAdapterIdQuadPart(learningModelDevice);
WINML_EXPECT_EQUAL(desc.AdapterLuid.LowPart, id.LowPart);
WINML_EXPECT_EQUAL(desc.AdapterLuid.HighPart, id.HighPart);
WINML_EXPECT_TRUE(learningModelDevice.Direct3D11Device() != nullptr);
adapter = nullptr;
m_device = LearningModelDevice(LearningModelDeviceKind::DirectXMinPower);
EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_MINIMUM_POWER, __uuidof(IDXGIAdapter), adapter.put_void()));
EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc));
id.QuadPart = GetAdapterIdQuadPart();
EXPECT_EQ(desc.AdapterLuid.LowPart, id.LowPart);
EXPECT_EQ(desc.AdapterLuid.HighPart, id.HighPart);
EXPECT_TRUE(m_device.Direct3D11Device() != nullptr);
learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectXMinPower);
WINML_EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_MINIMUM_POWER, __uuidof(IDXGIAdapter), adapter.put_void()));
WINML_EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc));
id.QuadPart = APITest::GetAdapterIdQuadPart(learningModelDevice);
WINML_EXPECT_EQUAL(desc.AdapterLuid.LowPart, id.LowPart);
WINML_EXPECT_EQUAL(desc.AdapterLuid.HighPart, id.HighPart);
WINML_EXPECT_TRUE(learningModelDevice.Direct3D11Device() != nullptr);
EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device));
EXPECT_EQ(m_session.Device().AdapterId(), m_device.AdapterId());
WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, learningModelDevice));
WINML_EXPECT_EQUAL(learningModelSession.Device().AdapterId(), learningModelDevice.AdapterId());
}
TEST_F(LearningModelSessionAPITests, EvaluateFeatures)
static void EvaluateFeatures()
{
std::vector<int64_t> shape = { 4 };
std::vector<winrt::hstring> data = { L"one", L"two", L"three", L"four" };
// create from buffer
auto tensor = TensorString::CreateFromArray(shape, data);
EXPECT_EQ(tensor.GetAsVectorView().Size(), data.size());
EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView())));
WINML_EXPECT_EQUAL(tensor.GetAsVectorView().Size(), data.size());
WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView())));
// create from vector view
auto dataCopy = data;
tensor = TensorString::CreateFromIterable(
shape, winrt::single_threaded_vector<winrt::hstring>(std::move(dataCopy)).GetView());
EXPECT_EQ(tensor.GetAsVectorView().Size(), data.size());
EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView())));
WINML_EXPECT_EQUAL(tensor.GetAsVectorView().Size(), data.size());
WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView())));
EXPECT_NO_THROW(LoadModel(L"id-tensor-string.onnx"));
LearningModelSession session(m_model);
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"id-tensor-string.onnx", learningModel));
LearningModelSession session(learningModel);
auto outputTensor = TensorString::Create();
@ -164,29 +171,30 @@ TEST_F(LearningModelSessionAPITests, EvaluateFeatures)
session.EvaluateFeatures(featureswinrtmap, L"0");
// verify identity model round-trip works
EXPECT_EQ(outputTensor.GetAsVectorView().Size(), data.size());
EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(outputTensor.GetAsVectorView())));
WINML_EXPECT_EQUAL(outputTensor.GetAsVectorView().Size(), data.size());
WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(outputTensor.GetAsVectorView())));
}
TEST_F(LearningModelSessionAPITests, EvaluateFeaturesAsync)
static void EvaluateFeaturesAsync()
{
std::vector<int64_t> shape = { 4 };
std::vector<winrt::hstring> data = { L"one", L"two", L"three", L"four" };
// create from buffer
auto tensor = TensorString::CreateFromArray(shape, data);
EXPECT_EQ(tensor.GetAsVectorView().Size(), data.size());
EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView())));
WINML_EXPECT_EQUAL(tensor.GetAsVectorView().Size(), data.size());
WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView())));
// create from vector view
auto dataCopy = data;
tensor = TensorString::CreateFromIterable(
shape, winrt::single_threaded_vector<winrt::hstring>(std::move(dataCopy)).GetView());
EXPECT_EQ(tensor.GetAsVectorView().Size(), data.size());
EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView())));
WINML_EXPECT_EQUAL(tensor.GetAsVectorView().Size(), data.size());
WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView())));
EXPECT_NO_THROW(LoadModel(L"id-tensor-string.onnx"));
LearningModelSession session(m_model);
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"id-tensor-string.onnx", learningModel));
LearningModelSession session(learningModel);
auto outputTensor = TensorString::Create(shape);
@ -197,37 +205,39 @@ TEST_F(LearningModelSessionAPITests, EvaluateFeaturesAsync)
session.EvaluateFeaturesAsync(featureswinrtmap, L"0").get();
// verify identity model round-trip works
EXPECT_EQ(outputTensor.GetAsVectorView().Size(), data.size());
EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(outputTensor.GetAsVectorView())));
WINML_EXPECT_EQUAL(outputTensor.GetAsVectorView().Size(), data.size());
WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(outputTensor.GetAsVectorView())));
}
TEST_F(LearningModelSessionAPITests, EvaluationProperties)
static void EvaluationProperties()
{
// load a model
EXPECT_NO_THROW(LoadModel(L"model.onnx"));
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel));
// create a session
m_session = LearningModelSession(m_model);
LearningModelSession learningModelSession = nullptr;
learningModelSession = LearningModelSession(learningModel);
// set a property
auto value = winrt::Windows::Foundation::PropertyValue::CreateBoolean(true);
m_session.EvaluationProperties().Insert(L"propName1", value);
learningModelSession.EvaluationProperties().Insert(L"propName1", value);
// get the property and make sure it's there with the right value
auto value2 = m_session.EvaluationProperties().Lookup(L"propName1");
EXPECT_EQ(value2.as<IPropertyValue>().GetBoolean(), true);
auto value2 = learningModelSession.EvaluationProperties().Lookup(L"propName1");
WINML_EXPECT_EQUAL(value2.as<IPropertyValue>().GetBoolean(), true);
}
static LearningModelSession CreateSession(LearningModel model)
{
LearningModelDevice device(nullptr);
EXPECT_NO_THROW(device = LearningModelDevice(LearningModelDeviceKind::DirectX));
WINML_EXPECT_NO_THROW(device = LearningModelDevice(LearningModelDeviceKind::DirectX));
LearningModelSession session(nullptr);
if (DeviceHelpers::IsFloat16Supported(device))
{
EXPECT_NO_THROW(session = LearningModelSession(model, device));
WINML_EXPECT_NO_THROW(session = LearningModelSession(model, device));
}
else
{
EXPECT_THROW_SPECIFIC(
WINML_EXPECT_THROW_SPECIFIC(
session = LearningModelSession(model, device),
winrt::hresult_error,
[](const winrt::hresult_error& e) -> bool
@ -239,26 +249,28 @@ static LearningModelSession CreateSession(LearningModel model)
return session;
}
TEST_F(LearningModelSessionAPITestsGpu, CreateSessionWithCastToFloat16InModel)
static void CreateSessionWithCastToFloat16InModel()
{
// load a model
EXPECT_NO_THROW(LoadModel(L"fp16-truncate-with-cast.onnx"));
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"fp16-truncate-with-cast.onnx", learningModel));
CreateSession(m_model);
CreateSession(learningModel);
}
TEST_F(LearningModelSessionAPITestsGpu, DISABLED_CreateSessionWithFloat16InitializersInModel)
static void DISABLED_CreateSessionWithFloat16InitializersInModel()
{
// Disabled due to https://microsoft.visualstudio.com/DefaultCollection/OS/_workitems/edit/21624720:
// Model fails to resolve due to ORT using incorrect IR version within partition
// load a model
EXPECT_NO_THROW(LoadModel(L"fp16-initializer.onnx"));
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"fp16-initializer.onnx", learningModel));
CreateSession(m_model);
CreateSession(learningModel);
}
static void EvaluateSessionAndCloseModel(
static void EvaluateSessionAndCloseModelHelper(
LearningModelDeviceKind kind,
bool close_model_on_session_creation)
{
@ -275,7 +287,7 @@ static void EvaluateSessionAndCloseModel(
// ensure you can create a session from the model
LearningModelSession session(nullptr);
EXPECT_NO_THROW(session = LearningModelSession(model, device, options));
WINML_EXPECT_NO_THROW(session = LearningModelSession(model, device, options));
std::vector<float> input(1000);
std::iota(std::begin(input), std::end(input), 0.0f);
@ -284,12 +296,12 @@ static void EvaluateSessionAndCloseModel(
binding.Bind(L"input", tensor_input);
LearningModelEvaluationResult result(nullptr);
EXPECT_NO_THROW(result = session.Evaluate(binding, L""));
WINML_EXPECT_NO_THROW(result = session.Evaluate(binding, L""));
if (close_model_on_session_creation)
{
// ensure that the model has been closed
EXPECT_THROW_SPECIFIC(
WINML_EXPECT_THROW_SPECIFIC(
LearningModelSession(model, device, options),
winrt::hresult_error,
[](const winrt::hresult_error& e) -> bool
@ -299,19 +311,20 @@ static void EvaluateSessionAndCloseModel(
}
else
{
EXPECT_NO_THROW(LearningModelSession(model, device, options));
WINML_EXPECT_NO_THROW(LearningModelSession(model, device, options));
}
}
TEST_F(LearningModelSessionAPITests, EvaluateSessionAndCloseModel)
static void EvaluateSessionAndCloseModel()
{
EXPECT_NO_THROW(::EvaluateSessionAndCloseModel(LearningModelDeviceKind::Cpu, true));
EXPECT_NO_THROW(::EvaluateSessionAndCloseModel(LearningModelDeviceKind::Cpu, false));
WINML_EXPECT_NO_THROW(::EvaluateSessionAndCloseModelHelper(LearningModelDeviceKind::Cpu, true));
WINML_EXPECT_NO_THROW(::EvaluateSessionAndCloseModelHelper(LearningModelDeviceKind::Cpu, false));
}
TEST_F(LearningModelSessionAPITests, CloseSession)
static void CloseSession()
{
EXPECT_NO_THROW(LoadModel(L"model.onnx"));
LearningModel learningModel = nullptr;
WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel));
LearningModelSession session = nullptr;
/*
@ -329,7 +342,7 @@ TEST_F(LearningModelSessionAPITests, CloseSession)
SIZE_T afterSessionCloseWorkingSetSize = 0;
bool getProcessMemoryInfoSuccess = false;
*/
EXPECT_NO_THROW(session = LearningModelSession(m_model));
WINML_EXPECT_NO_THROW(session = LearningModelSession(learningModel));
/*
// Get the current process memory info after session creation.
@ -341,7 +354,7 @@ TEST_F(LearningModelSessionAPITests, CloseSession)
beforeSessionCloseWorkingSetSize = pmc.WorkingSetSize;
pmc = { 0 };
*/
EXPECT_NO_THROW(session.Close());
WINML_EXPECT_NO_THROW(session.Close());
/*
Bug 23659026: Working set difference tolerance is too tight for LearningModelSessionAPITests::CloseSession
@ -367,17 +380,41 @@ TEST_F(LearningModelSessionAPITests, CloseSession)
*/
// verify that model still has metadata info after session close
std::wstring author(m_model.Author());
EXPECT_EQ(author, L"onnx-caffe2");
std::wstring author(learningModel.Author());
WINML_EXPECT_EQUAL(author, L"onnx-caffe2");
// verify that session throws RO_E_CLOSED error
std::vector<float> input(1 * 3 * 224 * 224, 0);
std::vector<int64_t> shape = { 1, 3, 224, 224 };
auto tensor_input = TensorFloat::CreateFromShapeArrayAndDataArray(shape, input);
EXPECT_THROW_SPECIFIC(LearningModelBinding binding(session),
WINML_EXPECT_THROW_SPECIFIC(LearningModelBinding binding(session),
winrt::hresult_error,
[](const winrt::hresult_error &e) -> bool
{
return e.code() == RO_E_CLOSED;
});
}
const LearningModelSesssionAPITestApi& getapi() {
static constexpr LearningModelSesssionAPITestApi api =
{
LearningModelSessionAPITestSetup,
LearningModelSessionAPITestGpuSetup,
LearningModelSessionAPITestsSkipEdgeCoreSetup,
CreateSessionDeviceDefault,
CreateSessionDeviceCpu,
CreateSessionWithModelLoadedFromStream,
CreateSessionDeviceDirectX,
CreateSessionDeviceDirectXHighPerformance,
CreateSessionDeviceDirectXMinimumPower,
AdapterIdAndDevice,
EvaluateFeatures,
EvaluateFeaturesAsync,
EvaluationProperties,
CreateSessionWithCastToFloat16InModel,
DISABLED_CreateSessionWithFloat16InitializersInModel,
EvaluateSessionAndCloseModel,
CloseSession,
};
return api;
}

View file

@ -0,0 +1,44 @@
#include "test.h"
struct LearningModelSesssionAPITestApi {
SetupTest LearningModelSessionAPITestSetup;
SetupTest LearningModelSessionAPITestGpuSetup;
SetupTest LearningModelSessionAPITestsSkipEdgeCoreSetup;
VoidTest CreateSessionDeviceDefault;
VoidTest CreateSessionDeviceCpu;
VoidTest CreateSessionWithModelLoadedFromStream;
VoidTest CreateSessionDeviceDirectX;
VoidTest CreateSessionDeviceDirectXHighPerformance;
VoidTest CreateSessionDeviceDirectXMinimumPower;
VoidTest AdapterIdAndDevice;
VoidTest EvaluateFeatures;
VoidTest EvaluateFeaturesAsync;
VoidTest EvaluationProperties;
VoidTest CreateSessionWithCastToFloat16InModel;
VoidTest DISABLED_CreateSessionWithFloat16InitializersInModel;
VoidTest EvaluateSessionAndCloseModel;
VoidTest CloseSession;
};
const LearningModelSesssionAPITestApi& getapi();
WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelSessionAPITest, LearningModelSessionAPITestSetup)
WINML_TEST(LearningModelSessionAPITest, CreateSessionDeviceDefault)
WINML_TEST(LearningModelSessionAPITest,CreateSessionDeviceCpu)
WINML_TEST(LearningModelSessionAPITest,CreateSessionWithModelLoadedFromStream)
WINML_TEST(LearningModelSessionAPITest,EvaluateFeatures)
WINML_TEST(LearningModelSessionAPITest,EvaluateFeaturesAsync)
WINML_TEST(LearningModelSessionAPITest,EvaluationProperties)
WINML_TEST(LearningModelSessionAPITest,EvaluateSessionAndCloseModel)
WINML_TEST_CLASS_END()
WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelSessionAPITestGpu, LearningModelSessionAPITestGpuSetup)
WINML_TEST(LearningModelSessionAPITestGpu, CreateSessionDeviceDirectX)
WINML_TEST(LearningModelSessionAPITestGpu, CreateSessionDeviceDirectXHighPerformance)
WINML_TEST(LearningModelSessionAPITestGpu, CreateSessionDeviceDirectXMinimumPower)
WINML_TEST(LearningModelSessionAPITestGpu, CreateSessionWithCastToFloat16InModel)
WINML_TEST(LearningModelSessionAPITestGpu, DISABLED_CreateSessionWithFloat16InitializersInModel)
WINML_TEST_CLASS_END()
WINML_TEST_CLASS_BEGIN_WITH_SETUP(LearningModelSessionAPITestsSkipEdgeCore, LearningModelSessionAPITestsSkipEdgeCoreSetup)
WINML_TEST(LearningModelSessionAPITestsSkipEdgeCore, AdapterIdAndDevice)
WINML_TEST_CLASS_END()

View file

@ -10,18 +10,20 @@
}
#define WINML_TEST_CLASS_BEGIN_NO_SETUP(test_class_name) \
class test_class_name : public ::testing::Test { \
};
namespace { \
class test_class_name : public ::testing::Test { \
};
#define WINML_TEST_CLASS_BEGIN_WITH_SETUP(test_class_name, setup_method) \
class test_class_name : public ::testing::Test { \
protected: \
void SetUp() override { \
getapi().setup_method(); \
} \
};
namespace { \
class test_class_name : public ::testing::Test { \
protected: \
void SetUp() override { \
getapi().setup_method(); \
} \
};
#define WINML_TEST_CLASS_END()
#define WINML_TEST_CLASS_END() }
// For old versions of gtest without GTEST_SKIP, stream the message and return success instead
#ifndef GTEST_SKIP
@ -30,17 +32,34 @@
#define GTEST_SKIP GTEST_SKIP_("")
#endif
#define EXPECT_THROW_SPECIFIC(statement, exception, condition) \
EXPECT_THROW( \
try { \
statement; \
} catch (const exception& e) { \
EXPECT_TRUE(condition(e)); \
throw; \
} \
, exception);
#ifndef INSTANTIATE_TEST_SUITE_P
// Use the old name, removed in newer versions of googletest
#define INSTANTIATE_TEST_SUITE_P INSTANTIATE_TEST_CASE_P
#endif
#define WINML_SKIP_TEST(message) \
GTEST_SKIP() << message;
#define WINML_EXPECT_NO_THROW(statement) EXPECT_NO_THROW(statement)
#define WINML_EXPECT_TRUE(statement) EXPECT_TRUE(statement)
#define WINML_EXPECT_FALSE(statement) EXPECT_FALSE(statement)
#define WINML_EXPECT_EQUAL(val1, val2) EXPECT_EQ(val1, val2)
#define WINML_EXPECT_NOT_EQUAL(val1, val2) EXPECT_NE(val1, val2)
#define WINML_LOG_ERROR(message) \
ADD_FAILURE() << message
#define WINML_LOG_COMMENT(message)\
SCOPED_TRACE(message)
#define WINML_EXPECT_HRESULT_SUCCEEDED(hresult_expression) EXPECT_HRESULT_SUCCEEDED(hresult_expression)
#define WINML_EXPECT_HRESULT_FAILED(hresult_expression) EXPECT_HRESULT_FAILED(hresult_expression)
#define WINML_EXPECT_THROW_SPECIFIC(statement, exception, condition) EXPECT_THROW_SPECIFIC(statement, exception, condition)
@ -60,4 +79,4 @@
if (auto isEdgeCore = RuntimeParameters::Parameters.find("EdgeCore"); \
isEdgeCore != RuntimeParameters::Parameters.end() && isEdgeCore->second != "0") { \
WINML_SKIP_TEST("Test can't be run in EdgeCore"); \
}
}

View file

@ -29,19 +29,4 @@
#include "comp_generated/winrt/windows.ai.machinelearning.h"
// WinML
#include "Windows.AI.MachineLearning.Native.h"
#define EXPECT_THROW_SPECIFIC(statement, exception, condition) \
EXPECT_THROW( \
try { \
statement; \
} catch (const exception& e) { \
EXPECT_TRUE(condition(e)); \
throw; \
} \
, exception);
#ifndef INSTANTIATE_TEST_SUITE_P
// Use the old name, removed in newer versions of googletest
#define INSTANTIATE_TEST_SUITE_P INSTANTIATE_TEST_CASE_P
#endif
#include "Windows.AI.MachineLearning.Native.h"

View file

@ -30,11 +30,13 @@ using namespace WEX::TestExecution;
#define WINML_EXPECT_NO_THROW(statement) VERIFY_NO_THROW(statement)
#define WINML_EXPECT_TRUE(statement) VERIFY_IS_TRUE(statement)
#define WINML_EXPECT_FALSE(statement) VERIFY_IS_FALSE(statement)
#define WINML_EXPECT_EQUAL(val1, val2) VERIFY_ARE_EQUAL(val1, val2)
#define WINML_EXPECT_NOT_EQUAL(val1, val2) VERIFY_ARE_NOT_EQUAL(val1, val2)
#define WINML_LOG_ERROR(message) \
VERIFY_FAIL(std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(message).c_str())
#define WINML_LOG_COMMENT(message)\
WEX::Logging::Log::Comment(std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(message).c_str())
#define WINML_EXPECT_HRESULT_SUCCEEDED(hresult_expression) VERIFY_SUCCEEDED(hresult_expression)
#define WINML_EXPECT_THROW_SPECIFIC(statement, exception, condition) VERIFY_THROWS_SPECIFIC(statement, exception, condition)
#define WINML_EXPECT_HRESULT_FAILED(hresult_expression) VERIFY_FAILED(hresult_expression)