Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 72 additions & 59 deletions winml/lib/Api.Core/WinMLAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ class AbiSafeTensor : public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
ITensor> {
private:
onnxruntime::Tensor& tensor_; // weak ref
ComPtr<IOrtValue> value_; // strong ref
onnxruntime::Tensor& tensor_; // weak ref
Microsoft::WRL::ComPtr<IOrtValue> value_; // strong ref

@ryanlai2 Ryan Lai (ryanlai2) Nov 25, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Microsoft::WRL:: [](start = 2, length = 16)

Why is explicit namespace needed? #Resolved

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh because winrt also has com ptrs so it makes it more clear


In reply to: 350335004 [](ancestors = 350335004)


public:
AbiSafeTensor(onnxruntime::Tensor* tensor,
Expand Down Expand Up @@ -589,8 +589,7 @@ class WinMLAdapter : public Microsoft::WRL::RuntimeClass<
} else {
THROW_HR(E_FAIL);
}
}
else if (key_kind == TensorKind::String) {
} else if (key_kind == TensorKind::String) {
if (value_kind == TensorKind::Int64) {
return static_cast<void*>(ml_value->GetMutable<std::map<std::string, int64_t>>());
} else if (value_kind == TensorKind::Float) {
Expand Down Expand Up @@ -630,68 +629,80 @@ class WinMLAdapter : public Microsoft::WRL::RuntimeClass<
#ifdef USE_DML
auto impl = wil::MakeOrThrow<AbiCustomRegistryImpl>();
*registry = impl.Detach();
return S_OK;
return S_OK;
#else
return E_NOTIMPL;
return E_NOTIMPL;
#endif USE_DML
}
}

void* STDMETHODCALLTYPE CreateGPUAllocationFromD3DResource(ID3D12Resource* pResource) override {
HRESULT STDMETHODCALLTYPE GetOperatorRegistry(ILearningModelOperatorProviderNative* operator_provider_native, IMLOperatorRegistry** registry) override {
#ifdef USE_DML
return Dml::CreateGPUAllocationFromD3DResource(pResource);
// Retrieve the "operator abi" registry.
winrt::com_ptr<IMLOperatorRegistry> operator_registry;
THROW_IF_FAILED(operator_provider_native->GetRegistry(operator_registry.put()));
*registry = operator_registry.detach();
return S_OK;
#else
return nullptr;
return E_NOTIMPL;
#endif USE_DML
}
}

void STDMETHODCALLTYPE FreeGPUAllocation(void* ptr) override {
void* STDMETHODCALLTYPE CreateGPUAllocationFromD3DResource(ID3D12Resource* pResource) override {
#ifdef USE_DML
Dml::FreeGPUAllocation(ptr);
return Dml::CreateGPUAllocationFromD3DResource(pResource);
#else
return nullptr;
#endif USE_DML
}
}

HRESULT STDMETHODCALLTYPE CopyTensor(
onnxruntime::IExecutionProvider* provider,
ITensor* src,
ITensor* dst) override {
void STDMETHODCALLTYPE FreeGPUAllocation(void* ptr) override {
#ifdef USE_DML
ORT_THROW_IF_ERROR(Dml::CopyTensor(provider, src->get(), *(dst->getMutable())));
return S_OK;
Dml::FreeGPUAllocation(ptr);
#endif USE_DML
}

HRESULT STDMETHODCALLTYPE CopyTensor(
onnxruntime::IExecutionProvider* provider,
ITensor* src,
ITensor* dst) override {
#ifdef USE_DML
ORT_THROW_IF_ERROR(Dml::CopyTensor(provider, src->get(), *(dst->getMutable())));
return S_OK;
#else
return E_NOTIMPL;
return E_NOTIMPL;
#endif USE_DML
}
}

