Remove usage of IOBinding in WinML and use C_API Run method (#2504)

* remove usage of iobinding

* Change data structure to use vector of Ort::Values

* Polish bind input / output

* Use C APIrun method

* Update providers on evaluate getresults

* Remove run and IObinding interface from WinMLAdapter

* Remove use of IObinding

* bind unbound outputs code moved to learningmodelbinding

* clean up unneeded istensor adapter function

* Fix comment

* Check if session is closed before binding and clearing

* PR feedback
This commit is contained in:
Ryan Lai 2019-11-27 15:31:30 -08:00 committed by GitHub
parent e8e285dd97
commit 197fd9ea3d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 204 additions and 170 deletions

View file

@ -30,6 +30,8 @@
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "FeatureDescriptorFactory.h"
#include "core\framework\utils.h"
#include "core\framework\session_state.h"
using namespace winrt::Windows::AI::MachineLearning;
@ -499,7 +501,7 @@ class WinMLAdapter : public Microsoft::WRL::RuntimeClass<
#endif USE_DML
}
HRESULT STDMETHODCALLTYPE GetOperatorRegistry(ILearningModelOperatorProviderNative* operator_provider_native, IMLOperatorRegistry** registry) override {
HRESULT STDMETHODCALLTYPE GetOperatorRegistry(ILearningModelOperatorProviderNative* operator_provider_native, IMLOperatorRegistry** registry) override {
#ifdef USE_DML
// Retrieve the "operator abi" registry.
winrt::com_ptr<IMLOperatorRegistry> operator_registry;
@ -509,7 +511,7 @@ HRESULT STDMETHODCALLTYPE GetOperatorRegistry(ILearningModelOperatorProviderNati
#else
return E_NOTIMPL;
#endif USE_DML
}
}
void* STDMETHODCALLTYPE CreateGPUAllocationFromD3DResource(ID3D12Resource* pResource) override {
#ifdef USE_DML
@ -529,7 +531,7 @@ HRESULT STDMETHODCALLTYPE GetOperatorRegistry(ILearningModelOperatorProviderNati
onnxruntime::IExecutionProvider* provider,
OrtValue* src,
OrtValue* dst) override {
#ifdef USE_DML
#ifdef USE_DML
ORT_THROW_IF_ERROR(Dml::CopyTensor(provider, *(src->GetMutable<onnxruntime::Tensor>()), *(dst->GetMutable<onnxruntime::Tensor>())));
return S_OK;
#else
@ -550,7 +552,7 @@ HRESULT STDMETHODCALLTYPE GetOperatorRegistry(ILearningModelOperatorProviderNati
});
return S_OK;
#else
return S_OK; // needs to return S_OK otherwise everything breaks because this gets called from the learningmodel constructor
return S_OK; // needs to return S_OK otherwise everything breaks because this gets called from the learningmodel constructor
#endif USE_DML
}
@ -611,7 +613,6 @@ HRESULT STDMETHODCALLTYPE GetOperatorRegistry(ILearningModelOperatorProviderNati
return S_OK;
}
}; // namespace Windows::AI::MachineLearning::Adapter
extern "C" HRESULT STDMETHODCALLTYPE OrtGetWinMLAdapter(IWinMLAdapter** adapter) {
@ -620,52 +621,6 @@ extern "C" HRESULT STDMETHODCALLTYPE OrtGetWinMLAdapter(IWinMLAdapter** adapter)
return adapterptr.CopyTo(__uuidof(IWinMLAdapter), reinterpret_cast<void**>(adapter));
}
// class IOBinding
// ===============
class IOBinding : public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
IIOBinding> {
private:
std::shared_ptr<onnxruntime::IOBinding> binding_;
std::vector<OrtValue*> outputs_weak_;
public:
IOBinding(onnxruntime::IOBinding* binding) : binding_(binding) {
}
onnxruntime::IOBinding* STDMETHODCALLTYPE get() override {
return binding_.get();
}
HRESULT STDMETHODCALLTYPE BindInput(const std::string& name, OrtValue* ort_value) override {
ORT_THROW_IF_ERROR(binding_->BindInput(name, *ort_value));
return S_OK;
}
HRESULT STDMETHODCALLTYPE BindOutput(const std::string& name, OrtValue* ort_value) override {
// this can be null for unbound outputs
if (ort_value == nullptr) {
OrtValue empty_value = {};
ORT_THROW_IF_ERROR(binding_->BindOutput(name, empty_value));
} else {
ORT_THROW_IF_ERROR(binding_->BindOutput(name, *ort_value));
}
return S_OK;
}
const std::vector<std::string>& STDMETHODCALLTYPE GetOutputNames() override {
return binding_->GetOutputNames();
}
std::vector<OrtValue*>& STDMETHODCALLTYPE GetOutputs() override {
auto& output_inner = binding_->GetOutputs();
outputs_weak_.clear();
for (unsigned i = 0; i < output_inner.size(); i++) {
outputs_weak_.push_back(&(output_inner[i]));
}
return outputs_weak_;
}
};
// InferenceSession
// ================
@ -679,18 +634,7 @@ void STDMETHODCALLTYPE InferenceSession::RegisterGraphTransformers() {
#endif USE_DML
}
HRESULT STDMETHODCALLTYPE InferenceSession::NewIOBinding(IIOBinding** io_binding) {
std::unique_ptr<onnxruntime::IOBinding> binding;
ORT_THROW_IF_ERROR(this->session_->NewIOBinding(&binding));
auto io_binding_outer = wil::MakeOrThrow<IOBinding>(binding.release());
return io_binding_outer.CopyTo(__uuidof(IIOBinding), reinterpret_cast<void**>(io_binding));
}
HRESULT STDMETHODCALLTYPE InferenceSession::Run(const onnxruntime::RunOptions* run_options, IIOBinding* io_binding) {
ORT_THROW_IF_ERROR(this->session_->Run(*run_options, *(io_binding->get())));
return S_OK;
}
HRESULT STDMETHODCALLTYPE InferenceSession::StartProfiling() {
HRESULT STDMETHODCALLTYPE InferenceSession::StartProfiling() {
this->session_->StartProfiling(PheonixSingleton<WinML::LotusEnvironment>()->GetDefaultLogger());
return S_OK;
}
@ -746,10 +690,15 @@ void STDMETHODCALLTYPE InferenceSession::ReleaseCompletedReferences(onnxruntime:
}
HRESULT STDMETHODCALLTYPE InferenceSession::CopyOneInputAcrossDevices(
const char* input_name,
const OrtValue* orig_mlvalue,
OrtValue** new_mlvalue) {
return E_NOTIMPL;
const char* input_name,
const OrtValue* orig_mlvalue,
OrtValue** new_mlvalue) {
auto session_protected_load_accessor =
static_cast<InferenceSessionProtectedLoadAccessor*>(session_.get());
const onnxruntime::SessionState& sessionState = session_protected_load_accessor->GetSessionState();
auto temp_mlvalue = std::make_unique<OrtValue>();
ORT_THROW_IF_ERROR(onnxruntime::utils::CopyOneInputAcrossDevices(sessionState, input_name, *orig_mlvalue, *temp_mlvalue.get()));
*new_mlvalue = temp_mlvalue.release();
return S_OK;
}
} // namespace Windows::AI::MachineLearning::Adapter

