Skip to content

Commit

Permalink
Fix model serialization with external data in current directory (micr…
Browse files Browse the repository at this point in the history
…osoft#17311)

When original model has external data in current directory, saving the
optimized model will raise File not found exception during looking for
external data file under root directory "/". This fix will look under
current directory for this case.

I manually tested an extra case and it is working: Original model with
external data in root directory ("/"), and save optimized to current
directory.

BTW, there is another bug found: when
"session.optimized_model_external_initializers_min_size_in_bytes" is set
a large value, some tensor is still pointed to the original external
data file. Add a TODO in unit test for this bug. Possible solution: load
external data into memory before saving model.
  • Loading branch information
tianleiwu authored Aug 28, 2023
1 parent 228db24 commit ee9d046
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
2 changes: 1 addition & 1 deletion onnxruntime/core/framework/tensorprotoutils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1492,7 +1492,7 @@ Status UnpackInitializerData(const onnx::TensorProto& initializer,
if (initializer.data_location() == TensorProto_DataLocation_EXTERNAL) {
ORT_RETURN_IF_ERROR(ReadExternalDataForTensor(
initializer,
model_path.IsEmpty() ? nullptr : model_path.ParentPath().ToPathString().c_str(),
(model_path.IsEmpty() || model_path.ParentPath().IsEmpty()) ? nullptr : model_path.ParentPath().ToPathString().c_str(),
unpacked_tensor));
return Status::OK();
}
Expand Down
56 changes: 56 additions & 0 deletions onnxruntime/test/python/onnxruntime_test_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,62 @@ def test_model_serialization_with_original_external_initializers_to_directory(se
else:
raise onnxruntime_error

def test_model_serialization_with_original_external_initializers_to_current_directory(self):
optimized_model_filepath = "model_opt_with_ext_data_1.onnx"
external_initializers_file = "model_opt_with_ext_data_1.bin"
optimized_model_filepath_2 = "model_opt_with_ext_data_2.onnx"
external_initializers_file_2 = "model_opt_with_ext_data_2.bin"

so = onnxrt.SessionOptions()
so.log_severity_level = 1
so.logid = "TestModelSerializationWithOriginalExternalInitializersToCurrentDirectory"
so.optimized_model_filepath = optimized_model_filepath

so.add_session_config_entry(
"session.optimized_model_external_initializers_file_name", external_initializers_file
)

# TODO(anyone): Set this to 100 will cause test error since some tensor below the threshold
# still refers to the original external data file. We shall fix this issue so that the
# optimized model only refers to one external data file.
so.add_session_config_entry("session.optimized_model_external_initializers_min_size_in_bytes", "10")
session1 = onnxrt.InferenceSession(
get_name("model_with_orig_ext_data.onnx"), sess_options=so, providers=["CPUExecutionProvider"]
)
del session1
self.assertTrue(os.path.isfile(optimized_model_filepath))
self.assertTrue(os.path.isfile(external_initializers_file))

so2 = onnxrt.SessionOptions()
so2.log_severity_level = 1
so2.logid = "TestModelSerializationWithExternalInitializersInCurrentDirectory"
so2.optimized_model_filepath = optimized_model_filepath_2
so2.add_session_config_entry(
"session.optimized_model_external_initializers_file_name", external_initializers_file_2
)
so2.add_session_config_entry("session.optimized_model_external_initializers_min_size_in_bytes", "10")

# verify that we can load the optimized model with external data in current directory and save
# optimized model with external data to current directory.
session2 = onnxrt.InferenceSession(
optimized_model_filepath, sess_options=so2, providers=["CPUExecutionProvider"]
)
del session2
self.assertTrue(os.path.isfile(optimized_model_filepath_2))
self.assertTrue(os.path.isfile(external_initializers_file_2))

# Remove model 1 to make sure optimized model 2 can be loaded independently from model 1
os.remove(optimized_model_filepath)
os.remove(external_initializers_file)

session3 = onnxrt.InferenceSession(
optimized_model_filepath_2, sess_options=onnxrt.SessionOptions(), providers=["CPUExecutionProvider"]
)
del session3

os.remove(optimized_model_filepath_2)
os.remove(external_initializers_file_2)

def test_get_providers(self):
self.assertTrue("CPUExecutionProvider" in onnxrt.get_available_providers())
# get_all_providers() returns the default EP order from highest to lowest.
Expand Down

0 comments on commit ee9d046

Please sign in to comment.