HRESULT STDMETHODCALLTYPE CreateGPUMLValue(
void* execution_provider_allocated_resource,
onnxruntime::IExecutionProvider* provider,
std::vector<int64_t>* shape,
onnxruntime::MLDataType data_type,
IOrtValue** gpu_value) override {
HRESULT STDMETHODCALLTYPE CreateGPUMLValue(
void* execution_provider_allocated_resource,
onnxruntime::IExecutionProvider* provider,
std::vector<int64_t>* shape,
onnxruntime::MLDataType data_type,
IOrtValue** gpu_value) override {
#ifdef USE_DML
THROW_HR_IF_MSG(WINML_ERR_INVALID_BINDING,
"DmlExecutionProvider" != provider->Type(),
"Cannot creat GPU tensor on CPU device");
THROW_HR_IF_MSG(WINML_ERR_INVALID_BINDING,
"DmlExecutionProvider" != provider->Type(),
"Cannot creat GPU tensor on CPU device");

onnxruntime::TensorShape tensor_shape(*shape);
onnxruntime::TensorShape tensor_shape(*shape);

auto tensor = new onnxruntime::Tensor(
data_type,
tensor_shape,
execution_provider_allocated_resource,
provider->GetAllocator(0, ::OrtMemType::OrtMemTypeDefault)->Info());
auto tensor = new onnxruntime::Tensor(
data_type,
tensor_shape,
execution_provider_allocated_resource,
provider->GetAllocator(0, ::OrtMemType::OrtMemTypeDefault)->Info());

auto ort_value = wil::MakeOrThrow<AbiSafeOrtValue>();
ort_value->get()->Init(tensor,
onnxruntime::DataTypeImpl::GetType<onnxruntime::Tensor>(),
onnxruntime::DataTypeImpl::GetType<onnxruntime::Tensor>()->GetDeleteFunc());
auto ort_value = wil::MakeOrThrow<AbiSafeOrtValue>();
ort_value->get()->Init(tensor,
onnxruntime::DataTypeImpl::GetType<onnxruntime::Tensor>(),
onnxruntime::DataTypeImpl::GetType<onnxruntime::Tensor>()->GetDeleteFunc());

*gpu_value = ort_value.Detach();
return S_OK;
*gpu_value = ort_value.Detach();
return S_OK;
#else
return E_NOTIMPL;
return E_NOTIMPL;
#endif USE_DML
}
}

HRESULT STDMETHODCALLTYPE CreateCPUMLValue(
std::vector<int64_t>* shape,
Expand Down Expand Up @@ -760,22 +771,22 @@ HRESULT STDMETHODCALLTYPE CreateGPUMLValue(
return S_OK;
}

// Override select shape inference functions which are incomplete in ONNX with versions that are complete,
// and are also used in DML kernel registrations. Doing this avoids kernel and shader creation being
// deferred until first evaluation. It also prevents a situation where inference functions in externally
// registered schema are reachable only after upstream schema have been revised in a later OS release,
// which would be a compatibility risk.
HRESULT STDMETHODCALLTYPE OverrideSchemaInferenceFunctions() override {
// Override select shape inference functions which are incomplete in ONNX with versions that are complete,
// and are also used in DML kernel registrations. Doing this avoids kernel and shader creation being
// deferred until first evaluation. It also prevents a situation where inference functions in externally
// registered schema are reachable only after upstream schema have been revised in a later OS release,
// which would be a compatibility risk.
HRESULT STDMETHODCALLTYPE OverrideSchemaInferenceFunctions() override {
#ifdef USE_DML
static std::once_flag schema_override_once_flag;
std::call_once(schema_override_once_flag, []() {
SchemaInferenceOverrider::OverrideSchemaInferenceFunctions();
});
return S_OK;
static std::once_flag schema_override_once_flag;
std::call_once(schema_override_once_flag, []() {
SchemaInferenceOverrider::OverrideSchemaInferenceFunctions();
});
return S_OK;
#else
return E_NOTIMPL;
return S_OK; // needs to return S_OK otherwise everything breaks because this gets called from the learningmodel constructor
#endif USE_DML
}
}

}; // namespace Windows::AI::MachineLearning::Adapter

Expand All @@ -793,7 +804,7 @@ class IOBinding : public Microsoft::WRL::RuntimeClass<
private:
std::shared_ptr<onnxruntime::IOBinding> binding_;
std::vector<IOrtValue*> outputs_weak_;
std::vector<ComPtr<IOrtValue>> outputs_;
std::vector<Microsoft::WRL::ComPtr<IOrtValue>> outputs_;

