Implementation of MMAP for ONNX FE (#18026)
* Implementation of MMAP for ONNX FE * fix win offsets * added virtual dtor to MappedMemory * review remarks. part.1 * added disable mmap flag to MO * added additional checks to mmap * remove unnecessary const * fix pybind default value * Added args.disable_mmap = False to MO tests * fixed MO test * avoid global headers * fix casting for win * disable mmap for legacy frontends flow * review remarks * Fixed passing parameters * added doc to MappedMemory and load_mmap_object
This commit is contained in:
1 parent
96d16b141d
commit
c59746fd27
33 files changed
+555
-384
No files matched your search
@@ -112,17 +112,6 @@ macro(ov_add_frontend)
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE LIBRARY_SRC ${frontend_root_dir}/src/*.cpp)
|
||||
if (WIN32)
|
||||
# Remove linux specific files
|
||||
file(GLOB_RECURSE LIN_FILES ${frontend_root_dir}/src/os/lin/*.cpp
|
||||
${frontend_root_dir}/src/os/lin/*.hpp)
|
||||
list(REMOVE_ITEM LIBRARY_SRC "${LIN_FILES}")
|
||||
else()
|
||||
# Remove windows specific files
|
||||
file(GLOB_RECURSE WIN_FILES ${frontend_root_dir}/src/os/win/*.cpp
|
||||
${frontend_root_dir}/src/os/win/*.hpp)
|
||||
list(REMOVE_ITEM LIBRARY_SRC "${WIN_FILES}")
|
||||
endif()
|
||||
file(GLOB_RECURSE LIBRARY_HEADERS ${frontend_root_dir}/src/*.hpp)
|
||||
file(GLOB_RECURSE LIBRARY_PUBLIC_HEADERS ${frontend_root_dir}/include/*.hpp)
|
||||
|
||||
|
||||
@@ -37,29 +37,32 @@ void regclass_frontend_FrontEnd(py::module m) {
|
||||
|
||||
fem.def(
|
||||
"load",
|
||||
[](FrontEnd& self, const py::object& py_obj) {
|
||||
[](FrontEnd& self, const py::object& py_obj, const bool enable_mmap = true) {
|
||||
if (py::isinstance(py_obj, py::module_::import("pathlib").attr("Path")) ||
|
||||
py::isinstance<py::str>(py_obj) || py::isinstance<py::bytes>(py_obj)) {
|
||||
// check if model path is either a string/pathlib.Path/bytes
|
||||
std::string model_path = Common::utils::convert_path_to_string(py_obj);
|
||||
return self.load(model_path);
|
||||
return self.load(model_path, enable_mmap);
|
||||
} else if (py::isinstance(py_obj, pybind11::module::import("io").attr("BytesIO"))) {
|
||||
// support of BytesIO
|
||||
py::buffer_info info = py::buffer(py_obj.attr("getbuffer")()).request();
|
||||
MemoryBuffer mb(reinterpret_cast<char*>(info.ptr), info.size);
|
||||
std::istream _istream(&mb);
|
||||
return self.load(&_istream);
|
||||
return self.load(&_istream, enable_mmap);
|
||||
} else {
|
||||
// Extended for one argument only for this time
|
||||
return self.load({Common::utils::py_object_to_any(py_obj)});
|
||||
return self.load({Common::utils::py_object_to_any(py_obj), enable_mmap});
|
||||
}
|
||||
},
|
||||
py::arg("path"),
|
||||
py::arg("enable_mmap") = true,
|
||||
R"(
|
||||
Loads an input model.
|
||||
|
||||
:param path: Object describing the model. It can be path to model file.
|
||||
:type path: Any
|
||||
:param enable_mmap: Use mmap feature to map memory of a model's weights instead of reading directly. Optional. The default value is true.
|
||||
:type enable_mmap: boolean
|
||||
:return: Loaded input model.
|
||||
:rtype: openvino.frontend.InputModel
|
||||
)");
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
/**
|
||||
* @brief A header file for definition of abstraction over platform specific shared memory map objects
|
||||
* @file mmap_object.hpp
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace ov {
|
||||
|
||||
/**
|
||||
* @brief This class represents a mapped memory.
|
||||
* Instead of reading files, we can map the memory via mmap for Linux or MapViewOfFile for Windows.
|
||||
* The MappedMemory class is a abstraction to handle such memory with os-dependent details.
|
||||
*/
|
||||
class MappedMemory {
|
||||
public:
|
||||
virtual char* data() noexcept = 0;
|
||||
virtual size_t size() const noexcept = 0;
|
||||
virtual ~MappedMemory() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Returns mapped memory for a file from provided path.
|
||||
* Instead of reading files, we can map the memory via mmap for Linux
|
||||
* in order to avoid time-consuming reading and reduce memory consumption.
|
||||
*
|
||||
* @param path Path to a file which memory will be mmaped.
|
||||
* @param data_size Number of bytes to map (zero, if all file will be mmaped).
|
||||
* @param offset Number of bytes to skip from beginning of the file.
|
||||
* @return MappedMemory shared ptr object which keep mmaped memory and control the lifetime.
|
||||
*/
|
||||
std::shared_ptr<ov::MappedMemory> load_mmap_object(const std::string& path,
|
||||
const size_t data_size = 0,
|
||||
const size_t offset = 0);
|
||||
|
||||
#ifdef OPENVINO_ENABLE_UNICODE_PATH_SUPPORT
|
||||
|
||||
/**
|
||||
* @brief Returns mapped memory for a file from provided path.
|
||||
* Instead of reading files, we can map the memory via MapViewOfFile for Windows
|
||||
* in order to avoid time-consuming reading and reduce memory consumption.
|
||||
*
|
||||
* @param path Path to a file which memory will be mmaped.
|
||||
* @param data_size Number of bytes to map (zero, if all file will be mmaped).
|
||||
* @param offset Number of bytes to skip from beginning of the file.
|
||||
* @return MappedMemory shared ptr object which keep mmaped memory and control the lifetime.
|
||||
*/
|
||||
std::shared_ptr<ov::MappedMemory> load_mmap_object(const std::wstring& path,
|
||||
const size_t data_size = 0,
|
||||
const size_t offset = 0);
|
||||
|
||||
#endif // OPENVINO_ENABLE_UNICODE_PATH_SUPPORT
|
||||
|
||||
} // namespace ov
|
||||
+27
-19
@@ -8,12 +8,12 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "mmap_object.hpp"
|
||||
#include "ngraph/runtime/shared_buffer.hpp"
|
||||
#include "openvino/util/file_util.hpp"
|
||||
#include "openvino/util/mmap_object.hpp"
|
||||
|
||||
namespace ov {
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class MapHolder {
|
||||
class MapHolder : public MappedMemory {
|
||||
void* m_data = MAP_FAILED;
|
||||
size_t m_size = 0;
|
||||
HandleHolder m_handle;
|
||||
@@ -63,21 +63,29 @@ class MapHolder {
|
||||
public:
|
||||
MapHolder() = default;
|
||||
|
||||
void set(const std::string& path) {
|
||||
void set(const std::string& path, const size_t data_size = 0, const size_t offset = 0) {
|
||||
int prot = PROT_READ;
|
||||
int mode = O_RDONLY;
|
||||
struct stat sb = {};
|
||||
m_handle = HandleHolder(open(path.c_str(), mode));
|
||||
OPENVINO_ASSERT(m_handle.get() != -1,
|
||||
"Can not open file ",
|
||||
path,
|
||||
" for mapping. Ensure that file exists and has appropriate permissions");
|
||||
OPENVINO_ASSERT(fstat(m_handle.get(), &sb) != -1, "Can not get file size for ", path);
|
||||
m_size = sb.st_size;
|
||||
if (m_handle.get() == -1) {
|
||||
throw std::runtime_error("Can not open file " + path +
|
||||
" for mapping. Ensure that file exists and has appropriate permissions");
|
||||
}
|
||||
if (fstat(m_handle.get(), &sb) == -1) {
|
||||
throw std::runtime_error("Can not get file size for " + path);
|
||||
}
|
||||
if (data_size + offset > static_cast<size_t>(sb.st_size)) {
|
||||
throw std::runtime_error("Can not map out of scope memory for " + path);
|
||||
}
|
||||
m_size = data_size > 0 ? data_size : sb.st_size - offset;
|
||||
if (m_size > 0) {
|
||||
m_data = mmap(nullptr, m_size, prot, MAP_PRIVATE, m_handle.get(), 0);
|
||||
OPENVINO_ASSERT(m_data != MAP_FAILED, "Can not create file mapping for ", path, ", err=", strerror(errno));
|
||||
m_data = mmap(nullptr, m_size, prot, MAP_PRIVATE, m_handle.get(), offset);
|
||||
if (m_data == MAP_FAILED) {
|
||||
throw std::runtime_error("Can not create file mapping for " + path + ", err=" + std::strerror(errno));
|
||||
}
|
||||
} else {
|
||||
m_size = 0;
|
||||
m_data = MAP_FAILED;
|
||||
}
|
||||
}
|
||||
@@ -88,21 +96,21 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
char* data() noexcept {
|
||||
char* data() noexcept override {
|
||||
return static_cast<char*>(m_data);
|
||||
}
|
||||
|
||||
size_t size() const noexcept {
|
||||
size_t size() const noexcept override {
|
||||
return m_size;
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<ngraph::runtime::AlignedBuffer> load_mmap_object(const std::string& path) {
|
||||
std::shared_ptr<ov::MappedMemory> load_mmap_object(const std::string& path,
|
||||
const size_t data_size,
|
||||
const size_t offset) {
|
||||
auto holder = std::make_shared<MapHolder>();
|
||||
holder->set(path);
|
||||
return std::make_shared<ngraph::runtime::SharedBuffer<std::shared_ptr<MapHolder>>>(holder->data(),
|
||||
holder->size(),
|
||||
holder);
|
||||
holder->set(path, data_size, offset);
|
||||
return holder;
|
||||
}
|
||||
|
||||
} // namespace ov
|
||||
+47
-34
@@ -2,10 +2,10 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "mmap_object.hpp"
|
||||
#include "ngraph/runtime/shared_buffer.hpp"
|
||||
#include "openvino/util/mmap_object.hpp"
|
||||
#include "openvino/util/file_util.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
// clang-format-off
|
||||
#ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class MapHolder {
|
||||
class MapHolder : public ov::MappedMemory {
|
||||
public:
|
||||
MapHolder() = default;
|
||||
|
||||
@@ -60,57 +60,74 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void set(const std::string& path) {
|
||||
void set(const std::string& path, const size_t data_size=0, const size_t offset=0) {
|
||||
// Note that file can't be changed (renamed/deleted) until it's unmapped. FILE_SHARE_DELETE flag allow
|
||||
// rename/deletion, but it doesn't work with FAT32 filesystem (works on NTFS)
|
||||
auto h = ::CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
map(path, h);
|
||||
map(path, h, data_size, offset);
|
||||
}
|
||||
|
||||
#ifdef OPENVINO_ENABLE_UNICODE_PATH_SUPPORT
|
||||
void set(const std::wstring& path) {
|
||||
void set(const std::wstring& path, const size_t data_size=0, const size_t offset=0) {
|
||||
// Note that file can't be changed (renamed/deleted) until it's unmapped. FILE_SHARE_DELETE flag allow
|
||||
// rename/deletion, but it doesn't work with FAT32 filesystem (works on NTFS)
|
||||
auto h = ::CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
map(ov::util::wstring_to_string(path), h);
|
||||
map(ov::util::wstring_to_string(path), h, data_size, offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
char* data() noexcept {
|
||||
char* data() noexcept override {
|
||||
return static_cast<char*>(m_data);
|
||||
}
|
||||
size_t size() const noexcept {
|
||||
size_t size() const noexcept override {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
private:
|
||||
void map(const std::string& path, HANDLE h) {
|
||||
OPENVINO_ASSERT(h != INVALID_HANDLE_VALUE,
|
||||
"Can not open file ",
|
||||
path,
|
||||
" for mapping. Ensure that file exists and has appropriate permissions");
|
||||
void map(const std::string& path, HANDLE h, const size_t data_size=0, const size_t offset=0) {
|
||||
if(h == INVALID_HANDLE_VALUE) {
|
||||
throw std::runtime_error("Can not open file " + path + " for mapping. Ensure that file exists and has appropriate permissions");
|
||||
}
|
||||
m_handle = HandleHolder(h);
|
||||
SYSTEM_INFO SystemInfo;
|
||||
GetSystemInfo(&SystemInfo);
|
||||
SYSTEM_INFO sys_info;
|
||||
GetSystemInfo(&sys_info);
|
||||
|
||||
DWORD map_mode = FILE_MAP_READ;
|
||||
DWORD access = PAGE_READONLY;
|
||||
|
||||
LARGE_INTEGER file_size_large;
|
||||
OPENVINO_ASSERT(::GetFileSizeEx(m_handle.get(), &file_size_large) != 0, "Can not get file size for ", path);
|
||||
if(::GetFileSizeEx(m_handle.get(), &file_size_large) == 0) {
|
||||
throw std::runtime_error("Can not get file size for " + path);
|
||||
}
|
||||
if (data_size + offset > static_cast<size_t>(file_size_large.QuadPart)) {
|
||||
throw std::runtime_error("Can not map out of scope memory for " + path);
|
||||
}
|
||||
m_size = data_size > 0 ? data_size : static_cast<size_t>(file_size_large.QuadPart) - offset;
|
||||
|
||||
// the offset must be a multiple of the allocation granularity
|
||||
const size_t alloc_gran = sys_info.dwAllocationGranularity;
|
||||
const size_t map_view_start = (offset / alloc_gran) * alloc_gran;
|
||||
const size_t map_view_size = (offset%alloc_gran) + m_size;
|
||||
const size_t file_map_size = offset + m_size;
|
||||
const size_t view_delta = offset - map_view_start;
|
||||
|
||||
m_size = static_cast<uint64_t>(file_size_large.QuadPart);
|
||||
if (m_size > 0) {
|
||||
m_mapping =
|
||||
HandleHolder(::CreateFileMapping(m_handle.get(), 0, access, m_size >> 32, m_size & 0xffffffff, 0));
|
||||
OPENVINO_ASSERT(m_mapping.get() != INVALID_HANDLE_VALUE, "Can not create file mapping for ", path);
|
||||
HandleHolder(::CreateFileMapping(m_handle.get(), 0, access, file_map_size >> 32, file_map_size & 0xffffffff, 0));
|
||||
if(m_mapping.get() == INVALID_HANDLE_VALUE) {
|
||||
throw std::runtime_error("Can not create file mapping for " + path);
|
||||
}
|
||||
|
||||
m_data = ::MapViewOfFile(m_mapping.get(),
|
||||
map_mode,
|
||||
0, // offset_align >> 32,
|
||||
0, // offset_align & 0xffffffff,
|
||||
m_size);
|
||||
OPENVINO_ASSERT(m_data, "Can not create map view for ", path);
|
||||
map_view_start >> 32, // offset_align >> 32,
|
||||
map_view_start & 0xffffffff, // offset_align & 0xffffffff,
|
||||
map_view_size);
|
||||
if(!m_data) {
|
||||
throw std::runtime_error("Can not create map view for " + path);
|
||||
}
|
||||
// move pointer to the expected data (after alignment with allocation granularity)
|
||||
m_data = reinterpret_cast<char*>(m_data) + view_delta;
|
||||
} else {
|
||||
m_data = nullptr;
|
||||
}
|
||||
@@ -123,22 +140,18 @@ private:
|
||||
HandleHolder m_mapping;
|
||||
};
|
||||
|
||||
std::shared_ptr<ngraph::runtime::AlignedBuffer> load_mmap_object(const std::string& path) {
|
||||
std::shared_ptr<ov::MappedMemory> load_mmap_object(const std::string& path, const size_t data_size, const size_t offset) {
|
||||
auto holder = std::make_shared<MapHolder>();
|
||||
holder->set(path);
|
||||
return std::make_shared<ngraph::runtime::SharedBuffer<std::shared_ptr<MapHolder>>>(holder->data(),
|
||||
holder->size(),
|
||||
holder);
|
||||
holder->set(path, data_size, offset);
|
||||
return holder;
|
||||
}
|
||||
|
||||
#ifdef OPENVINO_ENABLE_UNICODE_PATH_SUPPORT
|
||||
|
||||
std::shared_ptr<ngraph::runtime::AlignedBuffer> load_mmap_object(const std::wstring& path) {
|
||||
std::shared_ptr<ov::MappedMemory> load_mmap_object(const std::wstring& path, const size_t data_size, const size_t offset) {
|
||||
auto holder = std::make_shared<MapHolder>();
|
||||
holder->set(path);
|
||||
return std::make_shared<ngraph::runtime::SharedBuffer<std::shared_ptr<MapHolder>>>(holder->data(),
|
||||
holder->size(),
|
||||
holder);
|
||||
holder->set(path, data_size, offset);
|
||||
return holder;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -8,12 +8,12 @@
|
||||
#include <vector>
|
||||
|
||||
#include "input_model.hpp"
|
||||
#include "mmap_object.hpp"
|
||||
#include "ngraph/runtime/aligned_buffer.hpp"
|
||||
#include "ngraph/runtime/shared_buffer.hpp"
|
||||
#include "openvino/core/any.hpp"
|
||||
#include "openvino/core/so_extension.hpp"
|
||||
#include "openvino/util/file_util.hpp"
|
||||
#include "openvino/util/mmap_object.hpp"
|
||||
#include "xml_parse_utils.h"
|
||||
|
||||
using namespace ov;
|
||||
@@ -201,9 +201,13 @@ InputModel::Ptr FrontEnd::load_impl(const std::vector<ov::Any>& variants) const
|
||||
}
|
||||
}
|
||||
if (!weights_path.empty()) {
|
||||
if (enable_mmap)
|
||||
weights = ov::load_mmap_object(weights_path);
|
||||
else {
|
||||
if (enable_mmap) {
|
||||
auto mapped_memory = ov::load_mmap_object(weights_path);
|
||||
weights =
|
||||
std::make_shared<ngraph::runtime::SharedBuffer<std::shared_ptr<MappedMemory>>>(mapped_memory->data(),
|
||||
mapped_memory->size(),
|
||||
mapped_memory);
|
||||
} else {
|
||||
std::ifstream bin_stream;
|
||||
bin_stream.open(weights_path.c_str(), std::ios::binary);
|
||||
if (!bin_stream.is_open())
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
/**
|
||||
* @brief A header file for definition of abstraction over platform specific shared memory map objects
|
||||
* @file mmap_object.hpp
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ngraph/runtime/aligned_buffer.hpp"
|
||||
|
||||
namespace ov {
|
||||
|
||||
std::shared_ptr<ngraph::runtime::AlignedBuffer> load_mmap_object(const std::string& path);
|
||||
|
||||
#ifdef OPENVINO_ENABLE_UNICODE_PATH_SUPPORT
|
||||
|
||||
std::shared_ptr<ngraph::runtime::AlignedBuffer> load_mmap_object(const std::wstring& path);
|
||||
|
||||
#endif // OPENVINO_ENABLE_UNICODE_PATH_SUPPORT
|
||||
|
||||
} // namespace ov
|
||||
@@ -45,14 +45,17 @@ bool is_operator_supported(const std::string& op_name, std::int64_t version, con
|
||||
/// \note If stream parsing fails or the ONNX model contains unsupported ops,
|
||||
/// the function throws an ngraph_error exception.
|
||||
///
|
||||
/// \param[in] stream The input stream (e.g. file stream, memory stream, etc).
|
||||
/// \param[in] model_path The path to the imported onnx model.
|
||||
/// It is required if the imported model uses data saved in external
|
||||
/// files.
|
||||
/// \param[in] stream The input stream (e.g. file stream, memory stream, etc).
|
||||
/// \param[in] model_path The path to the imported onnx model.
|
||||
/// It is required if the imported model uses data saved in external
|
||||
/// files.
|
||||
/// \param[in] enable_mmap Enable mapping files with external weights instead of reading.
|
||||
///
|
||||
/// \return An nGraph function that represents a single output from the created graph.
|
||||
ONNX_IMPORTER_API
|
||||
std::shared_ptr<Function> import_onnx_model(std::istream& stream, const std::string& model_path = "");
|
||||
std::shared_ptr<Function> import_onnx_model(std::istream& stream,
|
||||
const std::string& model_path = "",
|
||||
bool enable_mmap = false);
|
||||
|
||||
/// \brief Imports and converts an ONNX model from the input file
|
||||
/// to an nGraph Function representation.
|
||||
@@ -62,10 +65,11 @@ std::shared_ptr<Function> import_onnx_model(std::istream& stream, const std::str
|
||||
///
|
||||
/// \param[in] file_path The path to a file containing the ONNX model
|
||||
/// (relative or absolute).
|
||||
/// \param[in] enable_mmap Enable mapping files with external weights instead of reading.
|
||||
///
|
||||
/// \return An nGraph function that represents a single output from the created graph.
|
||||
ONNX_IMPORTER_API
|
||||
std::shared_ptr<Function> import_onnx_model(const std::string& file_path);
|
||||
std::shared_ptr<Function> import_onnx_model(const std::string& file_path, bool enable_mmap = false);
|
||||
} // namespace onnx_import
|
||||
|
||||
} // namespace ngraph
|
||||
@@ -200,9 +200,12 @@ public:
|
||||
};
|
||||
|
||||
Attribute() = delete;
|
||||
explicit Attribute(const ONNX_NAMESPACE::AttributeProto& attribute_proto, const std::string& model_dir)
|
||||
explicit Attribute(const ONNX_NAMESPACE::AttributeProto& attribute_proto,
|
||||
const std::string& model_dir,
|
||||
const bool enable_mmap)
|
||||
: m_attribute_proto{&attribute_proto},
|
||||
m_model_dir{model_dir} {}
|
||||
m_model_dir{model_dir},
|
||||
m_enable_mmap{enable_mmap} {}
|
||||
|
||||
Attribute(Attribute&&) noexcept = default;
|
||||
Attribute(const Attribute&) = default;
|
||||
@@ -253,10 +256,10 @@ public:
|
||||
return get_type() == Type::graph_array;
|
||||
}
|
||||
Tensor get_tensor() const {
|
||||
return Tensor{m_attribute_proto->t(), m_model_dir};
|
||||
return Tensor{m_attribute_proto->t(), m_model_dir, m_enable_mmap};
|
||||
}
|
||||
SparseTensor get_sparse_tensor() const {
|
||||
return SparseTensor{m_attribute_proto->sparse_tensor(), m_model_dir};
|
||||
return SparseTensor{m_attribute_proto->sparse_tensor(), m_model_dir, m_enable_mmap};
|
||||
}
|
||||
float get_float() const {
|
||||
return m_attribute_proto->f();
|
||||
@@ -274,7 +277,7 @@ public:
|
||||
const auto& tensors = m_attribute_proto->tensors();
|
||||
ret.reserve(tensors.size());
|
||||
for (const auto& tensor : tensors)
|
||||
ret.emplace_back(tensor, m_model_dir);
|
||||
ret.emplace_back(tensor, m_model_dir, m_enable_mmap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -283,7 +286,7 @@ public:
|
||||
const auto& sparse_tensors = m_attribute_proto->sparse_tensors();
|
||||
ret.reserve(sparse_tensors.size());
|
||||
for (const auto& tensor : sparse_tensors)
|
||||
ret.emplace_back(tensor, m_model_dir);
|
||||
ret.emplace_back(tensor, m_model_dir, m_enable_mmap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -315,7 +318,7 @@ public:
|
||||
template <typename T, typename std::enable_if<std::is_same<T, Tensor>::value, bool>::type = true>
|
||||
T get_value() const {
|
||||
if (is_tensor()) {
|
||||
return Tensor{m_attribute_proto->t(), m_model_dir};
|
||||
return Tensor{m_attribute_proto->t(), m_model_dir, m_enable_mmap};
|
||||
}
|
||||
throw error::attribute::InvalidData{m_attribute_proto->type()};
|
||||
}
|
||||
@@ -323,7 +326,7 @@ public:
|
||||
template <typename T, typename std::enable_if<std::is_same<T, std::vector<Tensor>>::value, bool>::type = true>
|
||||
T get_value() const {
|
||||
if (is_tensor()) {
|
||||
return {Tensor{m_attribute_proto->t(), m_model_dir}};
|
||||
return {Tensor{m_attribute_proto->t(), m_model_dir, m_enable_mmap}};
|
||||
} else if (is_tensor_array()) {
|
||||
return get_tensor_array();
|
||||
}
|
||||
@@ -333,7 +336,7 @@ public:
|
||||
template <typename T, typename std::enable_if<std::is_same<T, SparseTensor>::value, bool>::type = true>
|
||||
T get_value() const {
|
||||
if (is_sparse_tensor()) {
|
||||
return SparseTensor{m_attribute_proto->sparse_tensor(), m_model_dir};
|
||||
return SparseTensor{m_attribute_proto->sparse_tensor(), m_model_dir, m_enable_mmap};
|
||||
}
|
||||
throw error::attribute::InvalidData{m_attribute_proto->type()};
|
||||
}
|
||||
@@ -341,7 +344,7 @@ public:
|
||||
template <typename T, typename std::enable_if<std::is_same<T, std::vector<SparseTensor>>::value, bool>::type = true>
|
||||
T get_value() const {
|
||||
if (is_sparse_tensor()) {
|
||||
return {SparseTensor{m_attribute_proto->sparse_tensor(), m_model_dir}};
|
||||
return {SparseTensor{m_attribute_proto->sparse_tensor(), m_model_dir, m_enable_mmap}};
|
||||
} else if (is_sparse_tensor_array()) {
|
||||
return get_sparse_tensor_array();
|
||||
}
|
||||
@@ -353,6 +356,7 @@ public:
|
||||
private:
|
||||
const ONNX_NAMESPACE::AttributeProto* m_attribute_proto;
|
||||
std::string m_model_dir;
|
||||
const bool m_enable_mmap;
|
||||
};
|
||||
|
||||
} // namespace onnx_import
|
||||
|
||||
@@ -145,16 +145,19 @@ ov::frontend::ExtensionHolder subgraph_required_extensions(
|
||||
|
||||
Graph::Graph(const std::string& model_dir,
|
||||
const std::shared_ptr<ONNX_NAMESPACE::ModelProto>& model_proto,
|
||||
const bool enable_mmap,
|
||||
ov::frontend::ExtensionHolder extensions)
|
||||
: Graph(model_dir, model_proto, common::make_unique<GraphCache>(), std::move(extensions)) {}
|
||||
: Graph(model_dir, model_proto, common::make_unique<GraphCache>(), enable_mmap, std::move(extensions)) {}
|
||||
|
||||
Graph::Graph(const std::string& model_dir,
|
||||
const std::shared_ptr<ONNX_NAMESPACE::ModelProto>& model_proto,
|
||||
std::unique_ptr<GraphCache>&& cache,
|
||||
const bool enable_mmap,
|
||||
ov::frontend::ExtensionHolder extensions)
|
||||
: m_cache{std::move(cache)},
|
||||
m_extensions{std::move(extensions)},
|
||||
m_model_dir{model_dir} {
|
||||
m_model_dir{model_dir},
|
||||
m_enable_mmap{enable_mmap} {
|
||||
const auto ops_bridge = detail::init_ops_bridge(m_extensions.conversions);
|
||||
m_model = common::make_unique<Model>(model_proto, detail::build_model_opset(*model_proto, ops_bridge));
|
||||
|
||||
@@ -165,7 +168,7 @@ Graph::Graph(const std::string& model_dir,
|
||||
// Process all initializers in the graph
|
||||
for (const auto& initializer_tensor : m_model->get_graph().initializer()) {
|
||||
if (initializer_tensor.has_name()) {
|
||||
Tensor tensor = Tensor{initializer_tensor, m_model_dir};
|
||||
Tensor tensor = Tensor{initializer_tensor, m_model_dir, enable_mmap};
|
||||
std::shared_ptr<default_opset::Constant> ng_constant;
|
||||
// For each initializer create a Constant node and store it in cache
|
||||
try {
|
||||
@@ -477,6 +480,7 @@ Subgraph::Subgraph(const std::shared_ptr<ONNX_NAMESPACE::ModelProto>& model_prot
|
||||
: Graph(parent_graph->model_dir(),
|
||||
model_proto,
|
||||
common::make_unique<GraphCache>(),
|
||||
parent_graph->mmap_enabled(),
|
||||
detail::subgraph_required_extensions(parent_graph->get_extensions())),
|
||||
m_parent_graph(parent_graph) {}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ class Graph : public std::enable_shared_from_this<Graph> {
|
||||
public:
|
||||
Graph(const std::string& model_dir,
|
||||
const std::shared_ptr<ONNX_NAMESPACE::ModelProto>& model_proto,
|
||||
const bool enable_mmap,
|
||||
ov::frontend::ExtensionHolder extensions = {});
|
||||
Graph() = delete;
|
||||
|
||||
@@ -40,6 +41,9 @@ public:
|
||||
const std::string& model_dir() const {
|
||||
return m_model_dir;
|
||||
}
|
||||
bool mmap_enabled() const {
|
||||
return m_enable_mmap;
|
||||
}
|
||||
const ParameterVector& get_ng_parameters() const {
|
||||
return m_parameters;
|
||||
}
|
||||
@@ -57,6 +61,7 @@ protected:
|
||||
Graph(const std::string& model_dir,
|
||||
const std::shared_ptr<ONNX_NAMESPACE::ModelProto>& model,
|
||||
std::unique_ptr<GraphCache>&& cache,
|
||||
const bool enable_mmap,
|
||||
ov::frontend::ExtensionHolder extensions = {});
|
||||
|
||||
void set_friendly_names(const Node& onnx_node, const OutputVector& ng_subgraph_outputs) const;
|
||||
@@ -77,6 +82,7 @@ protected:
|
||||
private:
|
||||
std::vector<Node> m_nodes;
|
||||
std::string m_model_dir;
|
||||
bool m_enable_mmap;
|
||||
};
|
||||
|
||||
/// \brief Representation of ONNX subgraph. It is used for example by ONNX Loop op.
|
||||
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
const auto& attributes = node_proto.attribute();
|
||||
m_attributes.reserve(attributes.size());
|
||||
for (const auto& attr_proto : attributes) {
|
||||
m_attributes.emplace_back(attr_proto, m_graph->model_dir());
|
||||
m_attributes.emplace_back(attr_proto, m_graph->model_dir(), m_graph->mmap_enabled());
|
||||
const auto& attribute = m_attributes.back();
|
||||
if (attribute.is_graph())
|
||||
m_subgraphs.insert({attribute.get_name(), std::make_shared<Subgraph>(attribute.get_subgraph(m_graph))});
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
m_output_names{std::begin(node_proto.output()), std::end(node_proto.output())},
|
||||
m_subgraphs(subgraphs) {
|
||||
for (const auto& attr_proto : node_proto.attribute()) {
|
||||
m_attributes.emplace_back(attr_proto, m_graph->model_dir());
|
||||
m_attributes.emplace_back(attr_proto, m_graph->model_dir(), m_graph->mmap_enabled());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,11 @@ namespace onnx_import {
|
||||
class SparseTensor {
|
||||
public:
|
||||
SparseTensor() = delete;
|
||||
explicit SparseTensor(const ONNX_NAMESPACE::SparseTensorProto& sparse_tensor, const std::string& model_dir)
|
||||
: m_values{sparse_tensor.values(), model_dir},
|
||||
m_indices{sparse_tensor.indices(), model_dir},
|
||||
SparseTensor(const ONNX_NAMESPACE::SparseTensorProto& sparse_tensor,
|
||||
const std::string& model_dir,
|
||||
const bool enable_mmap)
|
||||
: m_values{sparse_tensor.values(), model_dir, enable_mmap},
|
||||
m_indices{sparse_tensor.indices(), model_dir, enable_mmap},
|
||||
m_shape{std::begin(sparse_tensor.dims()), std::end(sparse_tensor.dims())} {
|
||||
if (m_shape == Shape{0}) {
|
||||
// It's possible to construct a sparse tensor in ONNX with "dims: 0" property
|
||||
|
||||
@@ -108,10 +108,11 @@ public:
|
||||
};
|
||||
|
||||
Tensor() = delete;
|
||||
explicit Tensor(const ONNX_NAMESPACE::TensorProto& tensor, const std::string& model_dir)
|
||||
explicit Tensor(const ONNX_NAMESPACE::TensorProto& tensor, const std::string& model_dir, const bool enable_mmap)
|
||||
: m_tensor_proto{&tensor},
|
||||
m_shape{std::begin(tensor.dims()), std::end(tensor.dims())},
|
||||
m_model_dir{model_dir} {
|
||||
m_model_dir{model_dir},
|
||||
m_enable_mmap{enable_mmap} {
|
||||
if (m_shape == Shape{0}) {
|
||||
// It's possible to construct a tensor in ONNX with "dims: 0" property
|
||||
// Such tensor contains a scalar. This results in a Shape{0} stored in m_shape.
|
||||
@@ -239,9 +240,16 @@ private:
|
||||
std::shared_ptr<default_opset::Constant> constant{nullptr};
|
||||
size_t data_size = get_data_size();
|
||||
if (has_external_data()) {
|
||||
auto external_data = load_external_data();
|
||||
constant = std::make_shared<ngraph::op::Constant>(type, m_shape, external_data.data());
|
||||
if (constant->get_byte_size() != external_data.size()) {
|
||||
const auto ext_data = detail::TensorExternalData(*m_tensor_proto);
|
||||
if (m_enable_mmap) {
|
||||
constant = std::make_shared<ngraph::op::Constant>(type,
|
||||
m_shape,
|
||||
ext_data.load_external_mmap_data(m_model_dir));
|
||||
} else {
|
||||
constant =
|
||||
std::make_shared<ngraph::op::Constant>(type, m_shape, ext_data.load_external_data(m_model_dir));
|
||||
}
|
||||
if (constant->get_byte_size() != ov::shape_size(m_shape) * type.size()) {
|
||||
throw error::invalid_external_data(
|
||||
"The size of the external data file does not match the byte size of an initializer '" + get_name() +
|
||||
"' in the model");
|
||||
@@ -288,14 +296,16 @@ private:
|
||||
ONNX_NAMESPACE::TensorProto_DataLocation::TensorProto_DataLocation_EXTERNAL;
|
||||
}
|
||||
|
||||
std::string load_external_data() const {
|
||||
const auto tensor_external_data = detail::TensorExternalData(*m_tensor_proto);
|
||||
return tensor_external_data.load_external_data(m_model_dir);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> get_external_data() const {
|
||||
return detail::__get_raw_data<T>(load_external_data(), m_tensor_proto->data_type());
|
||||
const auto ext_data = detail::TensorExternalData(*m_tensor_proto);
|
||||
std::shared_ptr<ngraph::runtime::AlignedBuffer> buffer = nullptr;
|
||||
if (m_enable_mmap) {
|
||||
buffer = ext_data.load_external_mmap_data(m_model_dir);
|
||||
} else {
|
||||
buffer = ext_data.load_external_data(m_model_dir);
|
||||
}
|
||||
return std::vector<T>(buffer->get_ptr<char>(), buffer->get_ptr<char>() + buffer->size());
|
||||
}
|
||||
|
||||
const void* get_data_ptr() const {
|
||||
@@ -339,6 +349,7 @@ private:
|
||||
const ONNX_NAMESPACE::TensorProto* m_tensor_proto;
|
||||
Shape m_shape;
|
||||
std::string m_model_dir;
|
||||
bool m_enable_mmap = true;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& outs, const Tensor& tensor) {
|
||||
|
||||
@@ -315,17 +315,23 @@ struct onnx_editor::ONNXModelEditor::Impl {
|
||||
#endif
|
||||
};
|
||||
|
||||
onnx_editor::ONNXModelEditor::ONNXModelEditor(const std::string& model_path, frontend::ExtensionHolder extensions)
|
||||
: m_extensions{std::move(extensions)},
|
||||
m_model_path{model_path},
|
||||
onnx_editor::ONNXModelEditor::ONNXModelEditor(const std::string& model_path,
|
||||
const bool enable_mmap,
|
||||
frontend::ExtensionHolder extensions)
|
||||
: m_model_path{model_path},
|
||||
m_enable_mmap{enable_mmap},
|
||||
m_extensions{std::move(extensions)},
|
||||
m_pimpl{new ONNXModelEditor::Impl{model_path}, [](Impl* impl) {
|
||||
delete impl;
|
||||
}} {}
|
||||
|
||||
#if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32)
|
||||
onnx_editor::ONNXModelEditor::ONNXModelEditor(const std::wstring& model_path, frontend::ExtensionHolder extensions)
|
||||
onnx_editor::ONNXModelEditor::ONNXModelEditor(const std::wstring& model_path,
|
||||
const bool enable_mmap,
|
||||
frontend::ExtensionHolder extensions)
|
||||
: m_extensions{std::move(extensions)},
|
||||
m_model_path{ov::util::wstring_to_string(model_path)},
|
||||
m_enable_mmap{enable_mmap},
|
||||
m_pimpl{new ONNXModelEditor::Impl{model_path}, [](Impl* impl) {
|
||||
delete impl;
|
||||
}} {}
|
||||
@@ -333,9 +339,11 @@ onnx_editor::ONNXModelEditor::ONNXModelEditor(const std::wstring& model_path, fr
|
||||
|
||||
onnx_editor::ONNXModelEditor::ONNXModelEditor(std::istream& model_stream,
|
||||
const std::string& model_path,
|
||||
const bool enable_mmap,
|
||||
frontend::ExtensionHolder extensions)
|
||||
: m_extensions{std::move(extensions)},
|
||||
m_model_path{model_path},
|
||||
: m_model_path{model_path},
|
||||
m_enable_mmap{enable_mmap},
|
||||
m_extensions{std::move(extensions)},
|
||||
m_pimpl{new ONNXModelEditor::Impl{model_stream}, [](Impl* impl) {
|
||||
delete impl;
|
||||
}} {}
|
||||
@@ -522,7 +530,10 @@ std::string onnx_editor::ONNXModelEditor::model_string() const {
|
||||
}
|
||||
|
||||
std::shared_ptr<Model> onnx_editor::ONNXModelEditor::get_function() const {
|
||||
return ngraph::onnx_import::detail::import_onnx_model(m_pimpl->m_model_proto, m_model_path, m_extensions);
|
||||
return ngraph::onnx_import::detail::import_onnx_model(m_pimpl->m_model_proto,
|
||||
m_model_path,
|
||||
m_enable_mmap,
|
||||
m_extensions);
|
||||
}
|
||||
|
||||
void onnx_editor::ONNXModelEditor::set_input_values(
|
||||
@@ -713,7 +724,10 @@ std::vector<std::string> onnx_editor::ONNXModelEditor::get_output_ports(const Ed
|
||||
}
|
||||
|
||||
std::shared_ptr<Model> onnx_editor::ONNXModelEditor::decode() {
|
||||
return ngraph::onnx_import::detail::decode_to_framework_nodes(m_pimpl->m_model_proto, m_model_path, m_extensions);
|
||||
return ngraph::onnx_import::detail::decode_to_framework_nodes(m_pimpl->m_model_proto,
|
||||
m_model_path,
|
||||
m_enable_mmap,
|
||||
m_extensions);
|
||||
}
|
||||
|
||||
void onnx_editor::ONNXModelEditor::add_output(const OutputEdge& output_edge) const {
|
||||
|
||||
@@ -31,9 +31,13 @@ public:
|
||||
/// is parsed and loaded into the m_model_proto member variable.
|
||||
///
|
||||
/// \param model_path Path to the file containing the model.
|
||||
ONNXModelEditor(const std::string& model_path, frontend::ExtensionHolder extensions = {});
|
||||
/// \param enable_mmap Enable mapping files with external weights instead of reading.
|
||||
/// \param extensions Holder for custom extensions (like custom ops).
|
||||
explicit ONNXModelEditor(const std::string& model_path,
|
||||
const bool enable_mmap = false,
|
||||
frontend::ExtensionHolder extensions = {});
|
||||
#if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32)
|
||||
ONNXModelEditor(const std::wstring& model_path, frontend::ExtensionHolder extensions = {});
|
||||
ONNXModelEditor(const std::wstring& model_path, const bool enable_mmap, frontend::ExtensionHolder extensions = {});
|
||||
#endif
|
||||
|
||||
/// \brief Creates an editor from a model stream. The stream is parsed and loaded
|
||||
@@ -42,9 +46,12 @@ public:
|
||||
/// \param model_stream The stream containing the model.
|
||||
/// \param model_path Path to the file containing the model. This information can be used
|
||||
/// for ONNX external weights feature support.
|
||||
ONNXModelEditor(std::istream& model_stream,
|
||||
const std::string& path = {},
|
||||
frontend::ExtensionHolder extensions = {});
|
||||
/// \param enable_mmap Enable mapping files with external weights instead of reading.
|
||||
/// \param extensions Holder for custom extensions (like custom ops).
|
||||
explicit ONNXModelEditor(std::istream& model_stream,
|
||||
const std::string& path = {},
|
||||
const bool enable_mmap = false,
|
||||
frontend::ExtensionHolder extensions = {});
|
||||
|
||||
/// \brief Modifies the in-memory representation of the model by setting
|
||||
/// custom input types for all inputs specified in the provided map.
|
||||
@@ -296,8 +303,9 @@ public:
|
||||
private:
|
||||
void update_mapper_if_needed() const;
|
||||
|
||||
frontend::ExtensionHolder m_extensions;
|
||||
const std::string m_model_path;
|
||||
const bool m_enable_mmap;
|
||||
frontend::ExtensionHolder m_extensions;
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl, void (*)(Impl*)> m_pimpl;
|
||||
|
||||
@@ -56,29 +56,32 @@ InputModel::Ptr FrontEnd::load_impl(const std::vector<ov::Any>& variants) const
|
||||
if (variants.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
// enable mmap by default
|
||||
const bool enable_mmap = variants[variants.size() - 1].is<bool>() ? variants[variants.size() - 1].as<bool>() : true;
|
||||
|
||||
if (variants[0].is<std::string>()) {
|
||||
const auto path = variants[0].as<std::string>();
|
||||
return std::make_shared<InputModel>(path, m_extensions);
|
||||
return std::make_shared<InputModel>(path, enable_mmap, m_extensions);
|
||||
}
|
||||
#if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32)
|
||||
if (variants[0].is<std::wstring>()) {
|
||||
const auto path = variants[0].as<std::wstring>();
|
||||
return std::make_shared<InputModel>(path, m_extensions);
|
||||
return std::make_shared<InputModel>(path, enable_mmap, m_extensions);
|
||||
}
|
||||
#endif
|
||||
if (variants[0].is<std::istream*>()) {
|
||||
const auto stream = variants[0].as<std::istream*>();
|
||||
if (variants.size() > 1 && variants[1].is<std::string>()) {
|
||||
const auto path = variants[1].as<std::string>();
|
||||
return std::make_shared<InputModel>(*stream, path, m_extensions);
|
||||
return std::make_shared<InputModel>(*stream, path, enable_mmap, m_extensions);
|
||||
}
|
||||
#if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32)
|
||||
if (variants.size() > 1 && variants[1].is<std::wstring>()) {
|
||||
const auto path = variants[1].as<std::wstring>();
|
||||
return std::make_shared<InputModel>(*stream, path, m_extensions);
|
||||
return std::make_shared<InputModel>(*stream, path, enable_mmap, m_extensions);
|
||||
}
|
||||
#endif
|
||||
return std::make_shared<InputModel>(*stream, m_extensions);
|
||||
return std::make_shared<InputModel>(*stream, enable_mmap, m_extensions);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -16,23 +16,30 @@ using namespace ov::frontend::onnx;
|
||||
|
||||
NGRAPH_SUPPRESS_DEPRECATED_START
|
||||
|
||||
InputModel::InputModel(const std::string& path, frontend::ExtensionHolder extensions)
|
||||
: m_editor{std::make_shared<onnx_editor::ONNXModelEditor>(path, std::move(extensions))} {}
|
||||
InputModel::InputModel(const std::string& path, const bool enable_mmap, frontend::ExtensionHolder extensions)
|
||||
: m_editor{std::make_shared<onnx_editor::ONNXModelEditor>(path, enable_mmap, std::move(extensions))} {}
|
||||
|
||||
#if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32)
|
||||
InputModel::InputModel(const std::wstring& path, frontend::ExtensionHolder extensions)
|
||||
: m_editor{std::make_shared<onnx_editor::ONNXModelEditor>(path, std::move(extensions))} {}
|
||||
InputModel::InputModel(const std::wstring& path, const bool enable_mmap, frontend::ExtensionHolder extensions)
|
||||
: m_editor{std::make_shared<onnx_editor::ONNXModelEditor>(path, enable_mmap, std::move(extensions))} {}
|
||||
#endif
|
||||
|
||||
InputModel::InputModel(std::istream& model_stream, frontend::ExtensionHolder extensions)
|
||||
: m_editor{std::make_shared<onnx_editor::ONNXModelEditor>(model_stream, "", std::move(extensions))} {}
|
||||
InputModel::InputModel(std::istream& model_stream, const bool enable_mmap, frontend::ExtensionHolder extensions)
|
||||
: m_editor{std::make_shared<onnx_editor::ONNXModelEditor>(model_stream, "", enable_mmap, std::move(extensions))} {}
|
||||
|
||||
InputModel::InputModel(std::istream& model_stream, const std::string& path, frontend::ExtensionHolder extensions)
|
||||
: m_editor{std::make_shared<onnx_editor::ONNXModelEditor>(model_stream, path, std::move(extensions))} {}
|
||||
InputModel::InputModel(std::istream& model_stream,
|
||||
const std::string& path,
|
||||
const bool enable_mmap,
|
||||
frontend::ExtensionHolder extensions)
|
||||
: m_editor{std::make_shared<onnx_editor::ONNXModelEditor>(model_stream, path, enable_mmap, std::move(extensions))} {
|
||||
}
|
||||
|
||||
#ifdef OPENVINO_ENABLE_UNICODE_PATH_SUPPORT
|
||||
InputModel::InputModel(std::istream& model_stream, const std::wstring& path, frontend::ExtensionHolder extensions)
|
||||
: InputModel(model_stream, ov::util::wstring_to_string(path), std::move(extensions)) {}
|
||||
InputModel::InputModel(std::istream& model_stream,
|
||||
const std::wstring& path,
|
||||
const bool enable_mmap,
|
||||
frontend::ExtensionHolder extensions)
|
||||
: InputModel(model_stream, ov::util::wstring_to_string(path), enable_mmap, std::move(extensions)) {}
|
||||
#endif
|
||||
|
||||
std::vector<ov::frontend::Place::Ptr> InputModel::get_inputs() const {
|
||||
|
||||
@@ -16,16 +16,22 @@ namespace onnx {
|
||||
|
||||
class InputModel : public ov::frontend::InputModel {
|
||||
public:
|
||||
InputModel(const std::string& path, ExtensionHolder extensions = {});
|
||||
InputModel(const std::string& path, const bool enable_mmap = false, ExtensionHolder extensions = {});
|
||||
#if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32)
|
||||
InputModel(const std::wstring& path, ExtensionHolder extensions = {});
|
||||
InputModel(const std::wstring& path, const bool enable_mmap = false, ExtensionHolder extensions = {});
|
||||
#endif
|
||||
InputModel(std::istream& model_stream, ExtensionHolder extensions = {});
|
||||
InputModel(std::istream& model_stream, const bool enable_mmap = false, ExtensionHolder extensions = {});
|
||||
// The path can be required even if the model is passed as a stream because it is necessary
|
||||
// for ONNX external data feature
|
||||
InputModel(std::istream& model_stream, const std::string& path, ExtensionHolder extensions = {});
|
||||
InputModel(std::istream& model_stream,
|
||||
const std::string& path,
|
||||
const bool enable_mmap = false,
|
||||
ExtensionHolder extensions = {});
|
||||
#ifdef OPENVINO_ENABLE_UNICODE_PATH_SUPPORT
|
||||
InputModel(std::istream& model_stream, const std::wstring& path, ExtensionHolder extensions = {});
|
||||
InputModel(std::istream& model_stream,
|
||||
const std::wstring& path,
|
||||
const bool enable_mmap = false,
|
||||
ExtensionHolder extensions = {});
|
||||
#endif
|
||||
|
||||
std::vector<ov::frontend::Place::Ptr> get_inputs() const override;
|
||||
|
||||
@@ -22,14 +22,16 @@ const auto legacy_conversion_extension = std::make_shared<ngraph::onnx_import::L
|
||||
|
||||
namespace ngraph {
|
||||
namespace onnx_import {
|
||||
std::shared_ptr<Function> import_onnx_model(std::istream& stream, const std::string& model_path) {
|
||||
std::shared_ptr<Function> import_onnx_model(std::istream& stream,
|
||||
const std::string& model_path,
|
||||
const bool enable_mmap) {
|
||||
const auto model_proto = std::make_shared<ONNX_NAMESPACE::ModelProto>(onnx_common::parse_from_istream(stream));
|
||||
ov::frontend::ExtensionHolder extensions;
|
||||
extensions.conversions.push_back(legacy_conversion_extension);
|
||||
return detail::import_onnx_model(model_proto, model_path, std::move(extensions));
|
||||
return detail::import_onnx_model(model_proto, model_path, enable_mmap, std::move(extensions));
|
||||
}
|
||||
|
||||
std::shared_ptr<Function> import_onnx_model(const std::string& file_path) {
|
||||
std::shared_ptr<Function> import_onnx_model(const std::string& file_path, const bool enable_mmap) {
|
||||
std::ifstream model_stream{file_path, std::ios::in | std::ios::binary};
|
||||
|
||||
if (!model_stream.is_open()) {
|
||||
@@ -37,7 +39,7 @@ std::shared_ptr<Function> import_onnx_model(const std::string& file_path) {
|
||||
". Could not open the file.");
|
||||
};
|
||||
|
||||
return import_onnx_model(model_stream, file_path);
|
||||
return import_onnx_model(model_stream, file_path, enable_mmap);
|
||||
}
|
||||
|
||||
std::set<std::string> get_supported_operators(std::int64_t version, const std::string& domain) {
|
||||
|
||||
@@ -89,11 +89,13 @@ void convert_decoded_function(std::shared_ptr<Function> function) {
|
||||
|
||||
std::shared_ptr<Function> import_onnx_model(std::shared_ptr<ONNX_NAMESPACE::ModelProto> model_proto,
|
||||
const std::string& model_path,
|
||||
const bool enable_mmap,
|
||||
ov::frontend::ExtensionHolder extensions) {
|
||||
apply_transformations(*model_proto);
|
||||
NGRAPH_SUPPRESS_DEPRECATED_START
|
||||
Graph graph{file_util::get_directory(ov::util::get_absolute_file_path(model_path)),
|
||||
model_proto,
|
||||
enable_mmap,
|
||||
std::move(extensions)};
|
||||
NGRAPH_SUPPRESS_DEPRECATED_END
|
||||
return graph.convert();
|
||||
@@ -101,11 +103,13 @@ std::shared_ptr<Function> import_onnx_model(std::shared_ptr<ONNX_NAMESPACE::Mode
|
||||
|
||||
std::shared_ptr<Function> decode_to_framework_nodes(std::shared_ptr<ONNX_NAMESPACE::ModelProto> model_proto,
|
||||
const std::string& model_path,
|
||||
const bool enable_mmap,
|
||||
ov::frontend::ExtensionHolder extensions) {
|
||||
apply_transformations(*model_proto);
|
||||
NGRAPH_SUPPRESS_DEPRECATED_START
|
||||
auto graph = std::make_shared<Graph>(file_util::get_directory(ov::util::get_absolute_file_path(model_path)),
|
||||
model_proto,
|
||||
enable_mmap,
|
||||
extensions);
|
||||
NGRAPH_SUPPRESS_DEPRECATED_END
|
||||
return graph->decode();
|
||||
|
||||
@@ -29,12 +29,13 @@ namespace detail {
|
||||
/// \param model_proto Reference to a GraphProto object.
|
||||
/// \param model_path The path to the imported onnx model.
|
||||
/// It is required if the imported model uses data saved in external files.
|
||||
/// \param enable_mmap Enable mapping files with external weights instead of reading.
|
||||
/// \param extensions An object containing a collection of frontend extensions to use during the import process
|
||||
///
|
||||
/// \return An nGraph function that represents a single output from the created
|
||||
/// graph.
|
||||
std::shared_ptr<Function> import_onnx_model(std::shared_ptr<ONNX_NAMESPACE::ModelProto> model_proto,
|
||||
const std::string& model_path,
|
||||
const bool enable_mmap,
|
||||
ov::frontend::ExtensionHolder extensions = {});
|
||||
|
||||
/// \brief Decode ONNX model to nGraph function with ONNXFrameworkNode(s)
|
||||
@@ -42,11 +43,12 @@ std::shared_ptr<Function> import_onnx_model(std::shared_ptr<ONNX_NAMESPACE::Mode
|
||||
/// \param model_proto Reference to a GraphProto object.
|
||||
/// \param model_path The path to the imported onnx model.
|
||||
/// It is required if the imported model uses data saved in external files.
|
||||
/// \param enable_mmap Enable mapping files with external weights instead of reading.
|
||||
/// \param extensions An object containing a collection of frontend extensions to use during the import process
|
||||
///
|
||||
/// \return A nGraph function with ONNXFrameworkNodes
|
||||
std::shared_ptr<Function> decode_to_framework_nodes(std::shared_ptr<ONNX_NAMESPACE::ModelProto> model_proto,
|
||||
const std::string& model_path,
|
||||
const bool enable_mmap,
|
||||
ov::frontend::ExtensionHolder extensions = {});
|
||||
|
||||
/// \brief Converts a nGraph function (onnx model decoded to function with ONNXFrameworkNode(s))
|
||||
|
||||
@@ -29,9 +29,29 @@ TensorExternalData::TensorExternalData(const ONNX_NAMESPACE::TensorProto& tensor
|
||||
m_sha1_digest = entry.value();
|
||||
}
|
||||
}
|
||||
if (m_sha1_digest.size() > 0) {
|
||||
OPENVINO_WARN << "SHA1 checksum is not supported";
|
||||
}
|
||||
}
|
||||
|
||||
std::string TensorExternalData::load_external_data(const std::string& model_dir) const {
|
||||
Buffer<ov::MappedMemory> TensorExternalData::load_external_mmap_data(const std::string& model_dir) const {
|
||||
NGRAPH_SUPPRESS_DEPRECATED_START
|
||||
auto full_path = file_util::path_join(model_dir, m_data_location);
|
||||
NGRAPH_SUPPRESS_DEPRECATED_END
|
||||
const int64_t file_size = ov::util::file_size(full_path);
|
||||
if (file_size <= 0 || m_offset + m_data_length > static_cast<uint64_t>(file_size)) {
|
||||
throw error::invalid_external_data{*this};
|
||||
}
|
||||
auto mapped_memory = ov::load_mmap_object(full_path, m_data_length, m_offset);
|
||||
if (m_data_length > mapped_memory->size() || mapped_memory->size() == 0) {
|
||||
throw error::invalid_external_data{*this};
|
||||
}
|
||||
return std::make_shared<ngraph::runtime::SharedBuffer<std::shared_ptr<ov::MappedMemory>>>(mapped_memory->data(),
|
||||
mapped_memory->size(),
|
||||
mapped_memory);
|
||||
}
|
||||
|
||||
Buffer<ngraph::runtime::AlignedBuffer> TensorExternalData::load_external_data(const std::string& model_dir) const {
|
||||
NGRAPH_SUPPRESS_DEPRECATED_START
|
||||
|
||||
auto full_path = file_util::path_join(model_dir, m_data_location);
|
||||
@@ -57,16 +77,16 @@ std::string TensorExternalData::load_external_data(const std::string& model_dir)
|
||||
// default value of m_offset is 0
|
||||
external_data_stream.seekg(m_offset, std::ios::beg);
|
||||
|
||||
if (m_sha1_digest.size() > 0) {
|
||||
OPENVINO_WARN << "SHA1 checksum is not supported";
|
||||
}
|
||||
|
||||
std::string read_data;
|
||||
read_data.resize(read_data_length);
|
||||
external_data_stream.read(&read_data[0], read_data_length);
|
||||
auto read_data = std::make_shared<ngraph::runtime::AlignedBuffer>(read_data_length);
|
||||
external_data_stream.read(read_data->get_ptr<char>(), read_data_length);
|
||||
external_data_stream.close();
|
||||
|
||||
return read_data;
|
||||
auto buffer = std::make_shared<ngraph::runtime::SharedBuffer<std::shared_ptr<ngraph::runtime::AlignedBuffer>>>(
|
||||
read_data->get_ptr<char>(),
|
||||
read_data->size(),
|
||||
read_data);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::string TensorExternalData::to_string() const {
|
||||
|
||||
@@ -6,9 +6,14 @@
|
||||
|
||||
#include <onnx/onnx_pb.h>
|
||||
|
||||
#include "ngraph/runtime/shared_buffer.hpp"
|
||||
#include "openvino/util/mmap_object.hpp"
|
||||
|
||||
namespace ngraph {
|
||||
namespace onnx_import {
|
||||
namespace detail {
|
||||
template <class T>
|
||||
using Buffer = std::shared_ptr<ngraph::runtime::SharedBuffer<std::shared_ptr<T>>>;
|
||||
/// \brief Helper class used to load tensor data from external files
|
||||
class TensorExternalData {
|
||||
public:
|
||||
@@ -20,8 +25,17 @@ public:
|
||||
/// \note If reading data from external files fails,
|
||||
/// the invalid_external_data exception is thrown.
|
||||
///
|
||||
/// \return External binary data loaded into a std::string
|
||||
std::string load_external_data(const std::string& model_dir) const;
|
||||
/// \return External binary data loaded into the SharedBuffer
|
||||
Buffer<ngraph::runtime::AlignedBuffer> load_external_data(const std::string& model_dir) const;
|
||||
|
||||
/// \brief Map (mmap for lin, MapViewOfFile for win) external data from tensor passed to constructor
|
||||
///
|
||||
/// \note If read data from external file fails,
|
||||
/// \note If reading data from external files fails,
|
||||
/// the invalid_external_data exception is thrown.
|
||||
///
|
||||
/// \return External binary data loaded into the SharedBuffer
|
||||
Buffer<ov::MappedMemory> load_external_mmap_data(const std::string& model_dir) const;
|
||||
|
||||
/// \brief Represets parameter of external data as string
|
||||
///
|
||||
|
||||
@@ -63,7 +63,6 @@ set(MULTI_TEST_SRC
|
||||
onnx_import_convpool.in.cpp
|
||||
onnx_import_deprecated.in.cpp
|
||||
onnx_import_dyn_shapes.in.cpp
|
||||
onnx_import_external_data.in.cpp
|
||||
onnx_import_org_openvino.in.cpp
|
||||
onnx_import_org_pytorch.in.cpp
|
||||
onnx_import_reshape.in.cpp
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "common_test_utils/file_utils.hpp"
|
||||
#include "default_opset.hpp"
|
||||
#include "engines_util/test_case.hpp"
|
||||
#include "engines_util/test_engines.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
#include "ngraph/file_util.hpp"
|
||||
#include "ngraph/type/element_type.hpp"
|
||||
#include "onnx_import/onnx.hpp"
|
||||
#include "util/test_control.hpp"
|
||||
#include "util/test_tools.hpp"
|
||||
#include "util/type_prop.hpp"
|
||||
|
||||
using namespace ngraph;
|
||||
using namespace ngraph::onnx_import;
|
||||
using namespace ngraph::test;
|
||||
|
||||
OPENVINO_SUPPRESS_DEPRECATED_START
|
||||
|
||||
static std::string s_manifest = "${MANIFEST}";
|
||||
static std::string s_device = test::backend_name_to_device("${BACKEND_NAME}");
|
||||
|
||||
NGRAPH_TEST(${BACKEND_NAME}, onnx_external_data) {
|
||||
const auto function = onnx_import::import_onnx_model(file_util::path_join(CommonTestUtils::getExecutableDirectory(),
|
||||
SERIALIZED_ZOO,
|
||||
"onnx/external_data/external_data.onnx"));
|
||||
|
||||
auto test_case = test::TestCase(function, s_device);
|
||||
test_case.add_input<float>({1.f, 2.f, 3.f, 4.f});
|
||||
test_case.add_expected_output<float>(Shape{2, 2}, {3.f, 6.f, 9.f, 12.f});
|
||||
|
||||
test_case.run();
|
||||
}
|
||||
|
||||
NGRAPH_TEST(${BACKEND_NAME}, onnx_external_data_from_stream) {
|
||||
std::string path = file_util::path_join(CommonTestUtils::getExecutableDirectory(),
|
||||
SERIALIZED_ZOO,
|
||||
"onnx/external_data/external_data.onnx");
|
||||
std::ifstream stream{path, std::ios::in | std::ios::binary};
|
||||
ASSERT_TRUE(stream.is_open());
|
||||
const auto function = onnx_import::import_onnx_model(stream, path);
|
||||
|
||||
auto test_case = test::TestCase(function, s_device);
|
||||
test_case.add_input<float>({1.f, 2.f, 3.f, 4.f});
|
||||
test_case.add_expected_output<float>(Shape{2, 2}, {3.f, 6.f, 9.f, 12.f});
|
||||
|
||||
test_case.run();
|
||||
|
||||
stream.close();
|
||||
}
|
||||
|
||||
NGRAPH_TEST(${BACKEND_NAME}, onnx_external_data_incorrect_size_exception) {
|
||||
try {
|
||||
auto function = onnx_import::import_onnx_model(
|
||||
file_util::path_join(CommonTestUtils::getExecutableDirectory(),
|
||||
SERIALIZED_ZOO,
|
||||
"onnx/external_data/external_data_incorrect_data_shape.onnx"));
|
||||
FAIL() << "Incorrect size of external data not detected";
|
||||
} catch (const ngraph_error& error) {
|
||||
EXPECT_PRED_FORMAT2(
|
||||
testing::IsSubstring,
|
||||
std::string(
|
||||
"The size of the external data file does not match the byte size of an initializer 'A' in the model"),
|
||||
error.what());
|
||||
} catch (...) {
|
||||
FAIL() << "Importing onnx model failed for unexpected reason";
|
||||
}
|
||||
}
|
||||
|
||||
NGRAPH_TEST(${BACKEND_NAME}, onnx_external_data_optional_fields) {
|
||||
const auto function =
|
||||
onnx_import::import_onnx_model(file_util::path_join(CommonTestUtils::getExecutableDirectory(),
|
||||
SERIALIZED_ZOO,
|
||||
"onnx/external_data/external_data_optional_fields.onnx"));
|
||||
|
||||
auto test_case = test::TestCase(function, s_device);
|
||||
test_case.add_input<float>({1.f, 2.f, 3.f, 4.f});
|
||||
test_case.add_expected_output<float>(Shape{2, 2}, {3.f, 6.f, 9.f, 12.f});
|
||||
|
||||
test_case.run();
|
||||
}
|
||||
|
||||
NGRAPH_TEST(${BACKEND_NAME}, onnx_external_data_in_different_paths) {
|
||||
auto function =
|
||||
onnx_import::import_onnx_model(file_util::path_join(CommonTestUtils::getExecutableDirectory(),
|
||||
SERIALIZED_ZOO,
|
||||
"onnx/external_data/external_data_different_paths.onnx"));
|
||||
|
||||
auto test_case = test::TestCase(function, s_device);
|
||||
// first input: {3.f}, second: {1.f, 2.f, 5.f} read from external files
|
||||
test_case.add_input<float>({2.f, 7.f, 7.f});
|
||||
|
||||
test_case.add_expected_output<float>({2.f, 4.f, 5.f});
|
||||
test_case.run();
|
||||
}
|
||||
|
||||
NGRAPH_TEST(${BACKEND_NAME}, onnx_external_two_tensors_data_in_the_same_file) {
|
||||
auto function = onnx_import::import_onnx_model(
|
||||
file_util::path_join(CommonTestUtils::getExecutableDirectory(),
|
||||
SERIALIZED_ZOO,
|
||||
"onnx/external_data/external_data_two_tensors_data_in_the_same_file.onnx"));
|
||||
|
||||
auto test_case = test::TestCase(function, s_device);
|
||||
// first input: {3, 2, 1}, second: {1, 2, 3} read from external file
|
||||
test_case.add_input<int32_t>({2, 3, 1});
|
||||
|
||||
test_case.add_expected_output<int32_t>({3, 3, 3});
|
||||
test_case.run();
|
||||
}
|
||||
|
||||
NGRAPH_TEST(${BACKEND_NAME}, onnx_external_invalid_external_data_exception) {
|
||||
try {
|
||||
auto function = onnx_import::import_onnx_model(
|
||||
file_util::path_join(CommonTestUtils::getExecutableDirectory(),
|
||||
SERIALIZED_ZOO,
|
||||
"onnx/external_data/external_data_file_not_found.onnx"));
|
||||
FAIL() << "Incorrect path to external data not detected";
|
||||
} catch (const ngraph_error& error) {
|
||||
EXPECT_PRED_FORMAT2(testing::IsSubstring,
|
||||
std::string("not_existed_file.data, offset: 4096, data_length: 16)"),
|
||||
error.what());
|
||||
} catch (...) {
|
||||
FAIL() << "Importing onnx model failed for unexpected reason";
|
||||
}
|
||||
}
|
||||
|
||||
NGRAPH_TEST(${BACKEND_NAME}, onnx_external_invalid_up_dir_path) {
|
||||
try {
|
||||
auto function = onnx_import::import_onnx_model(
|
||||
file_util::path_join(CommonTestUtils::getExecutableDirectory(),
|
||||
SERIALIZED_ZOO,
|
||||
"onnx/external_data/inner_scope/external_data_file_in_up_dir.onnx"));
|
||||
FAIL() << "Incorrect path to external data not detected";
|
||||
} catch (const ngraph_error& error) {
|
||||
EXPECT_PRED_FORMAT2(testing::IsSubstring,
|
||||
std::string("tensor.data, offset: 4096, "
|
||||
"data_length: 16)"),
|
||||
error.what());
|
||||
} catch (...) {
|
||||
FAIL() << "Importing onnx model failed for unexpected reason";
|
||||
}
|
||||
}
|
||||
|
||||
NGRAPH_TEST(${BACKEND_NAME}, onnx_external_invalid_data_length) {
|
||||
try {
|
||||
auto function = onnx_import::import_onnx_model(
|
||||
file_util::path_join(CommonTestUtils::getExecutableDirectory(),
|
||||
SERIALIZED_ZOO,
|
||||
"onnx/external_data/external_data_invalid_data_length.onnx"));
|
||||
FAIL() << "Incorrect path to external data not detected";
|
||||
} catch (const ngraph_error& error) {
|
||||
EXPECT_PRED_FORMAT2(testing::IsSubstring,
|
||||
std::string("tensor.data, offset: 0, "
|
||||
"data_length: 30000000000)"),
|
||||
error.what());
|
||||
} catch (...) {
|
||||
FAIL() << "Importing onnx model failed for unexpected reason";
|
||||
}
|
||||
}
|
||||
|
||||
NGRAPH_TEST(${BACKEND_NAME}, onnx_external_data_sanitize_path) {
|
||||
const auto function =
|
||||
onnx_import::import_onnx_model(file_util::path_join(CommonTestUtils::getExecutableDirectory(),
|
||||
SERIALIZED_ZOO,
|
||||
"onnx/external_data/external_data_sanitize_test.onnx"));
|
||||
|
||||
auto test_case = test::TestCase(function, s_device);
|
||||
test_case.add_input<float>({1.f, 2.f, 3.f, 4.f});
|
||||
test_case.add_expected_output<float>(Shape{2, 2}, {3.f, 6.f, 9.f, 12.f});
|
||||
|
||||
test_case.run();
|
||||
}
|
||||
|
||||
NGRAPH_TEST(${BACKEND_NAME}, onnx_external_data_in_constant_node) {
|
||||
const auto function =
|
||||
onnx_import::import_onnx_model(file_util::path_join(CommonTestUtils::getExecutableDirectory(),
|
||||
SERIALIZED_ZOO,
|
||||
"onnx/external_data/external_data_in_constant_node.onnx"));
|
||||
|
||||
auto test_case = test::TestCase(function, s_device);
|
||||
test_case.add_input<float>({3.f, 5.f, 8.f, 13.f});
|
||||
test_case.add_expected_output<float>(Shape{2, 2}, {4.f, 7.f, 11.f, 17.f});
|
||||
|
||||
test_case.run();
|
||||
}
|
||||
@@ -4,19 +4,23 @@
|
||||
|
||||
#include <file_utils.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <ie_blob.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <ie_core.hpp>
|
||||
#include <ngraph/ngraph.hpp>
|
||||
#include <set>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
|
||||
#include "common_test_utils/file_utils.hpp"
|
||||
#include "common_test_utils/unicode_utils.hpp"
|
||||
#include "engines_util/test_case.hpp"
|
||||
#include "ie_blob.h"
|
||||
#include "ie_core.hpp"
|
||||
#include "ngraph/ngraph.hpp"
|
||||
#include "openvino/frontend/manager.hpp"
|
||||
#include "openvino/openvino.hpp"
|
||||
|
||||
// API 1.0 tests
|
||||
TEST(ONNX_Reader_Tests, ImportModelWithExternalDataFromFile) {
|
||||
InferenceEngine::Core ie;
|
||||
auto cnnNetwork = ie.ReadNetwork(
|
||||
@@ -114,3 +118,183 @@ TEST(ONNX_Reader_Tests, ImportModelWithExternalDataFromWstringNamedFile) {
|
||||
ASSERT_TRUE(external_data_node_const->get_vector<float>() == (std::vector<float>{1, 2, 3, 4}));
|
||||
}
|
||||
#endif
|
||||
|
||||
// API 2.0 tests
|
||||
|
||||
class OnnxFeMmapFixture : public ::testing::TestWithParam<bool> {};
|
||||
|
||||
TEST_P(OnnxFeMmapFixture, onnx_external_data) {
|
||||
const auto path =
|
||||
CommonTestUtils::getModelFromTestModelZoo(std::string(ONNX_TEST_MODELS) + "external_data/external_data.onnx");
|
||||
ov::Core core;
|
||||
core.set_property(ov::enable_mmap(GetParam()));
|
||||
const auto model = core.read_model(path);
|
||||
auto test_case = ngraph::test::TestCase(model);
|
||||
test_case.add_input<float>({1.f, 2.f, 3.f, 4.f});
|
||||
test_case.add_expected_output<float>({2, 2}, {3.f, 6.f, 9.f, 12.f});
|
||||
|
||||
test_case.run();
|
||||
}
|
||||
|
||||
TEST_P(OnnxFeMmapFixture, onnx_external_data_from_stream) {
|
||||
const auto path =
|
||||
CommonTestUtils::getModelFromTestModelZoo(std::string(ONNX_TEST_MODELS) + "external_data/external_data.onnx");
|
||||
std::ifstream stream{path, std::ios::in | std::ios::binary};
|
||||
std::istream* is = &stream;
|
||||
ASSERT_TRUE(stream.is_open());
|
||||
|
||||
auto fem = ov::frontend::FrontEndManager();
|
||||
auto frontend = fem.load_by_framework("onnx");
|
||||
const bool enable_mmap = GetParam();
|
||||
const auto in_model = frontend->load(is, path, enable_mmap);
|
||||
const auto model = frontend->convert(in_model);
|
||||
|
||||
auto test_case = ngraph::test::TestCase(model);
|
||||
test_case.add_input<float>({1.f, 2.f, 3.f, 4.f});
|
||||
test_case.add_expected_output<float>(ov::Shape{2, 2}, {3.f, 6.f, 9.f, 12.f});
|
||||
|
||||
test_case.run();
|
||||
|
||||
stream.close();
|
||||
}
|
||||
|
||||
TEST_P(OnnxFeMmapFixture, onnx_external_data_incorrect_size_exception) {
|
||||
try {
|
||||
const auto path = CommonTestUtils::getModelFromTestModelZoo(
|
||||
std::string(ONNX_TEST_MODELS) + "external_data/external_data_incorrect_data_shape.onnx");
|
||||
ov::Core core;
|
||||
core.set_property(ov::enable_mmap(GetParam()));
|
||||
const auto model = core.read_model(path);
|
||||
FAIL() << "Incorrect size of external data not detected";
|
||||
} catch (const ov::Exception& ex) {
|
||||
EXPECT_PRED_FORMAT2(
|
||||
testing::IsSubstring,
|
||||
std::string(
|
||||
"The size of the external data file does not match the byte size of an initializer 'A' in the model"),
|
||||
ex.what());
|
||||
} catch (...) {
|
||||
FAIL() << "Importing onnx model failed for unexpected reason";
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(OnnxFeMmapFixture, onnx_external_data_optional_fields) {
|
||||
const auto path = CommonTestUtils::getModelFromTestModelZoo(std::string(ONNX_TEST_MODELS) +
|
||||
"external_data/external_data_optional_fields.onnx");
|
||||
ov::Core core;
|
||||
core.set_property(ov::enable_mmap(GetParam()));
|
||||
const auto model = core.read_model(path);
|
||||
auto test_case = ngraph::test::TestCase(model);
|
||||
test_case.add_input<float>({1.f, 2.f, 3.f, 4.f});
|
||||
test_case.add_expected_output<float>(ov::Shape{2, 2}, {3.f, 6.f, 9.f, 12.f});
|
||||
|
||||
test_case.run();
|
||||
}
|
||||
|
||||
TEST_P(OnnxFeMmapFixture, onnx_external_data_in_different_paths) {
|
||||
const auto path = CommonTestUtils::getModelFromTestModelZoo(std::string(ONNX_TEST_MODELS) +
|
||||
"external_data/external_data_different_paths.onnx");
|
||||
ov::Core core;
|
||||
core.set_property(ov::enable_mmap(GetParam()));
|
||||
const auto model = core.read_model(path);
|
||||
auto test_case = ngraph::test::TestCase(model);
|
||||
// first input: {3.f}, second: {1.f, 2.f, 5.f} read from external files
|
||||
test_case.add_input<float>({2.f, 7.f, 7.f});
|
||||
|
||||
test_case.add_expected_output<float>({2.f, 4.f, 5.f});
|
||||
test_case.run();
|
||||
}
|
||||
|
||||
TEST_P(OnnxFeMmapFixture, onnx_external_two_tensors_data_in_the_same_file) {
|
||||
const auto path = CommonTestUtils::getModelFromTestModelZoo(
|
||||
std::string(ONNX_TEST_MODELS) + "external_data/external_data_two_tensors_data_in_the_same_file.onnx");
|
||||
ov::Core core;
|
||||
core.set_property(ov::enable_mmap(GetParam()));
|
||||
const auto model = core.read_model(path);
|
||||
auto test_case = ngraph::test::TestCase(model);
|
||||
// first input: {3, 2, 1}, second: {1, 2, 3} read from external file
|
||||
test_case.add_input<int32_t>({2, 3, 1});
|
||||
|
||||
test_case.add_expected_output<int32_t>({3, 3, 3});
|
||||
test_case.run();
|
||||
}
|
||||
|
||||
TEST_P(OnnxFeMmapFixture, onnx_external_invalid_external_data_exception) {
|
||||
try {
|
||||
const auto path = CommonTestUtils::getModelFromTestModelZoo(std::string(ONNX_TEST_MODELS) +
|
||||
"external_data/external_data_file_not_found.onnx");
|
||||
ov::Core core;
|
||||
core.set_property(ov::enable_mmap(GetParam()));
|
||||
core.read_model(path);
|
||||
FAIL() << "Incorrect path to external data not detected";
|
||||
} catch (const ov::Exception& ex) {
|
||||
EXPECT_PRED_FORMAT2(testing::IsSubstring,
|
||||
std::string("not_existed_file.data, offset: 4096, data_length: 16)"),
|
||||
ex.what());
|
||||
} catch (...) {
|
||||
FAIL() << "Importing onnx model failed for unexpected reason";
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(OnnxFeMmapFixture, onnx_external_invalid_up_dir_path) {
|
||||
try {
|
||||
const auto path = CommonTestUtils::getModelFromTestModelZoo(
|
||||
std::string(ONNX_TEST_MODELS) + "external_data/inner_scope/external_data_file_in_up_dir.onnx");
|
||||
ov::Core core;
|
||||
core.set_property(ov::enable_mmap(GetParam()));
|
||||
core.read_model(path);
|
||||
FAIL() << "Incorrect path to external data not detected";
|
||||
} catch (const ov::Exception& ex) {
|
||||
EXPECT_PRED_FORMAT2(testing::IsSubstring,
|
||||
std::string("tensor.data, offset: 4096, "
|
||||
"data_length: 16)"),
|
||||
ex.what());
|
||||
} catch (...) {
|
||||
FAIL() << "Importing onnx model failed for unexpected reason";
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(OnnxFeMmapFixture, onnx_external_invalid_data_length) {
|
||||
try {
|
||||
const auto path = CommonTestUtils::getModelFromTestModelZoo(
|
||||
std::string(ONNX_TEST_MODELS) + "external_data/external_data_invalid_data_length.onnx");
|
||||
ov::Core core;
|
||||
core.set_property(ov::enable_mmap(GetParam()));
|
||||
core.read_model(path);
|
||||
FAIL() << "Incorrect path to external data not detected";
|
||||
} catch (const ov::Exception& ex) {
|
||||
EXPECT_PRED_FORMAT2(testing::IsSubstring,
|
||||
std::string("tensor.data, offset: 0, "
|
||||
"data_length: 30000000000)"),
|
||||
ex.what());
|
||||
} catch (...) {
|
||||
FAIL() << "Importing onnx model failed for unexpected reason";
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(OnnxFeMmapFixture, onnx_external_data_sanitize_path) {
|
||||
const auto path = CommonTestUtils::getModelFromTestModelZoo(std::string(ONNX_TEST_MODELS) +
|
||||
"external_data/external_data_sanitize_test.onnx");
|
||||
ov::Core core;
|
||||
core.set_property(ov::enable_mmap(GetParam()));
|
||||
const auto model = core.read_model(path);
|
||||
auto test_case = ngraph::test::TestCase(model);
|
||||
test_case.add_input<float>({1.f, 2.f, 3.f, 4.f});
|
||||
test_case.add_expected_output<float>(ov::Shape{2, 2}, {3.f, 6.f, 9.f, 12.f});
|
||||
|
||||
test_case.run();
|
||||
}
|
||||
|
||||
TEST_P(OnnxFeMmapFixture, onnx_external_data_in_constant_node) {
|
||||
const auto path = CommonTestUtils::getModelFromTestModelZoo(std::string(ONNX_TEST_MODELS) +
|
||||
"external_data/external_data_in_constant_node.onnx");
|
||||
ov::Core core;
|
||||
core.set_property(ov::enable_mmap(GetParam()));
|
||||
const auto model = core.read_model(path);
|
||||
auto test_case = ngraph::test::TestCase(model);
|
||||
test_case.add_input<float>({3.f, 5.f, 8.f, 13.f});
|
||||
test_case.add_expected_output<float>(ov::Shape{2, 2}, {4.f, 7.f, 11.f, 17.f});
|
||||
|
||||
test_case.run();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(OnnxFeMMapReadModel, OnnxFeMmapFixture, ::testing::Bool());
|
||||
@@ -40,6 +40,7 @@ def convert_model(
|
||||
version: bool = None,
|
||||
progress: bool = False,
|
||||
stream_output: bool = False,
|
||||
enable_mmap: bool = False,
|
||||
|
||||
# PaddlePaddle-specific parameters:
|
||||
example_output: Any = None,
|
||||
@@ -268,6 +269,10 @@ def convert_model(
|
||||
Enable model conversion progress display.
|
||||
:param stream_output:
|
||||
Switch model conversion progress display to a multiline mode.
|
||||
:param enable_mmap:
|
||||
Force reading weights instead of mapping weights files into memory.
|
||||
Currently, mmap feature is provided only for ONNX models
|
||||
that do not require fallback to the legacy ONNX frontend for the conversion.
|
||||
|
||||
PaddlePaddle-specific parameters:
|
||||
:param example_output:
|
||||
|
||||
@@ -444,7 +444,9 @@ def read_model(fem: FrontEndManager, path_to_xml: str):
|
||||
# avoid segfault during object destruction. So fe must
|
||||
# be destructed before fem object explicitly.
|
||||
fe = fem.load_by_framework(framework="ir")
|
||||
function = fe.convert(fe.load(path_to_xml))
|
||||
# *.xml/.*bin files are temporary created in the legacy scenario, so we cannot map the memory
|
||||
enable_mmap = False
|
||||
function = fe.convert(fe.load(path_to_xml, enable_mmap))
|
||||
return function
|
||||
|
||||
|
||||
|
||||
@@ -2040,7 +2040,7 @@ class TestConvertModelParamsParsing(unittest.TestCase):
|
||||
'log_level', 'input', 'output', 'mean_values', 'scale_values', 'source_layout',
|
||||
'target_layout', 'layout', 'compress_to_fp16', 'transform', 'extensions',
|
||||
'batch', 'silent', 'version', 'progress', 'stream_output',
|
||||
'transformations_config', 'example_input'},
|
||||
'transformations_config', 'example_input', 'enable_mmap'},
|
||||
'Caffe*-specific parameters:': {'input_proto', 'caffe_parser_path', 'k', 'disable_omitting_optional',
|
||||
'enable_flattening_nested_params'},
|
||||
'TensorFlow*-specific parameters:': {'input_model_is_text', 'input_checkpoint', 'input_meta_graph',
|
||||
|
||||
@@ -45,6 +45,7 @@ def convert_model(
|
||||
version: bool = None,
|
||||
progress: bool = False,
|
||||
stream_output: bool = False,
|
||||
enable_mmap: bool = True,
|
||||
|
||||
# PaddlePaddle-specific parameters:
|
||||
example_output: Any = None,
|
||||
@@ -273,6 +274,10 @@ def convert_model(
|
||||
Enable model conversion progress display.
|
||||
:param stream_output:
|
||||
Switch model conversion progress display to a multiline mode.
|
||||
:param enable_mmap:
|
||||
Force reading weights instead of mapping weights files into memory.
|
||||
Currently, mmap feature is provided only for ONNX models
|
||||
that do not require fallback to the legacy ONNX frontend for the conversion.
|
||||
|
||||
PaddlePaddle-specific parameters:
|
||||
:param example_output:
|
||||
|
||||
@@ -46,18 +46,19 @@ def moc_pipeline(argv: argparse.Namespace, moc_front_end: FrontEnd):
|
||||
:return: converted nGraph function ready for serialization
|
||||
"""
|
||||
input_checkpoint = getattr(argv, 'input_checkpoint', None)
|
||||
enable_mmap = getattr(argv, 'enable_mmap', True)
|
||||
if argv.input_model and input_checkpoint:
|
||||
# frozen format with v1 checkpoints
|
||||
input_model = moc_front_end.load([argv.input_model, argv.input_checkpoint])
|
||||
input_model = moc_front_end.load([argv.input_model, argv.input_checkpoint], enable_mmap)
|
||||
elif argv.input_model:
|
||||
input_model = moc_front_end.load(argv.input_model)
|
||||
input_model = moc_front_end.load(argv.input_model, enable_mmap)
|
||||
elif argv.saved_model_dir:
|
||||
if argv.saved_model_tags:
|
||||
input_model = moc_front_end.load([argv.saved_model_dir, argv.saved_model_tags])
|
||||
input_model = moc_front_end.load([argv.saved_model_dir, argv.saved_model_tags], enable_mmap)
|
||||
else:
|
||||
input_model = moc_front_end.load(argv.saved_model_dir)
|
||||
input_model = moc_front_end.load(argv.saved_model_dir, enable_mmap)
|
||||
elif argv.input_meta_graph:
|
||||
input_model = moc_front_end.load(argv.input_meta_graph)
|
||||
input_model = moc_front_end.load(argv.input_meta_graph, enable_mmap)
|
||||
if argv.output:
|
||||
# Simulate original behavior with freezing model
|
||||
# While freezing we do a cutting of model, to keep similar behavior we
|
||||
|
||||
@@ -2073,7 +2073,7 @@ class TestConvertModelParamsParsing(unittest.TestCase):
|
||||
'log_level', 'input', 'output', 'mean_values', 'scale_values', 'source_layout',
|
||||
'target_layout', 'layout', 'compress_to_fp16', 'transform', 'extensions',
|
||||
'batch', 'silent', 'version', 'progress', 'stream_output',
|
||||
'transformations_config', 'example_input'},
|
||||
'transformations_config', 'example_input', 'enable_mmap'},
|
||||
'Caffe*-specific parameters:': {'input_proto', 'caffe_parser_path', 'k', 'disable_omitting_optional',
|
||||
'enable_flattening_nested_params'},
|
||||
'TensorFlow*-specific parameters:': {'input_model_is_text', 'input_checkpoint', 'input_meta_graph',
|
||||
|
||||
Reference in new issue
Block a user