View file

@ -20,16 +20,6 @@ MIDL_INTERFACE("eaae30b5-7381-432d-9730-322136b02371") IModelInfo : IUnknown{
virtual HRESULT STDMETHODCALLTYPE GetOutputFeatures(ABI::Windows::Foundation::Collections::IVectorView<winml::ILearningModelFeatureDescriptor> * *features) = 0;
};
MIDL_INTERFACE("438e7719-554a-4058-84d9-eb6226c34887") IIOBinding : IUnknown{
// this returns a weak ref
virtual onnxruntime::IOBinding* STDMETHODCALLTYPE get() = 0;
virtual HRESULT STDMETHODCALLTYPE BindInput(const std::string& name, OrtValue * ml_value) = 0;
virtual HRESULT STDMETHODCALLTYPE BindOutput(const std::string& name, OrtValue * ml_value) = 0;
virtual const std::vector<std::string>& STDMETHODCALLTYPE GetOutputNames() = 0;
// this returns a weak ref
virtual std::vector<OrtValue *>& STDMETHODCALLTYPE GetOutputs() = 0;
};
MIDL_INTERFACE("a848faf6-5a2e-4a7f-b622-cc036f71e28a") IModelProto : IUnknown{
// this returns a weak ref
virtual onnx::ModelProto* STDMETHODCALLTYPE get() = 0;
@ -39,11 +29,11 @@ MIDL_INTERFACE("a848faf6-5a2e-4a7f-b622-cc036f71e28a") IModelProto : IUnknown{
MIDL_INTERFACE("6ec766ef-6365-42bf-b64f-ae85c015adb8") IInferenceSession : IUnknown {
virtual onnxruntime::InferenceSession* STDMETHODCALLTYPE get() = 0;
// the below returns a weak ref , DO NOT RELEASE IT
virtual HRESULT STDMETHODCALLTYPE GetOrtSession(OrtSession ** out) = 0;
virtual void STDMETHODCALLTYPE RegisterGraphTransformers() = 0;
virtual HRESULT STDMETHODCALLTYPE RegisterCustomRegistry(IMLOperatorRegistry * registry) = 0;
virtual HRESULT STDMETHODCALLTYPE LoadModel(IModelProto* model_proto) = 0;
virtual HRESULT STDMETHODCALLTYPE NewIOBinding(IIOBinding** io_binding) = 0;
virtual HRESULT STDMETHODCALLTYPE Run(const onnxruntime::RunOptions* run_options, IIOBinding* io_binding) = 0;
virtual HRESULT STDMETHODCALLTYPE StartProfiling() = 0;
virtual HRESULT STDMETHODCALLTYPE EndProfiling() = 0;
virtual void STDMETHODCALLTYPE FlushContext(onnxruntime::IExecutionProvider * dml_provider) = 0;
@ -130,11 +120,14 @@ public:
InferenceSession(onnxruntime::InferenceSession * session);
onnxruntime::InferenceSession* STDMETHODCALLTYPE get() override { return session_.get(); }
HRESULT STDMETHODCALLTYPE GetOrtSession(OrtSession ** out) override {
// (OrtSession *) are really (InferenceSession *) as well
*out = reinterpret_cast<OrtSession*>(session_.get());
return S_OK;
}
void STDMETHODCALLTYPE RegisterGraphTransformers() override;
HRESULT STDMETHODCALLTYPE RegisterCustomRegistry(IMLOperatorRegistry* registry) override;
HRESULT STDMETHODCALLTYPE LoadModel(IModelProto* model_proto) override;
HRESULT STDMETHODCALLTYPE NewIOBinding(IIOBinding** io_binding) override;
HRESULT STDMETHODCALLTYPE Run(const onnxruntime::RunOptions* run_options, IIOBinding* io_binding) override;
HRESULT STDMETHODCALLTYPE StartProfiling() override;
HRESULT STDMETHODCALLTYPE EndProfiling() override;
void STDMETHODCALLTYPE FlushContext(onnxruntime::IExecutionProvider* dml_provider) override;

View file

@ -8,13 +8,15 @@
#include "LearningModelBinding.h"
#include "LearningModelSession.h"
#include "TelemetryEvent.h"
#include <onnxruntime_c_api.h>
#include "LearningModel.h"
using namespace WinML;
namespace winrt::Windows::AI::MachineLearning::implementation {
LearningModelBinding::LearningModelBinding(
Windows::AI::MachineLearning::LearningModelSession const& session) try : m_session(session) {
m_lotusBinding.attach(session.as<LearningModelSession>()->CreateSessionBinding());
Windows::AI::MachineLearning::LearningModelSession const& session) try : m_session(session) {
session.as<winmlp::LearningModelSession>()->CheckClosed();
WINML_THROW_IF_FAILED(OrtGetWinMLAdapter(adapter_.put()));
}
WINML_CATCH_ALL
@ -40,7 +42,7 @@ static Windows::AI::MachineLearning::ILearningModelFeatureDescriptor FindValidBi
using NullableBindingPort = std::optional<std::pair<Windows::AI::MachineLearning::ILearningModelFeatureDescriptor, BindingType>>;
static NullableBindingPort FindValidBinding(
LearningModel model,
winml::LearningModel model,
const std::wstring& name) {
if (auto descriptor = FindValidBinding(model.InputFeatures(), name)) {
return std::make_pair(descriptor, BindingType::kInput);
@ -156,13 +158,13 @@ void LearningModelBinding::Bind(
auto featureName = WinML::Strings::UTF8FromHString(name);
std::tie(bindingName, binding_value, bindingType) = CreateBinding(featureName, value, properties);
Ort::Value ortValue = binding_value ? Ort::Value(binding_value) : Ort::Value(nullptr);
switch (bindingType) {
case BindingType::kInput:
WINML_THROW_IF_FAILED(m_lotusBinding->BindInput(bindingName, binding_value));
WINML_THROW_IF_FAILED(BindInput(bindingName, ortValue));
break;
case BindingType::kOutput:
WINML_THROW_IF_FAILED(m_lotusBinding->BindOutput(bindingName, binding_value));
WINML_THROW_IF_FAILED(BindOutput(bindingName, ortValue));
break;
default:
FAIL_FAST();
@ -171,7 +173,11 @@ void LearningModelBinding::Bind(
WINML_CATCH_ALL
void LearningModelBinding::Clear() try {
m_lotusBinding.attach(m_session.as<LearningModelSession>()->CreateSessionBinding());
m_session.as<winmlp::LearningModelSession>()->CheckClosed();
inputs_.clear();
input_names_.clear();
outputs_.clear();
output_names_.clear();
m_providers.clear();
}
WINML_CATCH_ALL
@ -218,11 +224,6 @@ void LearningModelBinding::Split(
throw hresult_not_implemented();
}
_winmla::IIOBinding* LearningModelBinding::BindingCollection() {
_winmla::IIOBinding* p;
m_lotusBinding.copy_to(&p);
return p;
}
ONNXTensorElementDataType STDMETHODCALLTYPE GetONNXTensorElementDataType(winml::TensorKind kind) {
if (kind == TensorKind::Float) {
@ -387,7 +388,7 @@ ILearningModelFeatureValue LearningModelBinding::CreateUnboundOuputFeatureValue(
Windows::Foundation::IInspectable LearningModelBinding::CreateUnboundOutput(
const std::string& name,
Ort::Value& ort_value) {
Ort::Value& ort_value) {
// Find valid binding port
auto bindingPort = FindValidBinding(
m_session.Model(),
@ -440,8 +441,8 @@ Windows::Foundation::IInspectable LearningModelBinding::CreateUnboundOutput(
std::unordered_map<std::string, Windows::Foundation::IInspectable> LearningModelBinding::UpdateProviders() {
std::unordered_map<std::string, Windows::Foundation::IInspectable> outputs;
auto& outputNames = m_lotusBinding->GetOutputNames();
auto& outputMLValues = m_lotusBinding->GetOutputs();
auto& outputNames = GetOutputNames();
auto& outputMLValues = GetOutputs();
WINML_THROW_HR_IF_FALSE_MSG(
E_UNEXPECTED,
outputNames.size() == outputMLValues.size(),
@ -449,7 +450,7 @@ std::unordered_map<std::string, Windows::Foundation::IInspectable> LearningModel
for (unsigned i = 0; i < outputNames.size(); i++) {
auto utf8Name = outputNames[i];
auto mlValue = outputMLValues[i];
OrtValue* mlValue = outputMLValues[i];
if (m_providers.find(utf8Name) != std::end(m_providers)) {
auto& providerInfo = m_providers[utf8Name];
@ -499,14 +500,13 @@ STDMETHODIMP LearningModelBinding::Bind(
auto featureName = WinML::Strings::UTF8FromUnicode(name, cchName);
std::tie(bindingName, binding_value_ptr, bindingType) = CreateBinding(featureName, to, nullptr);
Ort::Value bindingValue(binding_value_ptr);
Ort::Value ortValue = binding_value_ptr ? Ort::Value(binding_value_ptr) : Ort::Value(nullptr);
switch (bindingType) {
case BindingType::kInput:
WINML_THROW_IF_FAILED(m_lotusBinding->BindInput(bindingName, bindingValue));
WINML_THROW_IF_FAILED(BindInput(bindingName, ortValue));
break;
case BindingType::kOutput:
WINML_THROW_IF_FAILED(m_lotusBinding->BindOutput(bindingName, bindingValue));
WINML_THROW_IF_FAILED(BindOutput(bindingName, ortValue));
break;
default:
FAIL_FAST();
@ -515,4 +515,106 @@ STDMETHODIMP LearningModelBinding::Bind(
}
WINML_CATCH_ALL_COM
}
static std::pair<bool, size_t> Contains(const std::vector<std::string>& names, const std::string& name) {
auto it = std::find(std::begin(names), std::end(names), name);
if (it == std::end(names)) {
return {false, 0};
}
return {true, it - std::begin(names)};
}
// This method releases control of memory of ml_value from caller of BindInput
HRESULT LearningModelBinding::BindInput(const std::string& name, Ort::Value& ml_value) {
auto rc = Contains(input_names_, name);
auto add_or_replace = [this, &name](const bool exists, size_t index, Ort::Value& value) {
if (exists) {
inputs_[index] = Ort::Value(value.release());
} else {
input_names_.push_back(name);
inputs_.push_back(Ort::Value(value.release()));
}
};
if (ml_value.IsTensor()) {
Ort::Value new_mlvalue = Ort::Value(nullptr);
WINML_THROW_IF_FAILED(m_session.as<LearningModelSession>()
->GetIInferenceSession()
->CopyOneInputAcrossDevices(name.c_str(), ml_value, new_mlvalue.put()));
add_or_replace(rc.first, rc.second, new_mlvalue);
} else {
add_or_replace(rc.first, rc.second, ml_value);
}
return S_OK;
}
// This method releases control of memory of ml_value from caller of BindInput
HRESULT LearningModelBinding::BindOutput(const std::string& name, Ort::Value& ml_value) {
auto rc = Contains(output_names_, name);
OrtValue* ml_value_data = ml_value.release();
if (rc.first) {
outputs_[rc.second] = ml_value_data ? Ort::Value(ml_value_data) : Ort::Value(nullptr);
return S_OK;
}
output_names_.push_back(name);
outputs_.push_back(ml_value_data ? Ort::Value(ml_value_data) : Ort::Value(nullptr));
return S_OK;
}
const std::vector<std::string>& LearningModelBinding::GetOutputNames() const {
return output_names_;
}
std::vector<Ort::Value>& LearningModelBinding::GetOutputs() { return outputs_; }
const std::vector<std::string>& LearningModelBinding::GetInputNames() const {
return input_names_;
}
const std::vector<Ort::Value>& LearningModelBinding::GetInputs() const { return inputs_; }
void LearningModelBinding::BindUnboundOutputs()
{
auto& bound_output_names = GetOutputNames();
std::unordered_set<std::string> bound_output_names_set(
bound_output_names.begin(),
bound_output_names.end());
// Get model output feature names
auto model_impl = m_session.Model().as<winmlp::LearningModel>();
auto output_features = model_impl->OutputFeatures();
std::vector<ILearningModelFeatureDescriptor> output_descriptors(
begin(output_features),
end(output_features));
// Convert all output features to their feature names
std::vector<std::string> output_feature_names;
std::transform(
std::begin(output_descriptors),
std::end(output_descriptors),
std::back_inserter(output_feature_names),
[&](auto& descriptor) {
auto descriptor_native = descriptor.as<ILearningModelFeatureDescriptorNative>();
const wchar_t* p_name;
uint32_t size;
WINML_THROW_IF_FAILED(descriptor_native->GetName(&p_name, &size));
return WinML::Strings::UTF8FromUnicode(p_name, size);
});
// Find the set difference to determine if there are any unbound output features
std::vector<std::string> unbound_output_names;
std::copy_if(
std::begin(output_feature_names), std::end(output_feature_names),
std::inserter(unbound_output_names, std::begin(unbound_output_names)),
[&](const auto& outputFeatureName) {
return bound_output_names_set.find(outputFeatureName) == bound_output_names_set.end();
});
// Add all unbound outputs to binding collection
for (const auto& unbound_output : unbound_output_names) {
WINML_THROW_IF_FAILED(BindOutput(unbound_output, Ort::Value(nullptr)));
}
}
} // namespace winrt::Windows::AI::MachineLearning::implementation

View file

@ -41,7 +41,6 @@ struct LearningModelBinding : LearningModelBindingT<LearningModelBinding, ILearn
const Windows::Foundation::IInspectable& value,
Windows::Foundation::Collections::IPropertySet const& properties);
_winmla::IIOBinding* BindingCollection();
std::unordered_map<std::string, Windows::Foundation::IInspectable> UpdateProviders();
const Windows::AI::MachineLearning::LearningModelSession& GetSession() { return m_session; }
@ -52,6 +51,13 @@ struct LearningModelBinding : LearningModelBindingT<LearningModelBinding, ILearn
UINT32 cchName,
IUnknown* value);
const std::vector<std::string>& LearningModelBinding::GetOutputNames() const;
std::vector<Ort::Value>& LearningModelBinding::GetOutputs();
const std::vector<std::string>& LearningModelBinding::GetInputNames() const;
const std::vector<Ort::Value>& LearningModelBinding::GetInputs() const;
HRESULT BindOutput(const std::string& name, Ort::Value& ml_value);
void BindUnboundOutputs();
private:
void CacheProvider(std::string name, ProviderInfo& spProvider);
Windows::Foundation::IInspectable CreateUnboundOutput(const std::string& name, Ort::Value& ort_value);
@ -61,15 +67,18 @@ struct LearningModelBinding : LearningModelBindingT<LearningModelBinding, ILearn
bool IsOfTensorType(const Ort::Value& ort_value, TensorKind kind);
bool IsOfMapType(const Ort::Value& ort_value, TensorKind key_kind, TensorKind value_kind);
bool IsOfVectorMapType(const Ort::Value& ort_value, TensorKind key_kind, TensorKind value_kind);
HRESULT BindInput(const std::string& name, Ort::Value& ml_value);
private:
const Windows::AI::MachineLearning::LearningModelSession m_session;
std::unordered_map<std::string, ProviderInfo> m_providers;
com_ptr<_winmla::IIOBinding> m_lotusBinding;
com_ptr<_winmla::IWinMLAdapter> adapter_;
std::vector<std::string> input_names_;
std::vector<Ort::Value> inputs_;
std::vector<std::string> output_names_;
std::vector<Ort::Value> outputs_;
};
} // namespace winrt::Windows::AI::MachineLearning::implementation

View file

@ -198,54 +198,20 @@ LearningModelSession::EvaluateFeaturesAsync(
return EvaluateAsync(binding, correlation_id);
}
static _winmla::IIOBinding*
GetIOBinding(
winrt::com_ptr<winmlp::LearningModelBinding> binding_impl,
winml::LearningModel& model) {
// Get the IOBinding Collection, and bound outputs
com_ptr<_winmla::IIOBinding> io_binding;
io_binding.attach(binding_impl->BindingCollection());
auto& bound_output_names = io_binding->GetOutputNames();
std::unordered_set<std::string> bound_output_names_set(
bound_output_names.begin(),
bound_output_names.end());
// Get model output feature names
auto model_impl = model.as<winmlp::LearningModel>();
auto output_features = model_impl->OutputFeatures();
std::vector<ILearningModelFeatureDescriptor> output_descriptors(
begin(output_features),
end(output_features));
// Convert all output features to their feature names
std::vector<std::string> output_feature_names;
std::transform(
std::begin(output_descriptors),
std::end(output_descriptors),
std::back_inserter(output_feature_names),
[&](auto& descriptor) {
auto descriptor_native = descriptor.as<ILearningModelFeatureDescriptorNative>();
const wchar_t* p_name;
uint32_t size;
WINML_THROW_IF_FAILED(descriptor_native->GetName(&p_name, &size));
return WinML::Strings::UTF8FromUnicode(p_name, size);
});
// Find the set difference to determine if there are any unbound output features
std::vector<std::string> unbound_output_names;
std::copy_if(
std::begin(output_feature_names), std::end(output_feature_names),
std::inserter(unbound_output_names, std::begin(unbound_output_names)),
[&](const auto& outputFeatureName) {
return bound_output_names_set.find(outputFeatureName) == bound_output_names_set.end();
});
// Add all unbound outputs to the iobinding collection
for (const auto& unbound_output : unbound_output_names) {
WINML_THROW_IF_FAILED(io_binding->BindOutput(unbound_output, nullptr));
}
return io_binding.detach();
// copied from onnxruntime_cxx_inline.h
inline OrtStatus* OrtRun(
OrtSession * session,
const Ort::RunOptions& run_options,
const char* const* input_names,
const Ort::Value* input_values,
size_t input_count,
const char* const* output_names,
Ort::Value* output_values,
size_t output_count) {
static_assert(sizeof(Ort::Value) == sizeof(OrtValue*), "Value is really just an array of OrtValue* in memory, so we can reinterpret_cast safely");
auto ort_input_values = reinterpret_cast<const OrtValue**>(const_cast<Ort::Value*>(input_values));
auto ort_output_values = reinterpret_cast<OrtValue**>(output_values);
return Ort::GetApi().Run(session, run_options, input_names, ort_input_values, input_count, output_names, output_count, ort_output_values);
}
uint64_t
@ -255,13 +221,31 @@ LearningModelSession::Run(
auto device = device_.as<LearningModelDevice>();
CWinMLAutoLock lock(!device->IsCpuDevice() ? &evaluate_lock_ : nullptr);
// TODO : set the run_options
onnxruntime::RunOptions run_options;
Ort::RunOptions run_options;
binding_impl->BindUnboundOutputs();
com_ptr<_winmla::IIOBinding> io_binding;
io_binding.attach(GetIOBinding(binding_impl, model_));
std::vector<const char*> inputNames_c;
for (int i=0; i < binding_impl->GetInputNames().size(); i++)
{
inputNames_c.push_back(binding_impl->GetInputNames()[i].c_str());
}
std::vector<const char*> outputNames_c;
for (int i = 0; i < binding_impl->GetOutputNames().size(); i++) {
outputNames_c.push_back(binding_impl->GetOutputNames()[i].c_str());
}
OrtSession* session = nullptr;
WINML_THROW_IF_FAILED(inference_session_->GetOrtSession(&session));
// Invoke run on the ORT session.
WINML_THROW_IF_FAILED(inference_session_->Run(&run_options, io_binding.get()));
Ort::ThrowOnError(OrtRun(
session,
run_options,
inputNames_c.data(),
binding_impl->GetInputs().data(),
binding_impl->GetInputs().size(),
outputNames_c.data(),
binding_impl->GetOutputs().data(),
binding_impl->GetOutputs().size()));
if (!device->IsCpuDevice()) {
// Flush the D3D12 work from the DML execution provider and queue a fence before we release the lock.
@ -409,14 +393,6 @@ void LearningModelSession::Close() {
inference_session_ = nullptr;
}
_winmla::IIOBinding*
LearningModelSession::CreateSessionBinding() {
CheckClosed();
com_ptr<_winmla::IIOBinding> binding;
WINML_THROW_IF_FAILED(inference_session_->NewIOBinding(binding.put()));
return binding.detach();
}
void LearningModelSession::ApplyEvaluationProperties() try {
if (evaluation_properties_) {
auto is_debug_output_enabled = evaluation_properties_.HasKey(c_enable_debug_output);
@ -449,6 +425,11 @@ LearningModelSession::GetExecutionProvider() {
return cached_execution_provider_;
}
_winmla::IInferenceSession*
LearningModelSession::GetIInferenceSession() {
return inference_session_.get();
}
void LearningModelSession::CheckClosed() {
if (!inference_session_) {
WINML_THROW_HR(RO_E_CLOSED);

View file

@ -68,8 +68,11 @@ struct LearningModelSession : LearningModelSessionT<LearningModelSession> {
onnxruntime::IExecutionProvider*
GetExecutionProvider();
_winmla::IIOBinding*
CreateSessionBinding();
_winmla::IInferenceSession*
GetIInferenceSession();
void
CheckClosed();
private:
void
@ -97,9 +100,6 @@ struct LearningModelSession : LearningModelSessionT<LearningModelSession> {
void
ToggleProfiler();
void
CheckClosed();
private:
com_ptr<_winmla::IInferenceSession> inference_session_;