Simplify UnpackInitializerData API (#8736)

* Move UnpackInitializerData to use vector

* minor update

* minor update

* Update getclipminmax

* Change uint8_t -> std::byte

* fix build break

* Revert "fix build break"

This reverts commit 1ffa284ac54fd605c0651954ea4fb2cab0464526.

* Revert "Change uint8_t -> std::byte"

This reverts commit 764a656ebac6610cdf1f25e63770330c3aedece6.

* Add todo notes for extra vector alignment

* add check result size
This commit is contained in:
Guoyu Wang 2021-08-17 18:11:46 -07:00 committed by GitHub
parent 60089f7093
commit 3406b7b528
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 127 additions and 115 deletions

View file

@ -155,10 +155,10 @@ static Status GetExternalDataInfo(const ONNX_NAMESPACE::TensorProto& tensor_prot
// This function does not unpack string_data of an initializer tensor
static Status ReadExternalDataForTensor(const ONNX_NAMESPACE::TensorProto& tensor_proto,
const ORTCHAR_T* tensor_proto_dir,
std::unique_ptr<unsigned char[]>& unpacked_tensor,
SafeInt<size_t>& tensor_byte_size) {
std::vector<uint8_t>& unpacked_tensor) {
std::basic_string<ORTCHAR_T> external_file_path;
onnxruntime::FileOffsetType file_offset;
SafeInt<size_t> tensor_byte_size;
ORT_RETURN_IF_ERROR(GetExternalDataInfo(
tensor_proto,
tensor_proto_dir,
@ -166,12 +166,12 @@ static Status ReadExternalDataForTensor(const ONNX_NAMESPACE::TensorProto& tenso
file_offset,
tensor_byte_size));
unpacked_tensor.reset(new unsigned char[*&tensor_byte_size]);
unpacked_tensor.resize(tensor_byte_size);
ORT_RETURN_IF_ERROR(onnxruntime::Env::Default().ReadFileIntoBuffer(
external_file_path.c_str(),
file_offset,
tensor_byte_size,
gsl::make_span(reinterpret_cast<char*>(unpacked_tensor.get()), tensor_byte_size)));
gsl::make_span(reinterpret_cast<char*>(unpacked_tensor.data()), tensor_byte_size)));
return Status::OK();
}
@ -185,13 +185,11 @@ static Status UnpackTensorWithExternalDataImpl(const ONNX_NAMESPACE::TensorProto
size_t expected_num_elements, size_t element_size,
/*out*/ unsigned char* p_data) {
ORT_RETURN_IF(nullptr == p_data, "nullptr == p_data");
std::unique_ptr<unsigned char[]> unpacked_tensor;
SafeInt<size_t> tensor_byte_size = 0;
ORT_RETURN_IF_ERROR(ReadExternalDataForTensor(tensor, tensor_proto_dir, unpacked_tensor, tensor_byte_size));
std::vector<uint8_t> unpacked_tensor;
ORT_RETURN_IF_ERROR(ReadExternalDataForTensor(tensor, tensor_proto_dir, unpacked_tensor));
// ReadLittleEndian checks src and dst buffers are the same size
auto src_span = gsl::make_span(unpacked_tensor.get(), tensor_byte_size);
auto src_span = gsl::make_span(unpacked_tensor.data(), unpacked_tensor.size());
auto dst_span = gsl::make_span(p_data, expected_num_elements * element_size);
return onnxruntime::utils::ReadLittleEndian(element_size, src_span, dst_span);
@ -590,12 +588,12 @@ static Status GetFileContent(
break;
/**
* @brief Convert tensor_proto to tensor format and store it to pre-allocated tensor
* @param env
* @param model_path
* @brief Convert tensor_proto to tensor format and store it to pre-allocated tensor
* @param env
* @param model_path
* @param tensor_proto tensor data in protobuf format
* @param tensorp pre-allocated tensor object, where we store the data
* @return
* @return
*/
Status TensorProtoToTensor(const Env& env, const ORTCHAR_T* model_path,
const ONNX_NAMESPACE::TensorProto& tensor_proto,
@ -763,11 +761,10 @@ ONNXTensorElementDataType GetTensorElementType(const ONNX_NAMESPACE::TensorProto
ONNX_NAMESPACE::TensorProto TensorToTensorProto(const Tensor& tensor, const std::string& tensor_proto_name) {
// Given we are using the raw_data field in the protobuf, this will work only for little-endian format.
ORT_IF_CONSTEXPR (endian::native != endian::little) {
ORT_IF_CONSTEXPR(endian::native != endian::little) {
ORT_THROW("Big endian not supported");
}
// Set name, dimensions, type, and data of the TensorProto.
ONNX_NAMESPACE::TensorProto tensor_proto;
@ -951,10 +948,9 @@ common::Status SparseTensorProtoToDenseTensorProto(const ONNX_NAMESPACE::SparseT
if (type != TensorProto_DataType_STRING) {
// need to read in sparse data first as it could be in a type specific field, in raw data, or in external data
size_t sparse_bytes = 0;
std::unique_ptr<uint8_t[]> sparse_data_storage;
ORT_RETURN_IF_ERROR(UnpackInitializerData(sparse_values, model_path, sparse_data_storage, sparse_bytes));
void* sparse_data = sparse_data_storage.get();
std::vector<uint8_t> sparse_data_storage;
ORT_RETURN_IF_ERROR(UnpackInitializerData(sparse_values, model_path, sparse_data_storage));
void* sparse_data = sparse_data_storage.data();
size_t element_size = 0;
// We want to this list to match the one used below in DenseTensorToSparseTensorProto()
MLTypeCallDispatcherFromTypeList<conversion_internal::SupportedConversionTypeList> type_disp(type);
@ -1019,7 +1015,7 @@ common::Status SparseTensorProtoToDenseTensorProto(const ONNX_NAMESPACE::SparseT
return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL,
" BUG! Report to onnxruntime team. element_size of: ",
element_size, " is not supported.", " type: ", type);
}
}
ORT_RETURN_IF_ERROR(status);
}
@ -1106,33 +1102,33 @@ common::Status DenseTensorToSparseTensorProto(const ONNX_NAMESPACE::TensorProto&
n_dense_elements *= dim;
}
size_t tensor_bytes_size = 0;
std::unique_ptr<uint8_t[]> dense_raw_data;
ORT_RETURN_IF_ERROR(UnpackInitializerData(dense_proto, model_path, dense_raw_data, tensor_bytes_size));
std::vector<uint8_t> dense_raw_data;
ORT_RETURN_IF_ERROR(UnpackInitializerData(dense_proto, model_path, dense_raw_data));
size_t element_size = 0;
// We want this type list to match the one above in SparseTensorProtoToDenseTensorProto
MLTypeCallDispatcherFromTypeList<conversion_internal::SupportedConversionTypeList> type_disp(data_type);
ORT_RETURN_IF_ERROR(
(type_disp.InvokeRetWithUnsupportedPolicy<Status, conversion_internal::GetElementSize, conversion_internal::UnsupportedSparseDataType>(element_size)));
void* dense_data = dense_raw_data.data();
switch (element_size) {
case 1: {
SparsifyGeneric(dense_raw_data.get(), n_dense_elements, element_size,
SparsifyGeneric(dense_data, n_dense_elements, element_size,
IsZero<uint8_t>, CopyElement<uint8_t>, values, indices);
break;
}
case 2: {
SparsifyGeneric(dense_raw_data.get(), n_dense_elements, element_size,
SparsifyGeneric(dense_data, n_dense_elements, element_size,
IsZero<uint16_t>, CopyElement<uint16_t>, values, indices);
break;
}
case 4: {
SparsifyGeneric(dense_raw_data.get(), n_dense_elements, element_size,
SparsifyGeneric(dense_data, n_dense_elements, element_size,
IsZero<uint32_t>, CopyElement<uint32_t>, values, indices);
break;
}
case 8: {
SparsifyGeneric(dense_raw_data.get(), n_dense_elements, element_size,
SparsifyGeneric(dense_data, n_dense_elements, element_size,
IsZero<uint64_t>, CopyElement<uint64_t>, values, indices);
break;
}
@ -1159,39 +1155,37 @@ template common::Status GetSizeInBytesFromTensorProto<kAllocAlignment>(const ONN
size_t* out);
template common::Status GetSizeInBytesFromTensorProto<0>(const ONNX_NAMESPACE::TensorProto& tensor_proto, size_t* out);
#define CASE_UNPACK(TYPE, ELEMENT_TYPE, DATA_SIZE) \
case ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_##TYPE: { \
size_t element_count = 0; \
if (initializer.has_raw_data()) { \
tensor_byte_size = initializer.raw_data().size(); \
element_count = tensor_byte_size / sizeof(ELEMENT_TYPE); \
} else { \
element_count = initializer.DATA_SIZE(); \
tensor_byte_size = element_count * sizeof(ELEMENT_TYPE); \
} \
tensor_byte_size_out = tensor_byte_size; \
unpacked_tensor.reset(new unsigned char[tensor_byte_size_out]); \
return onnxruntime::utils::UnpackTensor( \
initializer, \
initializer.has_raw_data() ? initializer.raw_data().data() : nullptr, \
initializer.has_raw_data() ? initializer.raw_data().size() : 0, \
reinterpret_cast<ELEMENT_TYPE*>(unpacked_tensor.get()), element_count); \
break; \
#define CASE_UNPACK(TYPE, ELEMENT_TYPE, DATA_SIZE) \
case ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_##TYPE: { \
SafeInt<size_t> tensor_byte_size; \
size_t element_count = 0; \
if (initializer.has_raw_data()) { \
tensor_byte_size = initializer.raw_data().size(); \
element_count = tensor_byte_size / sizeof(ELEMENT_TYPE); \
} else { \
element_count = initializer.DATA_SIZE(); \
tensor_byte_size = element_count * sizeof(ELEMENT_TYPE); \
} \
unpacked_tensor.resize(tensor_byte_size); \
return onnxruntime::utils::UnpackTensor( \
initializer, \
initializer.has_raw_data() ? initializer.raw_data().data() : nullptr, \
initializer.has_raw_data() ? initializer.raw_data().size() : 0, \
reinterpret_cast<ELEMENT_TYPE*>(unpacked_tensor.data()), element_count); \
break; \
}
Status UnpackInitializerData(const onnx::TensorProto& initializer,
const Path& model_path,
std::unique_ptr<unsigned char[]>& unpacked_tensor,
size_t& tensor_byte_size_out) {
SafeInt<size_t> tensor_byte_size;
std::vector<uint8_t>& unpacked_tensor) {
// TODO, if std::vector does not use a custom allocator, the default std::allocator will
// allocation the memory aligned to std::max_align_t, need look into allocating
// forced aligned memory (align as 16 or larger)for unpacked_tensor
if (initializer.data_location() == TensorProto_DataLocation_EXTERNAL) {
ORT_RETURN_IF_ERROR(ReadExternalDataForTensor(
initializer,
model_path.IsEmpty() ? nullptr : model_path.ParentPath().ToPathString().c_str(),
unpacked_tensor,
tensor_byte_size));
tensor_byte_size_out = tensor_byte_size;
unpacked_tensor));
return Status::OK();
}
@ -1217,5 +1211,12 @@ Status UnpackInitializerData(const onnx::TensorProto& initializer,
}
#undef CASE_UNPACK
Status UnpackInitializerData(const ONNX_NAMESPACE::TensorProto& initializer,
std::vector<uint8_t>& unpacked_tensor) {
ORT_RETURN_IF(initializer.data_location() == TensorProto_DataLocation_EXTERNAL,
"The given initializer contains external data");
return UnpackInitializerData(initializer, Path(), unpacked_tensor);
}
} // namespace utils
} // namespace onnxruntime

View file

@ -47,11 +47,11 @@ common::Status TensorProtoToMLValue(const Env& env, const ORTCHAR_T* tensor_prot
const ONNX_NAMESPACE::TensorProto& input, const MemBuffer& m, OrtValue& value);
/**
* @brief Deserialize a TensorProto into a preallocated empty Tensor
* @param env
* @param model_path
* @param env
* @param model_path
* @param tensor_proto source data
* @param tensorp destination empty tensor
* @return
* @return
*/
common::Status TensorProtoToTensor(const Env& env, const ORTCHAR_T* model_path,
const ONNX_NAMESPACE::TensorProto& tensor_proto,
@ -304,15 +304,23 @@ Status UnpackTensor(const ONNX_NAMESPACE::TensorProto& tensor, const Path& model
* Unpack the data from an initializer tensor
* Please note, this function does not unpack string_data of an initializer tensor
* @param initializer given initializer tensor
* @param initializer_dir model_path to construct external data dir path. When this is empty, current dir is used.
* @param unpacked_tensor the data from the initializer in byte form
* @param tensor_byte_size the byte size of the unpacked_tensor
* @param model_path model_path to construct external data dir path. When this is empty, current dir is used.
* @param unpacked_tensor the vector holds data from the initializer in byte form
* @returns Status::OK() if data is unpacked successfully
*/
common::Status UnpackInitializerData(const ONNX_NAMESPACE::TensorProto& initializer,
const Path& model_path,
std::unique_ptr<unsigned char[]>& unpacked_tensor,
size_t& tensor_byte_size) ORT_MUST_USE_RESULT;
std::vector<uint8_t>& unpacked_tensor);
/**
* Unpack the data from an internal initializer tensor, will return error when the given initializer
* contains external data
* Please note, this function does not unpack string_data of an initializer tensor
* @param initializer given initializer tensor
* @param unpacked_tensor the vector holds data from the initializer in byte form
* @returns Status::OK() if data is unpacked successfully
*/
common::Status UnpackInitializerData(const ONNX_NAMESPACE::TensorProto& initializer,
std::vector<uint8_t>& unpacked_tensor);
} // namespace utils
} // namespace onnxruntime

View file

@ -2364,7 +2364,7 @@ Status Graph::VerifyNodeAndOpMatch(const ResolveOptions& options) {
node.since_version_ = node.op_->since_version();
if (node.op_->Deprecated()) {
node.op_ = nullptr;
node.op_ = nullptr;
}
}
@ -2451,7 +2451,7 @@ void Graph::InitFunctionBodyForNode(Node& node) {
function_container_.emplace_back(std::move(func_ptr));
node.SetFunctionBody(*function_container_.back());
}
ORT_CATCH(const std::exception& ) {
ORT_CATCH(const std::exception&) {
// Return without using this function op's expansion. No need to fail just yet.
// If ORT has a specialized kernel for this op then execution will proceed
return;
@ -3144,10 +3144,9 @@ ONNX_NAMESPACE::GraphProto Graph::ToGraphProtoWithExternalInitializers(const std
// Dense tensors larger than the threshold are added to the external file.
TensorProto* output_proto = result.add_initializer();
size_t tensor_bytes_size = 0;
std::unique_ptr<uint8_t[]> raw_data;
ORT_THROW_IF_ERROR(utils::UnpackInitializerData(initializer, Path(), raw_data, tensor_bytes_size));
std::vector<uint8_t> raw_data;
ORT_THROW_IF_ERROR(utils::UnpackInitializerData(initializer, Path(), raw_data));
size_t tensor_bytes_size = raw_data.size();
if (tensor_bytes_size < initializer_size_threshold) {
*output_proto = initializer;
continue;

View file

@ -44,11 +44,10 @@ Status SaveInitializerOrtFormat(flatbuffers::FlatBufferBuilder& builder,
std::copy(initializer.string_data().cbegin(), initializer.string_data().cend(), string_data_vec.begin());
string_data = builder.CreateVectorOfStrings(string_data_vec);
} else {
std::unique_ptr<uint8_t[]> unpacked_tensor;
size_t tensor_byte_size = 0;
std::vector<uint8_t> unpacked_tensor;
ORT_RETURN_IF_ERROR(
onnxruntime::utils::UnpackInitializerData(initializer, model_path, unpacked_tensor, tensor_byte_size));
raw_data = builder.CreateVector(unpacked_tensor.get(), tensor_byte_size);
onnxruntime::utils::UnpackInitializerData(initializer, model_path, unpacked_tensor));
raw_data = builder.CreateVector(unpacked_tensor.data(), unpacked_tensor.size());
}
fbs::TensorBuilder tb(builder);

View file

@ -281,12 +281,8 @@ bool HasValidQuantizationZeroPoints(const InitializedTensorSet& initializers, co
return false;
}
std::unique_ptr<uint8_t[]> unpacked_tensor;
size_t tensor_byte_size;
auto status = onnxruntime::utils::UnpackInitializerData(
zero_tensor,
node.ModelPath(),
unpacked_tensor, tensor_byte_size);
std::vector<uint8_t> unpacked_tensor;
auto status = onnxruntime::utils::UnpackInitializerData(zero_tensor, node.ModelPath(), unpacked_tensor);
if (!status.IsOK()) {
LOGS_DEFAULT(ERROR) << "Qlinear[Conv/MatMul] error when unpack zero tensor: " << zero_point_name
<< ", error msg: " << status.ErrorMessage();
@ -294,8 +290,8 @@ bool HasValidQuantizationZeroPoints(const InitializedTensorSet& initializers, co
}
// Verify all onnx weight zero point(s) are 0(s)
const int8_t* zero_points = reinterpret_cast<const int8_t*>(unpacked_tensor.get());
for (size_t i = 0; i < tensor_byte_size; i++) {
const int8_t* zero_points = reinterpret_cast<const int8_t*>(unpacked_tensor.data());
for (size_t i = 0; i < unpacked_tensor.size(); i++) {
if (zero_points[i] != 0) {
LOGS_DEFAULT(VERBOSE) << "u8s8 Qlinear[Conv/MatMul] only support 0 as zero point, "
<< "zero_points[" << i << "] has value: " << zero_points[i];
@ -315,14 +311,15 @@ float GetQuantizationScale(const InitializedTensorSet& initializers, const Node&
common::Status GetQuantizationZeroPoint(const InitializedTensorSet& initializers,
const Node& node, size_t idx, int32_t& zero_point) {
std::unique_ptr<uint8_t[]> unpacked_tensor;
size_t tensor_byte_size;
const auto& zero_point_tensor = *initializers.at(node.InputDefs()[idx]->Name());
std::vector<uint8_t> unpacked_tensor;
const auto& name = node.InputDefs()[idx]->Name();
const auto& zero_point_tensor = *initializers.at(name);
ORT_RETURN_IF_ERROR(
onnxruntime::utils::UnpackInitializerData(zero_point_tensor, node.ModelPath(),
unpacked_tensor, tensor_byte_size));
onnxruntime::utils::UnpackInitializerData(zero_point_tensor, node.ModelPath(), unpacked_tensor));
ORT_RETURN_IF(unpacked_tensor.empty(), "The initializer [", name, "] is empty");
// Onnx quantization uses uint8 [int8 not yet supported], need to cast to int32_t used by NNAPI
zero_point = static_cast<int32_t>(unpacked_tensor.get()[0]);
zero_point = static_cast<int32_t>(unpacked_tensor[0]);
return Status::OK();
}

View file

@ -281,20 +281,18 @@ Status ModelBuilder::RegisterInitializers() {
std::tie(index, size, padded_size) = initializers[i++];
const uint8_t* src = nullptr;
// uint8_t data need unpack, need a holder for free memory after copy
std::unique_ptr<uint8_t[]> unpacked_tensor;
std::vector<uint8_t> unpacked_tensor;
switch (tensor.data_type()) {
case ONNX_NAMESPACE::TensorProto_DataType_FLOAT:
src = reinterpret_cast<const uint8_t*>(GetTensorFloatData(tensor));
break;
case ONNX_NAMESPACE::TensorProto_DataType_UINT8:
size_t tensor_byte_size;
ORT_RETURN_IF_ERROR(
onnxruntime::utils::UnpackInitializerData(tensor, graph_viewer_.ModelPath(),
unpacked_tensor, tensor_byte_size));
ORT_RETURN_IF_NOT(size == tensor_byte_size,
"initializer tensor: ", tensor.name(), "'s size: ", tensor_byte_size,
onnxruntime::utils::UnpackInitializerData(tensor, graph_viewer_.ModelPath(), unpacked_tensor));
ORT_RETURN_IF_NOT(size == unpacked_tensor.size(),
"initializer tensor: ", tensor.name(), "'s size: ", unpacked_tensor.size(),
" should match the calculated size: ", size);
src = unpacked_tensor.get();
src = unpacked_tensor.data();
break;
// default:
// We should not get anything else here since we already checked in the 1st pass

View file

@ -297,8 +297,7 @@ static Status AddInitializerInNewLayout(ModelBuilder& model_builder,
// TODO support other data types
const uint8_t* src = nullptr;
std::unique_ptr<uint8_t[]> unpacked_tensor;
size_t tensor_byte_size;
std::vector<uint8_t> unpacked_tensor;
switch (tensor.data_type()) {
case ONNX_NAMESPACE::TensorProto_DataType_FLOAT:
@ -308,8 +307,8 @@ static Status AddInitializerInNewLayout(ModelBuilder& model_builder,
case ONNX_NAMESPACE::TensorProto_DataType_INT8: {
ORT_RETURN_IF_ERROR(
onnxruntime::utils::UnpackInitializerData(tensor, model_builder.GetGraphViewer().ModelPath(),
unpacked_tensor, tensor_byte_size));
src = unpacked_tensor.get();
unpacked_tensor));
src = unpacked_tensor.data();
break;
}
default:
@ -389,8 +388,7 @@ static Status AddInitializerTransposed(ModelBuilder& model_builder,
// TODO support other data types
const uint8_t* src = nullptr;
std::unique_ptr<uint8_t[]> unpacked_tensor;
size_t tensor_byte_size;
std::vector<uint8_t> unpacked_tensor;
switch (tensor.data_type()) {
case ONNX_NAMESPACE::TensorProto_DataType_FLOAT:
src = reinterpret_cast<const uint8_t*>(GetTensorFloatData(tensor));
@ -399,8 +397,8 @@ static Status AddInitializerTransposed(ModelBuilder& model_builder,
case ONNX_NAMESPACE::TensorProto_DataType_INT8: {
ORT_RETURN_IF_ERROR(
onnxruntime::utils::UnpackInitializerData(tensor, model_builder.GetGraphViewer().ModelPath(),
unpacked_tensor, tensor_byte_size));
src = unpacked_tensor.get();
unpacked_tensor));
src = unpacked_tensor.data();
break;
}
default:
@ -2615,18 +2613,18 @@ Status SliceOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const
const auto& initializers(model_builder.GetInitializerTensors());
const auto& tensor = *initializers.at(input_name);
std::unique_ptr<uint8_t[]> unpacked_tensor;
size_t tensor_byte_size;
std::vector<uint8_t> unpacked_tensor;
ORT_RETURN_IF_ERROR(
onnxruntime::utils::UnpackInitializerData(tensor, model_builder.GetGraphViewer().ModelPath(),
unpacked_tensor, tensor_byte_size));
unpacked_tensor));
size_t tensor_byte_size = unpacked_tensor.size();
const auto data_type = tensor.data_type();
if (data_type == ONNX_NAMESPACE::TensorProto_DataType_INT64) {
const int64_t* tensor_data = reinterpret_cast<const int64_t*>(unpacked_tensor.get());
const int64_t* tensor_data = reinterpret_cast<const int64_t*>(unpacked_tensor.data());
size_t size = tensor_byte_size / sizeof(int64_t);
data.insert(data.end(), tensor_data, tensor_data + size);
} else if (data_type == ONNX_NAMESPACE::TensorProto_DataType_INT32) {
const int32_t* tensor_data = reinterpret_cast<const int32_t*>(unpacked_tensor.get());
const int32_t* tensor_data = reinterpret_cast<const int32_t*>(unpacked_tensor.data());
size_t size = tensor_byte_size / sizeof(int32_t);
data.insert(data.end(), tensor_data, tensor_data + size);
} else {

View file

@ -5,9 +5,9 @@
#include "utils.h"
#include <core/common/safeint.h>
#include <core/framework/tensorprotoutils.h>
#include <core/graph/graph.h>
#include "core/providers/common.h"
#include <core/providers/common.h>
namespace onnxruntime {
@ -66,7 +66,13 @@ bool GetClipMinMax(const InitializedTensorSet& initializers, const Node& node,
LOGS(logger, VERBOSE) << "Input min of Clip must be known";
return false;
}
min = GetTensorFloatData(*initializers.at(min_name))[0];
std::vector<uint8_t> unpacked_tensor;
auto status = onnxruntime::utils::UnpackInitializerData(*initializers.at(min_name), unpacked_tensor);
if (!status.IsOK()) {
LOGS(logger, ERROR) << "Error while unpack min tensor: " << status.ErrorMessage();
return false;
}
min = reinterpret_cast<float*>(unpacked_tensor.data())[0];
}
if (node.InputDefs().size() > 2) { // we have input max
@ -75,7 +81,13 @@ bool GetClipMinMax(const InitializedTensorSet& initializers, const Node& node,
LOGS(logger, VERBOSE) << "Input max of Clip must be known";
return false;
}
max = GetTensorFloatData(*initializers.at(max_name))[0];
std::vector<uint8_t> unpacked_tensor;
auto status = onnxruntime::utils::UnpackInitializerData(*initializers.at(max_name), unpacked_tensor);
if (!status.IsOK()) {
LOGS(logger, ERROR) << "Error while unpack max tensor: " << status.ErrorMessage();
return false;
}
max = reinterpret_cast<float*>(unpacked_tensor.data())[0];
}
}

View file

@ -46,13 +46,13 @@ void LoadSaveAndCompareModel(const std::string& input_onnx,
const ONNX_NAMESPACE::TensorProto* tensor_proto = i.second;
const ONNX_NAMESPACE::TensorProto* from_external_tensor_proto = initializers_from_external[kInitName];
size_t tensor_proto_size = 0;
std::unique_ptr<uint8_t[]> tensor_proto_data;
ORT_THROW_IF_ERROR(utils::UnpackInitializerData(*tensor_proto, Path(), tensor_proto_data, tensor_proto_size));
std::vector<uint8_t> tensor_proto_data;
ORT_THROW_IF_ERROR(utils::UnpackInitializerData(*tensor_proto, Path(), tensor_proto_data));
size_t tensor_proto_size = tensor_proto_data.size();
size_t from_external_tensor_proto_size = 0;
std::unique_ptr<uint8_t[]> from_external_tensor_proto_data;
ORT_THROW_IF_ERROR(utils::UnpackInitializerData(*from_external_tensor_proto, Path(), from_external_tensor_proto_data, from_external_tensor_proto_size));
std::vector<uint8_t> from_external_tensor_proto_data;
ORT_THROW_IF_ERROR(utils::UnpackInitializerData(*from_external_tensor_proto, Path(), from_external_tensor_proto_data));
size_t from_external_tensor_proto_size = from_external_tensor_proto_data.size();
if (from_external_tensor_proto_size < initializer_size_threshold) {
// 'Small' tensors should be embedded in the onnx file.
@ -63,7 +63,7 @@ void LoadSaveAndCompareModel(const std::string& input_onnx,
}
ASSERT_EQ(tensor_proto_size, from_external_tensor_proto_size);
EXPECT_EQ(memcmp(tensor_proto_data.get(), from_external_tensor_proto_data.get(), tensor_proto_size), 0);
EXPECT_EQ(memcmp(tensor_proto_data.data(), from_external_tensor_proto_data.data(), tensor_proto_size), 0);
}
// Cleanup.
ASSERT_EQ(std::remove(output_onnx.c_str()), 0);