Initial changes for layering

This commit is contained in:
Ryan Lai 2019-11-07 16:50:24 -08:00
parent b94ae8e965
commit 444bfcc26e
14 changed files with 323 additions and 182 deletions

View file

@ -425,9 +425,11 @@ if (WIN32)
# set linker flags to minimize the binary size.
if (MSVC)
foreach(type EXE SHARED)
set(CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO} /OPT:REF,ICF,LBR")
set(CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO} /INCREMENTAL:NO")
foreach(type EXE STATIC SHARED)
if (NOT type MATCHES STATIC)
set(CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO} /OPT:REF,ICF,LBR")
set(CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO} /INCREMENTAL:NO")
endif()
if (NOT onnxruntime_USE_CUDA)
set(CMAKE_${type}_LINKER_FLAGS_RELEASE "${CMAKE_${type}_LINKER_FLAGS_RELEASE} /LTCG")
set(CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_${type}_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
@ -694,6 +696,15 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Android")
list(APPEND onnxruntime_EXTERNAL_LIBRARIES log)
endif()
if (onnxruntime_USE_WINML)
if (NOT onnxruntime_USE_DML)
message(
FATAL_ERROR
"Option onnxruntime_USE_WINML can only be used when onnxruntime_USE_DML is also enabled")
endif()
include(wil.cmake)
include(winml.cmake)
endif() # if(onnxruntime_USE_WINML)
#The following files may use the 'onnxruntime_libs' and 'onnxruntime_EXTERNAL_LIBRARIES' vars
if (onnxruntime_BUILD_SHARED_LIB)
@ -733,17 +744,4 @@ if (onnxruntime_BUILD_CSHARP)
message(STATUS "CSharp Build is enabled")
# set_property(GLOBAL PROPERTY VS_DOTNET_TARGET_FRAMEWORK_VERSION "netstandard2.0")
include(onnxruntime_csharp.cmake)
endif()
if (onnxruntime_USE_WINML)
if (NOT onnxruntime_USE_DML)
message(
FATAL_ERROR
"Option onnxruntime_USE_WINML can only be used when onnxruntime_USE_DML is also enabled")
endif()
include(wil.cmake)
include(winml.cmake)
endif() # if(onnxruntime_USE_WINML)
endif()

View file

@ -11,6 +11,7 @@ set(winml_api_root ${REPO_ROOT}/winml/api)
get_sdk(sdk_folder sdk_version)
set(target_folder ONNXRuntime/winml)
set(winml_dll_dir ${REPO_ROOT}/winml/dll)
set(winml_lib_dir ${REPO_ROOT}/winml/lib)
set(winml_lib_api_dir ${REPO_ROOT}/winml/lib/api)
set(winml_lib_api_core_dir ${REPO_ROOT}/winml/lib/api.core)
set(winml_lib_api_image_dir ${REPO_ROOT}/winml/lib/api.image)
@ -126,6 +127,7 @@ add_library(winml_lib_core STATIC
${winml_lib_api_core_dir}/inc/MLValueHelpers.h
${winml_lib_api_core_dir}/inc/ModelInfo.h
${winml_lib_api_core_dir}/inc/TensorBaseHelpers.h
${winml_lib_api_core_dir}/inc/WinMLAdapter.h
${winml_lib_api_core_dir}/CpuOrtSessionBuilder.h
${winml_lib_api_core_dir}/DmlOrtSessionBuilder.h
${winml_lib_api_core_dir}/FeatureDescriptorFactory.h
@ -138,6 +140,7 @@ add_library(winml_lib_core STATIC
${winml_lib_api_core_dir}/LotusEnvironment.cpp
${winml_lib_api_core_dir}/ModelInfo.cpp
${winml_lib_api_core_dir}/OrtSessionBuilder.cpp
${winml_lib_api_core_dir}/WinMLAdapter.cpp
${winml_lib_api_core_dir}/ZeroCopyInputStreamWrapper.cpp
)
@ -167,6 +170,7 @@ target_include_directories(winml_lib_core PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/ex
target_include_directories(winml_lib_core PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/external/onnx)
target_include_directories(winml_lib_core PRIVATE ${winml_lib_api_dir}) # needed for generated headers
target_include_directories(winml_lib_core PRIVATE ${winml_lib_dir})
target_include_directories(winml_lib_core PRIVATE ${winml_lib_api_core_dir})
target_include_directories(winml_lib_core PRIVATE ${winml_lib_common_dir}/inc)
target_include_directories(winml_lib_core PRIVATE ${ONNXRUNTIME_INCLUDE_DIR})
@ -196,6 +200,10 @@ add_dependencies(winml_lib_core winml_api_native_internal)
target_link_libraries(winml_lib_core PRIVATE wil)
target_link_libraries(winml_lib_core PRIVATE onnxruntime_providers_dml)
# add it to the onnxruntime shared library
list(APPEND onnxruntime_EXTERNAL_LIBRARIES winml_lib_core)
list(APPEND onnxruntime_EXTERNAL_DEPENDENCIES winml_lib_core)
###########################
# Add winml_lib_image
###########################
@ -430,6 +438,7 @@ target_include_directories(winml_dll PRIVATE ${ONNXRUNTIME_ROOT}/core/graph)
target_include_directories(winml_dll PRIVATE ${REPO_ROOT}/cmake/external/onnx)
target_include_directories(winml_dll PRIVATE ${REPO_ROOT}/cmake/external/protobuf/src)
target_include_directories(winml_dll PRIVATE ${REPO_ROOT}/cmake/external/gsl/include)
target_include_directories(winml_dll PRIVATE ${REPO_ROOT}/cmake/external/eigen)
# Properties
set_target_properties(winml_dll
@ -463,22 +472,22 @@ endif("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
# Link libraries
target_link_libraries(winml_dll PRIVATE windowsapp.lib)
target_link_libraries(winml_dll PRIVATE libprotobuf)
target_link_libraries(winml_dll PRIVATE onnx)
target_link_libraries(winml_dll PRIVATE onnxruntime_common)
target_link_libraries(winml_dll PRIVATE onnxruntime_graph)
target_link_libraries(winml_dll PRIVATE onnxruntime_framework)
target_link_libraries(winml_dll PRIVATE onnxruntime_mlas)
target_link_libraries(winml_dll PRIVATE onnxruntime_optimizer)
target_link_libraries(winml_dll PRIVATE onnxruntime_providers)
target_link_libraries(winml_dll PRIVATE onnxruntime_providers_dml)
target_link_libraries(winml_dll PRIVATE onnxruntime_session)
target_link_libraries(winml_dll PRIVATE onnxruntime_util)
target_link_libraries(winml_dll PRIVATE onnx_proto)
# target_link_libraries(winml_dll PRIVATE libprotobuf)
# target_link_libraries(winml_dll PRIVATE onnx)
# target_link_libraries(winml_dll PRIVATE onnxruntime_common)
# target_link_libraries(winml_dll PRIVATE onnxruntime_graph)
# target_link_libraries(winml_dll PRIVATE onnxruntime_framework)
# target_link_libraries(winml_dll PRIVATE onnxruntime_mlas)
# target_link_libraries(winml_dll PRIVATE onnxruntime_optimizer)
# target_link_libraries(winml_dll PRIVATE onnxruntime_providers)
# target_link_libraries(winml_dll PRIVATE onnxruntime_providers_dml)
# target_link_libraries(winml_dll PRIVATE onnxruntime_session)
# target_link_libraries(winml_dll PRIVATE onnxruntime_util)
# target_link_libraries(winml_dll PRIVATE onnx_proto)
target_link_libraries(winml_dll PRIVATE re2)
target_link_libraries(winml_dll PRIVATE wil)
target_link_libraries(winml_dll PRIVATE winml_lib_api)
target_link_libraries(winml_dll PRIVATE winml_lib_core)
# target_link_libraries(winml_dll PRIVATE winml_lib_core)
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)

View file

@ -133,7 +133,7 @@ void ModelInfo::Initialize(
}
// factory methods for creating an ort model from a path
std::unique_ptr<onnx::ModelProto>
onnx::ModelProto*
WinML::CreateModelProto(
const char* path) {
int file_descriptor;
@ -152,7 +152,7 @@ WinML::CreateModelProto(
auto stream = google::protobuf::io::FileInputStream(file_descriptor);
stream.SetCloseOnDelete(true);
auto model_proto = std::make_unique<onnx::ModelProto>();
auto model_proto = new onnx::ModelProto();
WINML_THROW_HR_IF_FALSE_MSG(
E_INVALIDARG,
model_proto->ParseFromZeroCopyStream(&stream),
@ -162,12 +162,12 @@ WinML::CreateModelProto(
}
// factory methods for creating an ort model from a stream
std::unique_ptr<onnx::ModelProto>
onnx::ModelProto*
WinML::CreateModelProto(
const wss::IRandomAccessStreamReference& stream_reference) {
const wss::IRandomAccessStreamReference& stream_reference) {
ZeroCopyInputStreamWrapper wrapper(stream_reference);
auto model_proto = std::make_unique<onnx::ModelProto>();
auto model_proto = new onnx::ModelProto();
WINML_THROW_HR_IF_FALSE_MSG(
E_INVALIDARG,
model_proto->ParseFromZeroCopyStream(&wrapper),

View file

@ -0,0 +1,180 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "inc/WinMLAdapter.h"
#include "inc/CustomRegistryHelper.h"
#include "inc/LotusEnvironment.h"
#include "core/providers/dml/DmlExecutionProvider/inc/DmlExecutionProvider.h"
#include "LearningModelDevice.h"
#include "TensorFeatureDescriptor.h"
#include "ImageFeatureDescriptor.h"
#include "api.image/inc/D3DDeviceCache.h"
using namespace winrt::Windows::AI::MachineLearning;
namespace Windows::AI::MachineLearning::Adapter {
HRESULT STDMETHODCALLTYPE
RegisterCustomRegistry(
onnxruntime::InferenceSession* p_session,
IMLOperatorRegistry* registry) {
RETURN_HR_IF(S_OK, registry == nullptr);
RETURN_HR_IF_NULL(E_POINTER, p_session);
auto custom_registries = WinML::GetLotusCustomRegistries(registry);
// Register
for (auto& custom_registry : custom_registries) {
WINML_THROW_IF_NOT_OK(p_session->RegisterCustomRegistry(custom_registry));
}
return S_OK;
}
void STDMETHODCALLTYPE EnableDebugOutput() {
WinML::CWinMLLogSink::EnableDebugOutput();
}
// ORT intentionally requires callers derive from their session class to access
// the protected Load method used below.
class InferenceSessionProtectedLoadAccessor : public onnxruntime::InferenceSession {
public:
onnxruntime::common::Status
Load(std::unique_ptr<ONNX_NAMESPACE::ModelProto> p_model_proto) {
return onnxruntime::InferenceSession::Load(std::move(p_model_proto));
}
};
HRESULT STDMETHODCALLTYPE
LoadModel(
onnxruntime::InferenceSession* session,
onnx::ModelProto* model_proto) {
auto session_protected_load_accessor =
static_cast<InferenceSessionProtectedLoadAccessor*>(session);
std::unique_ptr<ONNX_NAMESPACE::ModelProto> model_proto_ptr(model_proto);
WINML_THROW_IF_NOT_OK(session_protected_load_accessor->Load(std::move(model_proto_ptr)));
}
static bool
IsFeatureDescriptorFp16(
winml::ILearningModelFeatureDescriptor descriptor) {
if (auto imageFeatureDescriptor = descriptor.try_as<winmlp::ImageFeatureDescriptor>()) {
return TensorKind::Float16 == imageFeatureDescriptor->TensorKind();
}
if (auto tensorFeatureDescriptor = descriptor.try_as<winmlp::TensorFeatureDescriptor>()) {
return TensorKind::Float16 == tensorFeatureDescriptor->TensorKind();
}
return false;
}
HRESULT STDMETHODCALLTYPE
EnsureModelDeviceCompatibility(
winml::LearningModel const& model,
onnx::ModelProto* p_model_proto,
winml::LearningModelDevice const& device) {
auto isFloat16Supported = device.as<winmlp::LearningModelDevice>()->GetD3DDeviceCache()->IsFloat16Supported();
if (!isFloat16Supported) {
auto& graph = p_model_proto->graph();
// The model will not contain fp16 operations if:
// 1. The model has no fp16 inputs
// 2. The model has no fp16 initializers
// 3. The model does not create any fp16 intermediary tensors via the Cast (to float16) operator
// 4. The model does not have any fp16 outputs
// 1. Ensure that The model has no fp16 inputs
for (auto descriptor : model.InputFeatures()) {
WINML_THROW_HR_IF_TRUE_MSG(
DXGI_ERROR_UNSUPPORTED,
IsFeatureDescriptorFp16(descriptor),
"The model contains a 16-bit input (%ls), but the current device does not support 16-bit float.",
descriptor.Name().c_str());
}
// 2. Ensure that the model has no fp16 initializers
for (int i = 0; i < graph.node_size(); i++) {
auto node = graph.node(i);
if (node.op_type() == "Cast" && node.domain().empty()) {
for (int attribIndex = 0; attribIndex < node.attribute_size(); attribIndex++) {
auto attribute = node.attribute(attribIndex);
if (attribute.name() == "to") {
WINML_THROW_HR_IF_TRUE_MSG(
DXGI_ERROR_UNSUPPORTED,
attribute.i() == onnx::TensorProto::DataType::TensorProto_DataType_FLOAT16,
"The model contains a 16-bit float Cast Op (%s), but the current device does not support 16-bit float.",
node.name().c_str());
}
}
}
}
// 3. Ensure that the model does not create any fp16 intermediary
// tensors via the Cast (to float16) operator
for (int i = 0; i < graph.initializer_size(); i++) {
auto initializer = graph.initializer(i);
WINML_THROW_HR_IF_TRUE_MSG(
DXGI_ERROR_UNSUPPORTED,
initializer.data_type() == onnx::TensorProto::DataType::TensorProto_DataType_FLOAT16,
"The model contains a 16-bit float initializer (%s), but the current device does not support 16-bit float.",
initializer.name().c_str());
}
// 4. Ensure that the model does not have any fp16 outputs
for (auto descriptor : model.OutputFeatures()) {
WINML_THROW_HR_IF_TRUE_MSG(
DXGI_ERROR_UNSUPPORTED,
IsFeatureDescriptorFp16(descriptor),
"The model contains a 16-bit output (%ls), but the current device does not support 16-bit float.",
descriptor.Name().c_str());
}
}
}
HRESULT STDMETHODCALLTYPE ReleaseOrtObject(onnx::ModelProto* model_proto) {
std::unique_ptr<ONNX_NAMESPACE::ModelProto> ptr(model_proto);
}
HRESULT STDMETHODCALLTYPE ReleaseOrtObject(onnxruntime::IOBinding* io_binding) {
std::unique_ptr<onnxruntime::IOBinding> ptr(io_binding);
}
ID3D12Resource* STDMETHODCALLTYPE
GetD3D12ResourceFromAllocation(
onnxruntime::IExecutionProvider* provider,
void* allocation) {
auto d3dResource =
Dml::GetD3D12ResourceFromAllocation(
provider->GetAllocator(0, ::OrtMemType::OrtMemTypeDefault).get(),
allocation);
return d3dResource;
}
onnxruntime::MLDataType GetType(winml::TensorKind kind) {
switch (kind) {
case winml::TensorKind::Float:
return onnxruntime::DataTypeImpl::GetType<float>();
case winml::TensorKind::Float16:
return onnxruntime::DataTypeImpl::GetType<onnxruntime::MLFloat16>();
};
return nullptr;
}
onnxruntime::Tensor* STDMETHODCALLTYPE CreateTensor(
winml::TensorKind kind,
const int64_t* shape,
uint32_t shape_count,
onnxruntime::IExecutionProvider* provider) {
onnxruntime::TensorShape tensor_shape(shape, shape_count);
auto pTensor = new onnxruntime::Tensor(
GetType(kind),
tensor_shape,
provider->GetAllocator(0, ::OrtMemType::OrtMemTypeDefault));
return pTensor;
}
} // namespace Windows::AI::MachineLearning::Adapter

View file

@ -3,6 +3,8 @@
#pragma once
#include "WinMLAdapter.h"
namespace Windows::AI::MachineLearning {
class ModelInfo {
@ -25,9 +27,9 @@ class ModelInfo {
};
// factory methods for creating an ort model from a path
std::unique_ptr<onnx::ModelProto> CreateModelProto(const char* path);
onnx::ModelProto* CreateModelProto(const char* path);
// factory methods for creating an ort model from a stream
std::unique_ptr<onnx::ModelProto> CreateModelProto(const wss::IRandomAccessStreamReference& stream_reference);
onnx::ModelProto* CreateModelProto(const wss::IRandomAccessStreamReference& stream_reference);
} // namespace Windows::AI::MachineLearning

View file

@ -0,0 +1,55 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
namespace Windows::AI::MachineLearning::Adapter {
__declspec(dllexport) HRESULT STDMETHODCALLTYPE ReleaseOrtObject(onnx::ModelProto* model_proto);
__declspec(dllexport) HRESULT STDMETHODCALLTYPE ReleaseOrtObject(onnxruntime::IOBinding* io_binding);
__declspec(dllexport) HRESULT STDMETHODCALLTYPE RegisterCustomRegistry(
onnxruntime::InferenceSession* p_session,
IMLOperatorRegistry* registry);
__declspec(dllexport) void STDMETHODCALLTYPE EnableDebugOutput();
__declspec(dllexport) HRESULT STDMETHODCALLTYPE LoadModel(onnxruntime::InferenceSession* session, onnx::ModelProto* model);
__declspec(dllexport) HRESULT STDMETHODCALLTYPE EnsureModelDeviceCompatibility(
winml::LearningModel const& model,
onnx::ModelProto* p_model_proto,
winml::LearningModelDevice const& device);
__declspec(dllexport) ID3D12Resource* STDMETHODCALLTYPE GetD3D12ResourceFromAllocation(onnxruntime::IExecutionProvider* provider, void* allocation);
__declspec(dllexport) onnxruntime::Tensor* STDMETHODCALLTYPE CreateTensor(
winml::TensorKind kind,
const int64_t * shape,
uint32_t shape_count,
onnxruntime::IExecutionProvider* provider);
// header only code to enable smart pointers on abstract ort objects
template <typename T>
class OrtObject {
public:
OrtObject() {
p_ = nullptr;
}
OrtObject(T* m) {
p_ = m;
}
virtual ~OrtObject() {
if (p_ != nullptr) {
ReleaseOrtObject(p_);
}
}
T* p_;
};
using ModelProto = OrtObject<onnx::ModelProto>;
using IOBinding = OrtObject<onnxruntime::IOBinding>;
} // namespace Windows::AI::MachineLearning::Adapter

View file

@ -3,4 +3,5 @@
#pragma once
#include "cppwinrt_onnx.h"
#include "cppwinrt_onnx.h"
#include "dx.h"

View file

@ -28,6 +28,6 @@ enum ImageTensorChannelType {
struct ImageTensorDescription {
ImageTensorDataType dataType;
ImageTensorChannelType channelType;
UINT sizes[kImageTensorDimensionCountMax];
int64_t sizes[kImageTensorDimensionCountMax];
};
} // namespace Windows::AI::MachineLearning::Internal

View file

@ -347,8 +347,8 @@ static void GPUTensorize(
void* pAllocatedResource,
WinML::BindingContext& context) {
auto d3dResource =
Dml::GetD3D12ResourceFromAllocation(
spSession->GetExecutionProvider()->GetAllocator(0, ::OrtMemType::OrtMemTypeDefault).get(),
_winmla::GetD3D12ResourceFromAllocation(
spSession->GetExecutionProvider(),
pAllocatedResource);
auto spDevice = spSession->Device().as<LearningModelDevice>();
@ -391,14 +391,11 @@ static void GPUTensorize(
static OrtValue CreateMLValue(
com_ptr<LearningModelSession> spSession,
const ImageTensorDescription& tensorDescriptor) {
auto shape =
std::vector<int64_t>(
std::begin(tensorDescriptor.sizes),
std::end(tensorDescriptor.sizes));
auto pTensor = new onnxruntime::Tensor(
tensorDescriptor.dataType == kImageTensorDataTypeFloat32 ? onnxruntime::DataTypeImpl::GetType<float>() : onnxruntime::DataTypeImpl::GetType<onnxruntime::MLFloat16>(),
onnxruntime::TensorShape(shape),
spSession->GetExecutionProvider()->GetAllocator(0, ::OrtMemType::OrtMemTypeDefault));
auto pTensor = _winmla::CreateTensor(
tensorDescriptor.dataType == kImageTensorDataTypeFloat32 ? TensorKind::Float : TensorKind::Float16,
&(tensorDescriptor.sizes[0]),
sizeof(tensorDescriptor.sizes) / sizeof(tensorDescriptor.sizes[0]),
spSession->GetExecutionProvider());
OrtValue ort_value;
ort_value.Init(pTensor,
@ -591,7 +588,7 @@ HRESULT ImageFeatureValue::UpdateSourceResourceData(BindingContext& context, Ort
auto pooledConverter = PoolObjectWrapper::Create(spDevice->DetensorizerStore()->Fetch(descriptor));
auto pProvider = spSession->GetExecutionProvider();
auto d3dResource = Dml::GetD3D12ResourceFromAllocation(pProvider->GetAllocator(0, ::OrtMemType::OrtMemTypeDefault).get(), pAllocatedResource);
auto d3dResource = _winmla::GetD3D12ResourceFromAllocation(pProvider, pAllocatedResource);
for (uint32_t batchIdx = 0; batchIdx < m_batchSize; ++batchIdx) {
auto videoFrame = m_videoFrames.GetAt(batchIdx);

View file

@ -17,8 +17,6 @@
#include "SequenceFeatureDescriptor.h"
#include "TensorFeatureDescriptor.h"
using namespace OperatorHelper;
namespace winrt::Windows::AI::MachineLearning::implementation {
LearningModel::LearningModel(
const hstring& path,
@ -35,7 +33,7 @@ LearningModel::LearningModel(
OverrideShapeInferenceMethods();
model_proto_ = WinML::CreateModelProto(path.c_str());
model_proto_ = std::make_unique<_winmla::ModelProto>(WinML::CreateModelProto(path.c_str()));
Initialize();
@ -52,7 +50,7 @@ LearningModel::LearningModel(
OverrideShapeInferenceMethods();
model_proto_ = WinML::CreateModelProto(stream);
model_proto_ = std::make_unique<_winmla::ModelProto>(WinML::CreateModelProto(stream));
Initialize();
@ -62,7 +60,7 @@ WINML_CATCH_ALL
void LearningModel::Initialize() {
model_info_ = std::make_unique<WinML::ModelInfo>(
model_proto_.get());
model_proto_.get()->p_);
}
void LearningModel::LogCreationEvent(bool fromStream) {
@ -257,9 +255,9 @@ LearningModel::LoadFromStream(
}
WINML_CATCH_ALL
std::unique_ptr<onnx::ModelProto>
std::unique_ptr<_winmla::ModelProto>
LearningModel::DetachModelProto() {
std::unique_ptr<onnx::ModelProto> detached_model_proto;
std::unique_ptr<_winmla::ModelProto> detached_model_proto;
if (model_proto_ != nullptr) {
detached_model_proto = std::move(model_proto_);
@ -269,13 +267,13 @@ LearningModel::DetachModelProto() {
return detached_model_proto;
}
std::unique_ptr<onnx::ModelProto>
std::unique_ptr<_winmla::ModelProto>
LearningModel::CopyModelProto() {
if (model_proto_ == nullptr) {
return nullptr;
}
return std::make_unique<onnx::ModelProto>(*model_proto_);
return std::make_unique<_winmla::ModelProto>(*model_proto_);
}
static std::once_flag g_schema_override_once_flag;

View file

@ -4,10 +4,11 @@
#pragma once
#include "LearningModel.g.h"
#include "WinMLAdapter.h"
namespace Windows::AI::MachineLearning {
class LotusEnvironment;
class ModelInfo;
namespace Windows::AI::MachineLearning {
class LotusEnvironment;
class ModelInfo;
} // namespace Windows::AI::MachineLearning
namespace winrt::Windows::AI::MachineLearning::implementation {
@ -101,10 +102,10 @@ struct LearningModel : LearningModelT<LearningModel> {
IMLOperatorRegistry*
GetOperatorRegistry();
std::unique_ptr<onnx::ModelProto>
std::unique_ptr<_winmla::ModelProto>
DetachModelProto();
std::unique_ptr<onnx::ModelProto>
std::unique_ptr<_winmla::ModelProto>
CopyModelProto();
private:
@ -125,7 +126,7 @@ struct LearningModel : LearningModelT<LearningModel> {
private:
std::shared_ptr<WinML::LotusEnvironment> lotus_environment_;
std::unique_ptr<onnx::ModelProto> model_proto_;
std::unique_ptr<WinML::Adapter::ModelProto> model_proto_;
std::unique_ptr<WinML::ModelInfo> model_info_;
ILearningModelOperatorProvider operator_provider_;
};

View file

@ -5,9 +5,9 @@
#include "LearningModelSession.h"
#include "CustomRegistryHelper.h"
#include "ImageFeatureDescriptor.h"
#include "IOrtSessionBuilder.h"
#include "WinMLAdapter.h"
#include "LearningModel.h"
#include "LearningModelBinding.h"
#include "LearningModelEvaluationResult.h"
@ -39,110 +39,6 @@ struct __declspec(uuid("D113B493-BBA2-4993-8608-D706A73B91CE")) __declspec(novta
static const GUID WINML_PIX_EVAL_CAPTURABLE_WORK_GUID = __uuidof(guid_details::WINML_PIX_EVAL_CAPTURABLE_WORK_GUID);
namespace winrt::Windows::AI::MachineLearning::implementation {
// ORT intentionally requires callers derive from their session class to access
// the protected Load method used below.
class InferenceSessionProtectedLoadAccessor : public onnxruntime::InferenceSession {
public:
onnxruntime::common::Status
Load(std::unique_ptr<ONNX_NAMESPACE::ModelProto> p_model_proto) {
return onnxruntime::InferenceSession::Load(std::move(p_model_proto));
}
};
static bool
IsFeatureDescriptorFp16(
winml::ILearningModelFeatureDescriptor descriptor) {
if (auto imageFeatureDescriptor = descriptor.try_as<ImageFeatureDescriptor>()) {
return TensorKind::Float16 == imageFeatureDescriptor->TensorKind();
}
if (auto tensorFeatureDescriptor = descriptor.try_as<TensorFeatureDescriptor>()) {
return TensorKind::Float16 == tensorFeatureDescriptor->TensorKind();
}
return false;
}
static void
EnsureModelDeviceCompatibility(
winml::LearningModel const& model,
onnx::ModelProto* p_model_proto,
winml::LearningModelDevice const& device) {
auto isFloat16Supported = device.as<LearningModelDevice>()->GetD3DDeviceCache()->IsFloat16Supported();
if (!isFloat16Supported) {
auto& graph = p_model_proto->graph();
// The model will not contain fp16 operations if:
// 1. The model has no fp16 inputs
// 2. The model has no fp16 initializers
// 3. The model does not create any fp16 intermediary tensors via the Cast (to float16) operator
// 4. The model does not have any fp16 outputs
// 1. Ensure that The model has no fp16 inputs
for (auto descriptor : model.InputFeatures()) {
WINML_THROW_HR_IF_TRUE_MSG(
DXGI_ERROR_UNSUPPORTED,
IsFeatureDescriptorFp16(descriptor),
"The model contains a 16-bit input (%ls), but the current device does not support 16-bit float.",
descriptor.Name().c_str());
}
// 2. Ensure that the model has no fp16 initializers
for (int i = 0; i < graph.node_size(); i++) {
auto node = graph.node(i);
if (node.op_type() == "Cast" && node.domain().empty()) {
for (int attribIndex = 0; attribIndex < node.attribute_size(); attribIndex++) {
auto attribute = node.attribute(attribIndex);
if (attribute.name() == "to") {
WINML_THROW_HR_IF_TRUE_MSG(
DXGI_ERROR_UNSUPPORTED,
attribute.i() == onnx::TensorProto::DataType::TensorProto_DataType_FLOAT16,
"The model contains a 16-bit float Cast Op (%s), but the current device does not support 16-bit float.",
node.name().c_str());
}
}
}
}
// 3. Ensure that the model does not create any fp16 intermediary
// tensors via the Cast (to float16) operator
for (int i = 0; i < graph.initializer_size(); i++) {
auto initializer = graph.initializer(i);
WINML_THROW_HR_IF_TRUE_MSG(
DXGI_ERROR_UNSUPPORTED,
initializer.data_type() == onnx::TensorProto::DataType::TensorProto_DataType_FLOAT16,
"The model contains a 16-bit float initializer (%s), but the current device does not support 16-bit float.",
initializer.name().c_str());
}
// 4. Ensure that the model does not have any fp16 outputs
for (auto descriptor : model.OutputFeatures()) {
WINML_THROW_HR_IF_TRUE_MSG(
DXGI_ERROR_UNSUPPORTED,
IsFeatureDescriptorFp16(descriptor),
"The model contains a 16-bit output (%ls), but the current device does not support 16-bit float.",
descriptor.Name().c_str());
}
}
}
static HRESULT
RegisterCustomRegistry(
onnxruntime::InferenceSession* p_session,
IMLOperatorRegistry* registry) {
RETURN_HR_IF(S_OK, registry == nullptr);
RETURN_HR_IF_NULL(E_POINTER, p_session);
auto custom_registries = WinML::GetLotusCustomRegistries(registry);
// Register
for (auto& custom_registry : custom_registries) {
WINML_THROW_IF_NOT_OK(p_session->RegisterCustomRegistry(custom_registry));
}
return S_OK;
}
LearningModelSession::LearningModelSession(
winml::LearningModel const& model) try : LearningModelSession(model,
@ -166,7 +62,7 @@ LearningModelSession::LearningModelSession(
}
WINML_CATCH_ALL
std::unique_ptr<onnx::ModelProto>
std::unique_ptr<_winmla::ModelProto>
LearningModelSession::GetOptimizedModel() {
// Get the model proto
auto should_close_model =
@ -176,9 +72,9 @@ LearningModelSession::GetOptimizedModel() {
return GetOptimizedModel(should_close_model);
}
std::unique_ptr<onnx::ModelProto>
std::unique_ptr<_winmla::ModelProto>
LearningModelSession::GetOptimizedModel(bool should_close_model) {
std::unique_ptr<onnx::ModelProto> model_proto;
std::unique_ptr<_winmla::ModelProto> model_proto;
{
// Lock the model detach/copy since multiple threads can access concurrently
@ -196,7 +92,7 @@ LearningModelSession::GetOptimizedModel(bool should_close_model) {
}
// Ensure that the model is runnable on the device
EnsureModelDeviceCompatibility(model_, model_proto.get(), device_);
WINML_THROW_IF_FAILED(_winmla::EnsureModelDeviceCompatibility(model_, model_proto.get()->p_, device_));
return model_proto;
}
@ -230,16 +126,16 @@ void LearningModelSession::Initialize() {
// Register the custom operator registry
auto model = model_.as<winmlp::LearningModel>();
RegisterCustomRegistry(session.get(), model->GetOperatorRegistry());
WINML_THROW_IF_FAILED(_winmla::RegisterCustomRegistry(session.get(), model->GetOperatorRegistry()));
// Register only the transformers not already in ORT
const bool registerLotusTransformers = false;
GraphTransformerHelpers::RegisterGraphTransformers(session.get(), registerLotusTransformers);
// Load the model into the session
auto session_protected_load_accessor =
static_cast<InferenceSessionProtectedLoadAccessor*>(session.get());
WINML_THROW_IF_NOT_OK(session_protected_load_accessor->Load(std::move(model_proto)));
WINML_THROW_IF_FAILED(_winmla::LoadModel(session.get(), model_proto.get()->p_));
// the session owns the model_proto now
model_proto.release();
// Initialize the session
session_builder->Initialize(session.get(), p_cached_execution_provider);
@ -525,7 +421,7 @@ void LearningModelSession::ApplyEvaluationProperties() try {
if (evaluation_properties_) {
auto is_debug_output_enabled = evaluation_properties_.HasKey(c_enable_debug_output);
if (is_debug_output_enabled) {
WinML::CWinMLLogSink::EnableDebugOutput();
_winmla::EnableDebugOutput();
}
}
}

View file

@ -7,6 +7,7 @@
#include "LearningModelBinding.h"
#include "WinML_Lock.h"
#include "WinMLAdapter.h"
namespace winrt::Windows::AI::MachineLearning::implementation {
@ -74,10 +75,10 @@ struct LearningModelSession : LearningModelSessionT<LearningModelSession> {
void
Initialize();
std::unique_ptr<onnx::ModelProto>
std::unique_ptr<_winmla::ModelProto>
GetOptimizedModel();
std::unique_ptr<onnx::ModelProto>
std::unique_ptr<_winmla::ModelProto>
GetOptimizedModel(bool should_close_model);
uint64_t

View file

@ -34,4 +34,7 @@ namespace Windows::AI::MachineLearning {}
namespace WinML = ::Windows::AI::MachineLearning;
namespace Windows::AI::MachineLearning::Telemetry {}
namespace _winmlt = ::Windows::AI::MachineLearning::Telemetry;
namespace _winmlt = ::Windows::AI::MachineLearning::Telemetry;
namespace Windows::AI::MachineLearning::Adapter {}
namespace _winmla = ::Windows::AI::MachineLearning::Adapter;