Add new SessionOptions config entry to disable specific transformers and rules (#20135)

### Description
<!-- Describe your changes. -->

### Motivation and Context
<!-- - Why is this change required? What problem does it solve?
- If it fixes an open issue, please link to the issue here. -->

Certain transformers slow down session loading time while providing no
runtime perf benefits.
Allow clients to exclude them.
This commit is contained in:
Dmitri Smirnov 2024-04-02 16:33:05 -07:00 committed by GitHub
parent e916929371
commit 12e2538065
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 74 additions and 15 deletions

View file

@ -7,17 +7,27 @@
// These are the inline implementations of the C++ header APIs. They're in this separate file as to not clutter
// the main C++ file with implementation details.
#include <cstring>
#include <algorithm>
#include <functional>
#include <iterator>
#include <type_traits>
#define RETURN_ON_API_FAIL(expression) \
{ \
auto err = (expression); \
if (err) { \
return Status(err); \
} \
// Convert OrtStatus to Ort::Status and return
// instead of throwing
#define ORT_CXX_RETURN_ON_API_FAIL(expression) \
{ \
auto ort_status = (expression); \
if (ort_status) { \
return Ort::Status(ort_status); \
} \
}
#ifdef __cpp_if_constexpr
#define ORT_CXX_IF_CONSTEXPR if constexpr
#else
#define ORT_CXX_IF_CONSTEXPR if
#endif
namespace Ort {
namespace detail {
@ -1967,7 +1977,7 @@ inline ShapeInferContext::ShapeInferContext(const OrtApi* ort_api,
inline Status ShapeInferContext::SetOutputShape(size_t indice, const Shape& shape) {
OrtTensorTypeAndShapeInfo* info = {};
RETURN_ON_API_FAIL(ort_api_->CreateTensorTypeAndShapeInfo(&info));
ORT_CXX_RETURN_ON_API_FAIL(ort_api_->CreateTensorTypeAndShapeInfo(&info));
using InfoPtr = std::unique_ptr<OrtTensorTypeAndShapeInfo, std::function<void(OrtTensorTypeAndShapeInfo*)>>;
@ -1991,9 +2001,9 @@ inline Status ShapeInferContext::SetOutputShape(size_t indice, const Shape& shap
}
}
RETURN_ON_API_FAIL(ort_api_->SetDimensions(info, integer_dims.data(), integer_dims.size()));
RETURN_ON_API_FAIL(ort_api_->SetSymbolicDimensions(info, symbolic_dims.data(), symbolic_dims.size()));
RETURN_ON_API_FAIL(ort_api_->ShapeInferContext_SetOutputTypeShape(ctx_, indice, info));
ORT_CXX_RETURN_ON_API_FAIL(ort_api_->SetDimensions(info, integer_dims.data(), integer_dims.size()));
ORT_CXX_RETURN_ON_API_FAIL(ort_api_->SetSymbolicDimensions(info, symbolic_dims.data(), symbolic_dims.size()));
ORT_CXX_RETURN_ON_API_FAIL(ort_api_->ShapeInferContext_SetOutputTypeShape(ctx_, indice, info));
return Status{nullptr};
}

View file

@ -93,6 +93,15 @@ static const char* const kOrtSessionOptionsMemoryOptimizerEnabler = "optimizatio
static const char* const kOrtSessionOptionsMemoryOptimizerProbeConfig = "optimization.enable_memory_probe_recompute_config";
#endif
// This setting if set should contain a comma separated list of optimizers names that should be disabled.
// Optimizers may take time to execute and affect model loading time. If you feel that a specific optimizer
// does not provider runtime benefits, but affects your model loading time you may disable it using this config
// entry. This option is not enabled in ORT_MINIMAL_BUILD build.
// A list of optimizes is available in onnxruntime/core/optimizer/graph_transformer_utils.cc
//
// Default is an empty string which means no optimizers are disabled.
static const char* const kOrtSessionOptionsDisableSpecifiedOptimizers = "optimization.disable_specified_optimizers";
// Enable or disable using device allocator for allocating initialized tensor memory. "1": enable; "0": disable. The default is "0".
// Using device allocators means the memory allocation is made using malloc/new.
static const char* const kOrtSessionOptionsUseDeviceAllocatorForInitializers = "session.use_device_allocator_for_initializers";

View file

@ -15,6 +15,7 @@
#include "core/common/logging/logging.h"
#include "core/common/parse_string.h"
#include "core/common/path_string.h"
#include "core/common/string_utils.h"
#include "core/flatbuffers/flatbuffers_utils.h"
#include "core/flatbuffers/ort_format_version.h"
#include "core/framework/bfc_arena.h"
@ -401,7 +402,21 @@ void InferenceSession::ConstructorCommon(const SessionOptions& session_options,
#if !defined(ORT_MINIMAL_BUILD)
// Update the number of steps for the graph transformer manager using the "finalized" session options
ORT_ENFORCE(graph_transformer_mgr_.SetSteps(session_options_.max_num_graph_transformation_steps).IsOK());
ORT_THROW_IF_ERROR(graph_transformer_mgr_.SetSteps(session_options_.max_num_graph_transformation_steps));
#endif
#if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD)
{
auto disabled_string = session_options_.config_options.GetConfigOrDefault(
kOrtSessionOptionsDisableSpecifiedOptimizers, "");
if (!disabled_string.empty()) {
const auto disabled_list = utils::SplitString(disabled_string, ";");
InlinedHashSet<std::string> disabled_rules_and_transformers;
disabled_rules_and_transformers.reserve(disabled_list.size());
disabled_rules_and_transformers.insert(disabled_list.cbegin(), disabled_list.cend());
ORT_THROW_IF_ERROR(FilterEnabledOptimizers(std::move(disabled_rules_and_transformers)));
}
}
#endif
bool set_denormal_as_zero =

View file

@ -2726,8 +2726,7 @@ static constexpr OrtApi ort_api_1_to_18 = {
&OrtApis::SessionOptionsAppendExecutionProvider_OpenVINO_V2,
&OrtApis::SessionOptionsAppendExecutionProvider_VitisAI,
&OrtApis::KernelContext_GetScratchBuffer,
&OrtApis::KernelInfoGetAllocator,
};
&OrtApis::KernelInfoGetAllocator};
// OrtApiBase can never change as there is no way to know what version of OrtApiBase is returned by OrtGetApiBase.
static_assert(sizeof(OrtApiBase) == sizeof(void*) * 2, "New methods can't be added to OrtApiBase as it is not versioned");

View file

@ -6023,6 +6023,33 @@ TEST_F(GraphTransformationTests, FilterEnabledOptimizers) {
ASSERT_TRUE(op_to_count["Add"] == 1);
}
TEST_F(GraphTransformationTests, FilterEnabledOptimizersViaSessionOptions) {
constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/constant_folding_with_scalar_shape_to_initializer.onnx";
SessionOptions so;
so.session_logid = "GraphTransformationTests.FilterEnabledOptimizersViaSessionOptions";
ASSERT_STATUS_OK(so.config_options.AddConfigEntry(kOrtSessionOptionsDisableSpecifiedOptimizers, "ConstantFolding"));
InferenceSessionWrapper session_object{so, GetEnvironment()};
ASSERT_STATUS_OK(session_object.Load(model_uri));
const auto& graph = session_object.GetGraph();
// check the ops that should go away if the constant folding transformer runs
std::map<std::string, int> op_to_count = CountOpsInGraph(graph);
ASSERT_TRUE(op_to_count["Shape"] == 1);
ASSERT_TRUE(op_to_count["ConstantOfShape"] == 1);
ASSERT_TRUE(op_to_count["Add"] == 1);
ASSERT_STATUS_OK(session_object.Initialize()); // Initialize runs the transformers
op_to_count = CountOpsInGraph(graph);
ASSERT_TRUE(op_to_count["Shape"] == 1);
ASSERT_TRUE(op_to_count["ConstantOfShape"] == 1);
ASSERT_TRUE(op_to_count["Add"] == 1);
}
TEST_F(GraphTransformationTests, PropagateCastOpsTests) {
using Strategy = GraphTransformerConfiguration::PropagateCastOpsConfiguration::Strategy;
struct PropagateCastOpsTestSpecs {

View file

@ -4,7 +4,6 @@
#include "core/common/common.h"
#include "core/session/onnxruntime_cxx_api.h"
#include "core/session/onnxruntime_session_options_config_keys.h"
#include "core/optimizer/graph_transformer_level.h"
#include "gmock/gmock.h"
using namespace onnxruntime;