diff --git a/onnxruntime/core/providers/openvino/backend_manager.cc b/onnxruntime/core/providers/openvino/backend_manager.cc index 215cfafb2d174..a2f39b0705dbb 100644 --- a/onnxruntime/core/providers/openvino/backend_manager.cc +++ b/onnxruntime/core/providers/openvino/backend_manager.cc @@ -84,18 +84,21 @@ BackendManager::BackendManager(SessionContext& session_context, std::string device_type = session_context_.device_type; auto& sw = shared_context_.shared_weights; + if (sw.external_weight_filename.empty() && !sw.metadata.empty()) { + // Reasonable assumption that all metadata entries have the same external file location + sw.external_weight_filename = sw.metadata.begin()->second.location; + } + if (session_context_.so_share_ep_contexts) { - std::filesystem::path weight_filename = session_context_.onnx_model_path_name.parent_path(); - if (sw.external_weight_filename.empty() && !sw.metadata.empty()) { - // Reasonable assumption that all metadata entries have the same external file location - sw.external_weight_filename = sw.metadata.begin()->second.location; + auto weight_path = session_context_.GetNewWeightsFilePath(sw.external_weight_filename); + if (!std::filesystem::exists(weight_path)) { + weight_path = session_context_.GetModelDirectory() / sw.external_weight_filename; } - weight_filename /= sw.external_weight_filename; - std::ifstream weight_file(weight_filename); + std::ifstream weight_file(weight_path); if (weight_file) { if (!sw.mapped_weights) { - sw.mapped_weights = std::make_unique(weight_filename); + sw.mapped_weights = std::make_unique(weight_path); } backend_utils::CreateOVTensors(session_context_.device_type, sw.metadata, *sw.mapped_weights); } @@ -241,7 +244,7 @@ Status BackendManager::ExportCompiledBlobAsEPCtxNode(const onnxruntime::GraphVie std::ofstream blob_file(blob_filename, std::ios::out | std::ios::trunc | std::ios::binary); if (!blob_file) { - ORT_THROW("Unable to open file for epctx model dump."); + ORT_THROW("Unable to open file for epctx model dump." + blob_filename.string()); } compiled_model.export_model(blob_file); model_blob_str = blob_filename.filename().string(); @@ -324,7 +327,7 @@ static bool IsQDQGraph(const onnxruntime::GraphViewer& graph_viewer) { static void DumpOpenVINOEPModel([[maybe_unused]] const std::filesystem::path& onnx_model_path_name, [[maybe_unused]] ONNX_NAMESPACE::ModelProto* model_proto, [[maybe_unused]] const onnxruntime::Node& fused_node) { -#ifdef NOT_RELEASE +#ifdef NOT_RELEASE if (openvino_ep::backend_utils::IsDebugEnabled()) { auto model_name = onnx_model_path_name.empty() ? "unknown.onnx" : onnx_model_path_name.filename(); diff --git a/onnxruntime/core/providers/openvino/contexts.h b/onnxruntime/core/providers/openvino/contexts.h index 1314edd54e937..621bd461eeb72 100644 --- a/onnxruntime/core/providers/openvino/contexts.h +++ b/onnxruntime/core/providers/openvino/contexts.h @@ -118,6 +118,20 @@ struct SessionContext : ProviderInfo { mutable bool has_external_weights = false; // Value is set to mutable to modify from capability const std::vector OpenVINO_Version = {OPENVINO_VERSION_MAJOR, OPENVINO_VERSION_MINOR}; const std::string openvino_sdk_version = std::to_string(OPENVINO_VERSION_MAJOR) + "." + std::to_string(OPENVINO_VERSION_MINOR); + + fs::path GetModelDirectory() const { + return onnx_model_path_name.parent_path(); + } + + fs::path GetEpContextOutputDirectory() const { + return so_context_file_path.empty() ? GetModelDirectory() : so_context_file_path.parent_path(); + } + + fs::path GetNewWeightsFilePath(fs::path external_weights_filename) const { + ORT_ENFORCE(!external_weights_filename.empty(), "External weights filename should not be empty."); + // Otherwise, use the provided external weights filename. + return GetEpContextOutputDirectory() / fs::path(external_weights_filename.filename().string() + "_weights.bin"); + } }; // Holds context specific to subgraph. diff --git a/onnxruntime/core/providers/openvino/openvino_execution_provider.cc b/onnxruntime/core/providers/openvino/openvino_execution_provider.cc index f9d4ab13cf2ce..d1218efc3a85d 100644 --- a/onnxruntime/core/providers/openvino/openvino_execution_provider.cc +++ b/onnxruntime/core/providers/openvino/openvino_execution_provider.cc @@ -102,12 +102,13 @@ common::Status OpenVINOExecutionProvider::Compile( graph_body_viewer_0.DomainToVersionMap().at(kOnnxDomain); } + const auto metadata_path = session_context_.GetEpContextOutputDirectory() / "metadata.bin"; + // Temporary code to read metadata before it moves to the .bin auto& metadata = shared_context_->shared_weights.metadata; if (session_context_.so_share_ep_contexts && metadata.empty()) { // Metadata is always read from model location, this could be a source or epctx model - fs::path metadata_filename = session_context_.onnx_model_path_name.parent_path() / "metadata.bin"; - std::ifstream file(metadata_filename, std::ios::binary); + std::ifstream file(metadata_path, std::ios::binary); if (file) { file >> metadata; } @@ -174,20 +175,30 @@ common::Status OpenVINOExecutionProvider::Compile( } if (session_context_.so_share_ep_contexts) { - fs::path metadata_filename; - if (session_context_.so_context_file_path.empty()) { - metadata_filename = session_context_.onnx_model_path_name.parent_path() / "metadata.bin"; + const auto& sw_path_filename = shared_context_->shared_weights.external_weight_filename; + fs::path new_weights_file_path = session_context_.GetNewWeightsFilePath(sw_path_filename); + fs::path original_weights_path = session_context_.GetModelDirectory() / sw_path_filename; + + if (!std::filesystem::exists(new_weights_file_path)) { + try { + std::filesystem::create_hard_link(original_weights_path, new_weights_file_path); + } catch (const std::filesystem::filesystem_error& e) { + LOGS_DEFAULT(WARNING) << "Failed to create hard link: " << e.what() << " Falling back to copy."; + std::filesystem::copy_file(original_weights_path, new_weights_file_path); + } } else { - metadata_filename = session_context_.so_context_file_path.parent_path() / "metadata.bin"; + LOGS_DEFAULT(WARNING) << "Weights file already exists: " << new_weights_file_path.string() << " Link/Copy."; } // Metadata is generated only for shared contexts - // If saving metadata then save it to the provided path or ose the original model path + // If saving metadata then save it to the provided path or use the original model path // Multiple calls to Compile() will update the metadata and for the last call // the resulting file will contain the aggregated content - std::ofstream file(metadata_filename, std::ios::binary); + std::ofstream file(metadata_path, std::ios::binary); if (file) { file << metadata; + } else { + LOGS_DEFAULT(WARNING) << "Failed to write metadata to file: " << metadata_path.string(); } }