public:
IOBinding(onnxruntime::IOBinding* binding) : binding_(binding) {
Expand Down Expand Up @@ -883,12 +894,14 @@ InferenceSession::RegisterCustomRegistry(
IMLOperatorRegistry* registry) {
RETURN_HR_IF(S_OK, registry == nullptr);

#ifdef USE_DML
auto custom_registries = GetLotusCustomRegistries(registry);

// Register
for (auto& custom_registry : custom_registries) {
ORT_THROW_IF_ERROR(session_->RegisterCustomRegistry(custom_registry));
}
#endif USE_DML

return S_OK;
}
Expand Down
5 changes: 4 additions & 1 deletion winml/lib/Api.Core/inc/CustomRegistryHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#ifdef USE_DML
#include "core/providers/dml/DmlExecutionProvider/src/AbiCustomRegistry.h"

namespace Windows::AI::MachineLearning::Adapter {
Expand All @@ -24,4 +25,6 @@ GetLotusCustomRegistries(
return {};
}

} // namespace Windows::AI::MachineLearning::Adapter
} // namespace Windows::AI::MachineLearning::Adapter

#endif USE_DML
1 change: 1 addition & 0 deletions winml/lib/Api.Core/inc/WinMLAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ MIDL_INTERFACE("b19385e7-d9af-441a-ba7f-3993c7b1c9db") IWinMLAdapter : IUnknown

// custom ops
virtual HRESULT STDMETHODCALLTYPE GetCustomRegistry(IMLOperatorRegistry** registry) = 0;
virtual HRESULT STDMETHODCALLTYPE GetOperatorRegistry(ILearningModelOperatorProviderNative * operator_provider_native, IMLOperatorRegistry * *registry) = 0;

// dml ep hooks
virtual void* STDMETHODCALLTYPE CreateGPUAllocationFromD3DResource(ID3D12Resource* pResource) = 0;
Expand Down
15 changes: 5 additions & 10 deletions winml/lib/Api/LearningModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@

#include "LearningModel.h"

#include "core/providers/dml/DmlExecutionProvider/src/MLOperatorAuthorImpl.h"
#include "TelemetryEvent.h"

#include "LotusEnvironment.h"

#include "MapFeatureDescriptor.h"
#include "SequenceFeatureDescriptor.h"
#include "TensorFeatureDescriptor.h"
Expand All @@ -18,7 +15,7 @@ namespace winrt::Windows::AI::MachineLearning::implementation {
LearningModel::LearningModel(
const hstring& path,
const winml::ILearningModelOperatorProvider op_provider) try : LearningModel(WinML::Strings::UTF8FromHString(path),
op_provider) {
op_provider) {
}
WINML_CATCH_ALL

Expand Down Expand Up @@ -57,7 +54,7 @@ LearningModel::LearningModel(
WINML_CATCH_ALL

void LearningModel::Initialize() {
WINML_THROW_IF_FAILED(adapter_->CreateModelInfo(model_proto_.get(), model_info_.put()));
WINML_THROW_IF_FAILED(adapter_->CreateModelInfo(model_proto_.get(), model_info_.put()));
}

void LearningModel::LogCreationEvent(bool fromStream) {
Expand Down Expand Up @@ -165,11 +162,9 @@ LearningModel::GetOperatorRegistry() {
auto operator_provider_native =
operator_provider_.as<ILearningModelOperatorProviderNative>();

// Retrieve the "operator abi" registry.
winrt::com_ptr<IMLOperatorRegistry> operator_registry;
operator_provider_native->GetRegistry(operator_registry.put());

return operator_registry.get();
IMLOperatorRegistry* registry = nullptr;
WINML_THROW_IF_FAILED(adapter_->GetOperatorRegistry(operator_provider_native.get(), &registry));
return registry;
}

wfc::IVectorView<winml::ILearningModelFeatureDescriptor>
Expand Down