Disable external initializers build option (#7635)

* Merge set custom allocator to master

* Add documentation for the new API.
Reset global env in testCustomArenaAllocator so won't have a registered allocator of type arena (from previous test)

* Add a session option config that will allow to disable loading model with initializers that have an external data (+test it).

* Add the model used for the test and its external initializers data

* Change the session config option that disable external initializers to a build option.

* Addressing PR comments
This commit is contained in:
alonre24 2021-05-20 00:16:36 +03:00 committed by GitHub
parent 6c868341e3
commit 374acf1423
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 130 additions and 13 deletions

View file

@ -124,6 +124,7 @@ option(onnxruntime_EXTENDED_MINIMAL_BUILD "onnxruntime_MINIMAL_BUILD with suppor
option(onnxruntime_MINIMAL_BUILD_CUSTOM_OPS "Add custom operator kernels support to a minimal build." OFF)
option(onnxruntime_REDUCED_OPS_BUILD "Reduced set of kernels are registered in build via modification of the kernel registration source files." OFF)
option(onnxruntime_DISABLE_ORT_FORMAT_LOAD "Disable loading an ORT format model when onnxruntime_MINIMAL_BUILD=OFF (i.e. in a full build)." OFF)
option(onnxruntime_DISABLE_EXTERNAL_INITIALIZERS "Don't allow models to load external data" OFF)
#A special option just for debugging and sanitize check. Please do not enable in option in retail builds.
#The option has no effect on Windows.
@ -363,6 +364,10 @@ if (onnxruntime_REDUCED_OPS_BUILD)
add_compile_definitions(REDUCED_OPS_BUILD)
endif()
if(onnxruntime_DISABLE_EXTERNAL_INITIALIZERS)
add_definitions(-DDISABLE_EXTERNAL_INITIALIZERS=1)
endif()
if(onnxruntime_DISABLE_RTTI)
add_compile_definitions(ORT_NO_RTTI GOOGLE_PROTOBUF_NO_RTTI)
if(MSVC)

View file

@ -785,13 +785,13 @@ struct OrtApi {
* \name - name of the attribute to be parsed
* \out - pointer to memory where the attribute's contents are to be stored
* \size - actual size of string attribute
* (If `out` is nullptr, the value of `size` is set to the true size of the string
* (If `out` is nullptr, the value of `size` is set to the true size of the string
attribute, and a success status is returned.
If the `size` parameter is greater than or equal to the actual string attribute's size,
the value of `size` is set to the true size of the string attribute, the provided memory
is filled with the attribute's contents, and a success status is returned.
If the `size` parameter is lesser than the actual string attribute's size and `out`
is not nullptr, the value of `size` is set to the true size of the string attribute
and a failure status is returned.)
@ -1258,14 +1258,14 @@ struct OrtApi {
* \name - name of the attribute to be parsed
* \out - pointer to memory where the attribute's contents are to be stored
* \size - actual size of attribute array
* (If `out` is nullptr, the value of `size` is set to the true size of the attribute
* (If `out` is nullptr, the value of `size` is set to the true size of the attribute
array's size, and a success status is returned.
If the `size` parameter is greater than or equal to the actual attribute array's size,
the value of `size` is set to the true size of the attribute array's size,
the provided memory is filled with the attribute's contents,
the provided memory is filled with the attribute's contents,
and a success status is returned.
If the `size` parameter is lesser than the actual attribute array's size and `out`
is not nullptr, the value of `size` is set to the true size of the attribute array's size
and a failure status is returned.)
@ -1279,14 +1279,14 @@ struct OrtApi {
* \name - name of the attribute to be parsed
* \out - pointer to memory where the attribute's contents are to be stored
* \size - actual size of attribute array
* (If `out` is nullptr, the value of `size` is set to the true size of the attribute
* (If `out` is nullptr, the value of `size` is set to the true size of the attribute
array's size, and a success status is returned.
If the `size` parameter is greater than or equal to the actual attribute array's size,
the value of `size` is set to the true size of the attribute array's size,
the provided memory is filled with the attribute's contents,
the provided memory is filled with the attribute's contents,
and a success status is returned.
If the `size` parameter is lesser than the actual attribute array's size and `out`
is not nullptr, the value of `size` is set to the true size of the attribute array's size
and a failure status is returned.)

View file

@ -1160,6 +1160,18 @@ common::Status InferenceSession::Initialize() {
have_cpu_ep = execution_providers_.Get(onnxruntime::kCpuExecutionProvider) != nullptr;
}
// Verify that there are no external initializers in the graph if external data is disabled.
onnxruntime::Graph& graph = model_->MainGraph();
#ifdef DISABLE_EXTERNAL_INITIALIZERS
const InitializedTensorSet& initializers = graph.GetAllInitializedTensors();
for (const auto& it: initializers) {
if (utils::HasExternalData(*it.second)) {
return common::Status(common::ONNXRUNTIME, common::FAIL,
"Initializer tensors with external data is not allowed.");
}
}
#endif
// Register default CPUExecutionProvider if user didn't provide it through the Register() calls.
// RegisterExecutionProvider locks the session_mutex_ so we can't be holding it when we call that
if (!have_cpu_ep) {
@ -1210,8 +1222,6 @@ common::Status InferenceSession::Initialize() {
session_options_.enable_mem_reuse,
prepacked_weights_container_);
onnxruntime::Graph& graph = model_->MainGraph();
// Collect the kernel registries from execution provider instances;
// There are 2 kinds of kernel registries with priority from high to low as below,
// 1. Custom execution provider type specific kernel registries.

View file

@ -2,6 +2,8 @@
// Licensed under the MIT License.
#include "core/session/onnxruntime_cxx_api.h"
#include "onnxruntime_session_options_config_keys.h"
#include "test/util/include/asserts.h"
#ifdef USE_CUDA
#include "core/providers/cuda/cuda_provider_factory.h"
#endif
@ -57,5 +59,20 @@ TEST(CApiTest, model_from_array) {
#endif
}
#endif
#ifdef DISABLE_EXTERNAL_INITIALIZERS
TEST(CApiTest, TestDisableExternalInitiliazers) {
const char* model_path = "testdata/model_with_external_initializers.onnx";
Ort::SessionOptions so;
try {
Ort::Session session(*ort_env.get(), model_path, so);
ASSERT_TRUE(false) << "Creation of session should have thrown exception";
} catch (const std::exception& ex) {
ASSERT_THAT(ex.what(), testing::HasSubstr("Initializer tensors with external data is not allowed."));
}
}
#endif
} // namespace test
} // namespace onnxruntime

BIN
onnxruntime/test/testdata/Pads.bin vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,19 @@
 onnx-example:
&
X
PadsY"Pad*
mode"constant 
test-model*"BPadsj
locationPads.binpZ
X


Z
Pads

b
Y


B

View file

@ -0,0 +1,66 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import onnx
import numpy as np
from onnx import helper
from onnx import TensorProto
from onnx.numpy_helper import from_array
from onnx.external_data_helper import set_external_data
def create_external_data_tensor(value, tensor_name): # type: (List[Any], Text) -> TensorProto
tensor = from_array(np.array(value))
tensor.name = tensor_name
tensor_filename = "{}.bin".format(tensor_name)
set_external_data(tensor, location=tensor_filename)
with open(os.path.join(tensor_filename), 'wb') as data_file:
data_file.write(tensor.raw_data)
tensor.ClearField('raw_data')
tensor.data_location = onnx.TensorProto.EXTERNAL
return tensor
def GenerateModel(model_name):
# Create one input (ValueInfoProto)
X = helper.make_tensor_value_info('X', TensorProto.FLOAT, [1, 2])
# Create second input (ValueInfoProto)
Pads = helper.make_tensor_value_info('Pads', TensorProto.INT64, [4])
# Create one output (ValueInfoProto)
Y = helper.make_tensor_value_info('Y', TensorProto.FLOAT, [1, 4])
# Create a node (NodeProto)
node_def = helper.make_node(
'Pad', # node name
['X', 'Pads'], # inputs
['Y'], # outputs
mode='constant', # Attributes
)
# Create the graph (GraphProto)
graph_def = helper.make_graph(
[node_def],
"test-model",
[X, Pads],
[Y],
[create_external_data_tensor([0, 0, 1, 1, ], "Pads")]
)
# Create the model (ModelProto)
model_def = helper.make_model(graph_def,
producer_name='onnx-example')
print('The ir_version in model: {}\n'.format(model_def.ir_version))
print('The producer_name in model: {}\n'.format(model_def.producer_name))
print('The graph in model:\n{}'.format(model_def.graph))
onnx.checker.check_model(model_def)
print('The model is checked!')
with open(model_name, "wb") as model_file:
model_file.write(model_def.SerializeToString())
if __name__ == "__main__":
GenerateModel('model_with_external_initializers.onnx')