mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-25 19:48:11 +00:00
Layer dev paulm (#2492)
* commetns for dml graph transformer fixed ort value passing using the allocatir info * fixed and coded maps and sequences across the abi
This commit is contained in:
parent
8346ddf222
commit
c27f56c38e
10 changed files with 124 additions and 104 deletions
|
|
@ -18,7 +18,7 @@ set(WINML_TEST_INC_DIR
|
|||
|
||||
function(set_winml_target_properties target)
|
||||
set_target_properties(${target} PROPERTIES
|
||||
FOLDER "WinMLTest"
|
||||
FOLDER "ONNXRuntimeTest/winml"
|
||||
CXX_STANDARD 17
|
||||
CXX_STANDARD_REQUIRED YES
|
||||
CXX_EXTENSIONS NO
|
||||
|
|
|
|||
|
|
@ -273,6 +273,7 @@ struct Value : Base<OrtValue> {
|
|||
|
||||
size_t GetStringTensorDataLength() const;
|
||||
void GetStringTensorContent(void* buffer, size_t buffer_length, size_t* offsets, size_t offsets_count) const;
|
||||
std::vector<std::string> GetStrings();
|
||||
|
||||
template <typename T>
|
||||
T* GetTensorMutableData();
|
||||
|
|
|
|||
|
|
@ -444,6 +444,33 @@ inline void Value::GetStringTensorContent(void* buffer, size_t buffer_length, si
|
|||
ThrowOnError(Global<void>::api_.GetStringTensorContent(p_, buffer, buffer_length, offsets, offsets_count));
|
||||
}
|
||||
|
||||
inline std::vector<std::string> Value::GetStrings() {
|
||||
std::vector<std::string> out;
|
||||
// make sure this is an array of strings
|
||||
auto shape = this->GetTensorTypeAndShapeInfo().GetShape();
|
||||
// there needs to be only one dimension
|
||||
if (shape.size() != 1) throw Ort::Exception("shape.size() != 1", ORT_INVALID_ARGUMENT);
|
||||
// make a big buffer to hold all the string data
|
||||
size_t buflen = this->GetStringTensorDataLength();
|
||||
std::vector<uint8_t> buf(buflen);
|
||||
std::vector<size_t> offsets(shape[0]);
|
||||
this->GetStringTensorContent(buf.data(), buf.size(), offsets.data(), offsets.size());
|
||||
// now go build all the strings
|
||||
for (auto i = 0; i < shape[0]; ++i) {
|
||||
std::string str;
|
||||
size_t strlen = 0;
|
||||
// are we on the last one?
|
||||
if (i == (shape[0] - 1ll)) {
|
||||
strlen = buflen - offsets[i];
|
||||
} else {
|
||||
strlen = offsets[i + 1ll] - offsets[i];
|
||||
}
|
||||
str.append(reinterpret_cast<const char *>(buf.data() + offsets[i]), strlen);
|
||||
out.push_back(str);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* Value::GetTensorMutableData() {
|
||||
T* out;
|
||||
|
|
|
|||
|
|
@ -25,48 +25,17 @@
|
|||
|
||||
namespace GraphTransformerHelpers
|
||||
{
|
||||
void RegisterGraphTransformers(onnxruntime::InferenceSession* lotusSession, bool registerLotusTransforms)
|
||||
void RegisterGraphTransformers(onnxruntime::InferenceSession* lotusSession)
|
||||
{
|
||||
// Register Lotus graph transformers
|
||||
// we were able to combine all of the winml/dml/ort work except for 2 transformers.
|
||||
// these 2 are tracked by :
|
||||
// Bug 22973884 : Fix issues with BatchNorm + Add and BatchNorm + Mul handling implicit inputs, and move from Winml to ORT
|
||||
//
|
||||
// TODO: Work out issues controlling graph optimization passes through ORT's optimization level
|
||||
// and rule list. In the meantime (and before new transformers are tested in Winml), passes
|
||||
// are registered explicitly, and the optimization level is set to default above (no optimization).
|
||||
//
|
||||
// Issues:
|
||||
// Why is UnsqueezeElimination not registered by name in ORT?
|
||||
// Why are level 2 (default) transformers not run before partitioning, which the DML XP requires?
|
||||
// Why are level2 transformers only enabled on the CPU provider in GenerateTransformers?
|
||||
// Why does name filtering only apply to rule based graph transformers?
|
||||
// Why is Matmul+Add not used when contrib ops are disabled?
|
||||
|
||||
if (registerLotusTransforms)
|
||||
{
|
||||
lotusSession->RegisterGraphTransformer(std::move(std::make_unique<onnxruntime::ConstantFolding>()), onnxruntime::TransformerLevel::Level1);
|
||||
}
|
||||
|
||||
std::unique_ptr<onnxruntime::RuleBasedGraphTransformer> rule_transformer =
|
||||
std::make_unique<onnxruntime::RuleBasedGraphTransformer>("WinmlRuleTransformer");
|
||||
|
||||
if (registerLotusTransforms)
|
||||
{
|
||||
rule_transformer->Register(std::make_unique<onnxruntime::EliminateIdentity>());
|
||||
rule_transformer->Register(std::make_unique<onnxruntime::UnsqueezeElimination>());
|
||||
rule_transformer->Register(std::make_unique<onnxruntime::EliminateDropout>());
|
||||
rule_transformer->Register(std::make_unique<onnxruntime::EliminateSlice>());
|
||||
rule_transformer->Register(std::make_unique<onnxruntime::ConvBNFusion>());
|
||||
rule_transformer->Register(std::make_unique<onnxruntime::ConvMulFusion>());
|
||||
rule_transformer->Register(std::make_unique<onnxruntime::ConvAddFusion>());
|
||||
}
|
||||
|
||||
rule_transformer->Register(std::make_unique<onnxruntime::BatchNormalizationMulFusion>());
|
||||
rule_transformer->Register(std::make_unique<onnxruntime::BatchNormalizationAddFusion>());
|
||||
|
||||
lotusSession->RegisterGraphTransformer(std::move(rule_transformer), onnxruntime::TransformerLevel::Level1);
|
||||
|
||||
if (registerLotusTransforms)
|
||||
{
|
||||
lotusSession->RegisterGraphTransformer(std::move(std::make_unique<onnxruntime::MatMulAddFusion>()), onnxruntime::TransformerLevel::Level1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,5 +5,5 @@
|
|||
|
||||
namespace GraphTransformerHelpers
|
||||
{
|
||||
void RegisterGraphTransformers(onnxruntime::InferenceSession* lotusSession, bool registerLotusTransforms);
|
||||
void RegisterGraphTransformers(onnxruntime::InferenceSession* lotusSession);
|
||||
}
|
||||
|
|
@ -574,12 +574,11 @@ HRESULT STDMETHODCALLTYPE GetOperatorRegistry(ILearningModelOperatorProviderNati
|
|||
return static_cast<AllocatorWrapper*>(this_)->impl_->Free(p);
|
||||
}
|
||||
static const struct OrtMemoryInfo* ORT_API_CALL InfoImpl(const struct OrtAllocator* this_) {
|
||||
return &(static_cast<const AllocatorWrapper*>(this_)->info_);
|
||||
return &(static_cast<const AllocatorWrapper*>(this_)->impl_->Info());
|
||||
}
|
||||
|
||||
private:
|
||||
onnxruntime::AllocatorPtr impl_;
|
||||
OrtMemoryInfo info_;
|
||||
};
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetProviderAllocator(
|
||||
|
|
@ -654,9 +653,10 @@ class IOBinding : public Microsoft::WRL::RuntimeClass<
|
|||
InferenceSession::InferenceSession(onnxruntime::InferenceSession* session) : session_(session) {
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE InferenceSession::RegisterGraphTransformers(bool registerLotusTransforms) {
|
||||
void STDMETHODCALLTYPE InferenceSession::RegisterGraphTransformers() {
|
||||
#ifdef USE_DML
|
||||
GraphTransformerHelpers::RegisterGraphTransformers(session_.get(), registerLotusTransforms);
|
||||
// Bug 22973884 : Fix issues with BatchNorm + Add and BatchNorm + Mul handling implicit inputs, and move from Winml to ORT
|
||||
GraphTransformerHelpers::RegisterGraphTransformers(session_.get());
|
||||
#endif USE_DML
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ MIDL_INTERFACE("a848faf6-5a2e-4a7f-b622-cc036f71e28a") IModelProto : IUnknown{
|
|||
|
||||
MIDL_INTERFACE("6ec766ef-6365-42bf-b64f-ae85c015adb8") IInferenceSession : IUnknown {
|
||||
virtual onnxruntime::InferenceSession* STDMETHODCALLTYPE get() = 0;
|
||||
virtual void STDMETHODCALLTYPE RegisterGraphTransformers(bool registerLotusTransforms) = 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;
|
||||
|
|
@ -131,7 +131,7 @@ public:
|
|||
InferenceSession(onnxruntime::InferenceSession * session);
|
||||
|
||||
onnxruntime::InferenceSession* STDMETHODCALLTYPE get() override { return session_.get(); }
|
||||
void STDMETHODCALLTYPE RegisterGraphTransformers(bool registerLotusTransforms) override;
|
||||
void STDMETHODCALLTYPE RegisterGraphTransformers() override;
|
||||
HRESULT STDMETHODCALLTYPE RegisterCustomRegistry(IMLOperatorRegistry* registry) override;
|
||||
HRESULT STDMETHODCALLTYPE LoadModel(IModelProto* model_proto) override;
|
||||
HRESULT STDMETHODCALLTYPE NewIOBinding(IIOBinding** io_binding) override;
|
||||
|
|
|
|||
|
|
@ -130,8 +130,7 @@ void LearningModelSession::Initialize() {
|
|||
WINML_THROW_IF_FAILED(session->RegisterCustomRegistry(model->GetOperatorRegistry()));
|
||||
|
||||
// Register only the transformers not already in ORT
|
||||
const bool registerLotusTransformers = false;
|
||||
session->RegisterGraphTransformers(registerLotusTransformers);
|
||||
session->RegisterGraphTransformers();
|
||||
|
||||
// Load the model into the session
|
||||
WINML_THROW_IF_FAILED(session->LoadModel(model_proto.get()));
|
||||
|
|
|
|||
|
|
@ -63,14 +63,29 @@ struct MapBase : winrt::implements<
|
|||
}
|
||||
|
||||
template <typename TRawType>
|
||||
static TRawType ConvertToABIType(const typename ValidLotusType<TRawType>::Type& lotusValue) {
|
||||
TRawType copy = lotusValue;
|
||||
return copy;
|
||||
static std::vector<TRawType> ConvertToABIType(Ort::Value& ort_value) {
|
||||
// make sure this is an array of these types
|
||||
auto shape = ort_value.GetTensorTypeAndShapeInfo().GetShape();
|
||||
// there needs to be only one dimension
|
||||
THROW_HR_IF(E_INVALIDARG, shape.size() != 1);
|
||||
auto lotus_value = ort_value.GetTensorMutableData<typename ValidLotusType<TRawType>::Type>();
|
||||
// now go through all the entries
|
||||
std::vector<TRawType> out;
|
||||
for (auto i = 0; i < shape[0]; i++) {
|
||||
out.push_back(lotus_value[i]);
|
||||
}
|
||||
// retun the vector
|
||||
return out;
|
||||
}
|
||||
|
||||
template <>
|
||||
static typename winrt::hstring ConvertToABIType(const typename ValidLotusType<winrt::hstring>::Type& lotusValue) {
|
||||
return WinML::Strings::HStringFromUTF8(lotusValue);
|
||||
static std::vector<winrt::hstring> ConvertToABIType<winrt::hstring>(Ort::Value& ort_value) {
|
||||
auto strings = ort_value.GetStrings();
|
||||
std::vector<winrt::hstring> out;
|
||||
for (auto i = 0; i < strings.size(); ++i) {
|
||||
out.push_back(WinML::Strings::HStringFromUTF8(strings[i].c_str()));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
MapBase(ABIMap const& data) : data_(data) {}
|
||||
|
|
@ -133,7 +148,7 @@ struct MapBase : winrt::implements<
|
|||
}
|
||||
|
||||
template <typename TLotusKey, typename TLotusValue>
|
||||
static Ort::Value CreateOrtMap(TLotusKey * keys, TLotusValue * values, size_t len) {
|
||||
static Ort::Value CreateOrtMap(TLotusKey* keys, TLotusValue* values, size_t len) {
|
||||
// now create OrtValue wrappers over the buffers
|
||||
auto cpu_memory = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeDefault);
|
||||
std::vector<int64_t> shape = {static_cast<int64_t>(len)};
|
||||
|
|
@ -149,6 +164,7 @@ struct MapBase : winrt::implements<
|
|||
|
||||
// TODO : we need to handle inputs. for now only handle outputs and don't pre allocate anything
|
||||
if (context.type == WinML::BindingType::kOutput) {
|
||||
*ort_value = nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
@ -156,7 +172,7 @@ struct MapBase : winrt::implements<
|
|||
ConvertToLotusMap(data_);
|
||||
|
||||
// and make the map
|
||||
*ort_value = CreateOrtMap(lotus_data_->first.data(), lotus_data_->second.data(), lotus_data_->first.size());
|
||||
*ort_value = CreateOrtMap(lotus_data_->first.data(), lotus_data_->second.data(), lotus_data_->first.size()).release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
@ -171,8 +187,25 @@ struct MapBase : winrt::implements<
|
|||
(BindingContext& context, OrtValue* ort_value) {
|
||||
data_.Clear();
|
||||
|
||||
void* pResource = nullptr;
|
||||
Ort::ThrowOnError(Ort::GetApi().GetTensorMutableData(ort_value, &pResource));
|
||||
Ort::AllocatorWithDefaultOptions allocator;
|
||||
|
||||
// get the keys
|
||||
OrtValue* ptr = nullptr;
|
||||
Ort::ThrowOnError(Ort::GetApi().GetValue(ort_value, 0, allocator, &ptr));
|
||||
Ort::Value keys{ptr};
|
||||
// get the values
|
||||
ptr = nullptr;
|
||||
Ort::ThrowOnError(Ort::GetApi().GetValue(ort_value, 1, allocator, &ptr));
|
||||
Ort::Value values{ptr};
|
||||
|
||||
auto keys_vector = ConvertToABIType<TKey>(keys);
|
||||
auto values_vector = ConvertToABIType<TValue>(values);
|
||||
|
||||
auto len = keys.GetCount();
|
||||
for (auto i = 0; i < len; ++i) {
|
||||
data_.Insert(keys_vector[i], values_vector[i]);
|
||||
}
|
||||
return S_OK;
|
||||
|
||||
// TODO: code this
|
||||
//const LotusMap& map = *static_cast<LotusMap*>(pResource);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ struct SequenceBase : public winrt::implements<
|
|||
using TKey = std::string;
|
||||
using TValue = float;
|
||||
using Type = std::pair<std::vector<TKey>, std::vector<TValue>>;
|
||||
using ABIKey = winrt::hstring;
|
||||
using ABIValue = TValue;
|
||||
};
|
||||
template <>
|
||||
struct ValidLotusType<AbiMapInt64BitToFloat> {
|
||||
|
|
@ -41,6 +43,8 @@ struct SequenceBase : public winrt::implements<
|
|||
using TKey = int64_t;
|
||||
using TValue = float;
|
||||
using Type = std::pair<std::vector<TKey>, std::vector<TValue>>;
|
||||
using ABIKey = TKey;
|
||||
using ABIValue = TValue;
|
||||
};
|
||||
|
||||
template <typename TElement>
|
||||
|
|
@ -189,8 +193,7 @@ struct SequenceBase : public winrt::implements<
|
|||
return Ort::Value::CreateMap(keys_ort_value, values_ort_value);
|
||||
}
|
||||
|
||||
STDMETHOD(GetOrtValue)
|
||||
(
|
||||
STDMETHOD(GetOrtValue)(
|
||||
WinML::BindingContext& context,
|
||||
OrtValue** ort_value) {
|
||||
// TODO: Tensorized data should be cached so multiple bindings work more efficiently
|
||||
|
|
@ -235,71 +238,59 @@ struct SequenceBase : public winrt::implements<
|
|||
}
|
||||
|
||||
template <typename TRawType>
|
||||
static TRawType
|
||||
ConvertToABIType(
|
||||
const typename ValidLotusType<TRawType>::Type& lotus_value) {
|
||||
// make a copy
|
||||
TRawType copy = lotus_value;
|
||||
return copy;
|
||||
static std::vector<TRawType> ConvertToABIType(Ort::Value& ort_value) {
|
||||
// make sure this is an array of these types
|
||||
auto shape = ort_value.GetTensorTypeAndShapeInfo().GetShape();
|
||||
// there needs to be only one dimension
|
||||
THROW_HR_IF(E_INVALIDARG, shape.size() != 1);
|
||||
auto lotus_value = ort_value.GetTensorMutableData<typename ValidLotusType<TRawType>::Type>();
|
||||
// now go through all the entries
|
||||
std::vector<TRawType> out;
|
||||
for (auto i = 0; i < shape[0]; i++) {
|
||||
out.push_back(lotus_value[i]);
|
||||
}
|
||||
// return the vector
|
||||
return out;
|
||||
}
|
||||
|
||||
template <>
|
||||
static winrt::hstring
|
||||
ConvertToABIType(
|
||||
const typename ValidLotusType<winrt::hstring>::Type& lotus_value) {
|
||||
return WinML::Strings::HStringFromUTF8(lotus_value);
|
||||
}
|
||||
|
||||
static AbiMapStringToFloat
|
||||
ConvertToABIType(
|
||||
typename ValidLotusType<AbiMapStringToFloat>::TKey* keys,
|
||||
typename ValidLotusType<AbiMapStringToFloat>::TValue* values,
|
||||
size_t len) {
|
||||
// need to make a copy to convert std::string to hstring
|
||||
std::map<winrt::hstring, float> copy;
|
||||
for (auto i = 0; i < len; ++i) {
|
||||
auto key = WinML::Strings::HStringFromUTF8(keys[i]);
|
||||
copy[key] = values[i];
|
||||
static std::vector<winrt::hstring> ConvertToABIType<winrt::hstring>(Ort::Value& ort_value) {
|
||||
auto strings = ort_value.GetStrings();
|
||||
std::vector<winrt::hstring> out;
|
||||
for (auto i = 0; i < strings.size(); ++i) {
|
||||
out.push_back(WinML::Strings::HStringFromUTF8(strings[i].c_str()));
|
||||
}
|
||||
return winrt::single_threaded_map<winrt::hstring, float>(
|
||||
std::move(copy));
|
||||
return out;
|
||||
}
|
||||
|
||||
static AbiMapInt64BitToFloat
|
||||
ConvertToABIType(
|
||||
typename ValidLotusType<AbiMapInt64BitToFloat>::TKey* keys,
|
||||
typename ValidLotusType<AbiMapInt64BitToFloat>::TValue* values,
|
||||
size_t len) {
|
||||
// need to make a copy since stl objects are not ABI safe.
|
||||
std::map<int64_t, float> copy;
|
||||
for (auto i = 0; i < len; ++i) {
|
||||
copy[keys[i]] = values[i];
|
||||
}
|
||||
return winrt::single_threaded_map<int64_t, float>(
|
||||
std::move(copy));
|
||||
}
|
||||
|
||||
STDMETHOD(UpdateSourceResourceData)
|
||||
(
|
||||
STDMETHOD(UpdateSourceResourceData)(
|
||||
BindingContext& context,
|
||||
OrtValue* ort_value) {
|
||||
auto writable_vector = data_.as<wfc::IVector<T>>();
|
||||
writable_vector.Clear();
|
||||
|
||||
Ort::AllocatorWithDefaultOptions allocator;
|
||||
Ort::Value ort_value_in(ort_value);
|
||||
auto len = ort_value_in.GetCount();
|
||||
size_t len;
|
||||
Ort::ThrowOnError(Ort::GetApi().GetValueCount(ort_value, &len));
|
||||
for (auto i = 0; i < len; ++i) {
|
||||
auto map = ort_value_in.GetValue(i, allocator);
|
||||
OrtValue* out = nullptr;
|
||||
Ort::ThrowOnError(Ort::GetApi().GetValue(ort_value, i, allocator, &out));
|
||||
Ort::Value map{out};
|
||||
auto keys = map.GetValue(0, allocator);
|
||||
auto values = map.GetValue(1, allocator);
|
||||
|
||||
auto keys_data = keys.GetTensorMutableData<ValidLotusType<T>::TKey>();
|
||||
auto values_data = keys.GetTensorMutableData<ValidLotusType<T>::TValue>();
|
||||
|
||||
writable_vector.Append(ConvertToABIType(keys_data, values_data, keys.GetTensorTypeAndShapeInfo().GetElementCount()));
|
||||
}
|
||||
auto keys_vector = ConvertToABIType<typename ValidLotusType<T>::ABIKey>(keys);
|
||||
auto values_vector = ConvertToABIType<typename ValidLotusType<T>::ABIValue>(values);
|
||||
|
||||
std::map<typename ValidLotusType<T>::ABIKey, typename ValidLotusType<T>::ABIValue> std_map;
|
||||
for (auto j = 0; j < keys_vector.size(); ++j) {
|
||||
std_map[keys_vector[j]] = values_vector[j];
|
||||
}
|
||||
auto abi_map = winrt::single_threaded_map<typename ValidLotusType<T>::ABIKey, typename ValidLotusType<T>::ABIValue>(
|
||||
std::move(std_map));
|
||||
|
||||
writable_vector.Append(abi_map);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue