diff --git a/include/onnxruntime/core/framework/float16.h b/include/onnxruntime/core/framework/float16.h index 4b256b3137..6c780c53b2 100644 --- a/include/onnxruntime/core/framework/float16.h +++ b/include/onnxruntime/core/framework/float16.h @@ -7,6 +7,10 @@ #include "cuda_bf16.h" #endif +#if !defined(__CUDACC__) && !defined(__HIPCC__) +#include +#endif + #include "core/common/common.h" namespace onnxruntime { @@ -19,10 +23,10 @@ namespace onnxruntime { // MLFloat16 struct MLFloat16 { - uint16_t val; + uint16_t val{0}; - MLFloat16() : val(0) {} - explicit MLFloat16(uint16_t x) : val(x) {} + MLFloat16() = default; + explicit constexpr MLFloat16(uint16_t x) : val(x) {} explicit MLFloat16(float f); float ToFloat() const; @@ -45,7 +49,7 @@ struct BFloat16 { struct FromBitsT {}; static constexpr ORT_HOST_DEVICE FromBitsT FromBits() { return FromBitsT(); } - constexpr ORT_HOST_DEVICE BFloat16(unsigned short bits, FromBitsT) : val(bits){}; + constexpr ORT_HOST_DEVICE BFloat16(unsigned short bits, FromBitsT) : val(bits) {} inline ORT_HOST_DEVICE BFloat16(float v) { #if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 @@ -109,6 +113,33 @@ struct BFloat16 { #endif }; +inline bool operator==(const BFloat16& left, const BFloat16& right) { return left.val == right.val; } +inline bool operator!=(const BFloat16& left, const BFloat16& right) { return left.val != right.val; } +inline bool operator<(const BFloat16& left, const BFloat16& right) { return left.val < right.val; } + + +// User defined suffixes to make it easier to declare +// initializers with MLFloat16 and BFloat16 from unsigned short +// E.g 10_f16 or 10_b16 +#if !defined(__CUDACC__) && !defined(__HIPCC__) +inline MLFloat16 operator"" _f16(unsigned long long int v) { + return MLFloat16(gsl::narrow(v)); +} + +inline MLFloat16 operator"" _fp16(long double v) { + return MLFloat16(static_cast(v)); +} + +inline BFloat16 operator"" _b16(unsigned long long int v) { + return BFloat16(gsl::narrow(v), BFloat16::FromBits()); +} + +inline BFloat16 operator"" _bfp16(long double v) { + return BFloat16(static_cast(v)); +} + +#endif + inline void BFloat16ToFloat(const BFloat16* blf, float* flt, size_t size) { auto src = blf; auto d = flt; diff --git a/onnxruntime/core/optimizer/initializer.cc b/onnxruntime/core/optimizer/initializer.cc index b35eaa8deb..1128fadcd0 100644 --- a/onnxruntime/core/optimizer/initializer.cc +++ b/onnxruntime/core/optimizer/initializer.cc @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#if !defined(ORT_MINIMAL_BUILD) #include "core/optimizer/initializer.h" #include "gsl/gsl" @@ -11,49 +10,314 @@ #include "core/framework/tensor_external_data_info.h" #include "core/platform/env.h" +#include + namespace onnxruntime { -Status Initializer::ReadExternalRawData( - const ONNX_NAMESPACE::TensorProto& tensor_proto, const Path& model_path, std::vector& raw_data) { - ORT_RETURN_IF_NOT( - tensor_proto.data_type() != ONNX_NAMESPACE::TensorProto_DataType_UNDEFINED && - tensor_proto.data_type() != ONNX_NAMESPACE::TensorProto_DataType_STRING, - "External data type must not be UNDEFINED or STRING."); - ORT_RETURN_IF( - model_path.IsEmpty(), - "model_path must not be empty. Ensure that a path is provided when the model is created or loaded."); - - std::unique_ptr external_data{}; - ORT_RETURN_IF_ERROR(ExternalDataInfo::Create(tensor_proto.external_data(), external_data)); - - size_t actual_tensor_data_length; - ORT_RETURN_IF_ERROR(utils::GetSizeInBytesFromTensorProto<0>( - tensor_proto, &actual_tensor_data_length)); - const size_t external_data_length = external_data->GetLength(); - - ORT_RETURN_IF_NOT( - external_data_length == 0 || - external_data_length == actual_tensor_data_length, - "TensorProto external data size mismatch. ", - "Computed size: ", actual_tensor_data_length, - ", external_data.length: ", external_data_length); - - Path external_data_relative_path{}; - ORT_RETURN_IF_ERROR(Path::Parse( - external_data->GetRelPath(), external_data_relative_path)); - - std::vector buffer(actual_tensor_data_length); - - ORT_RETURN_IF_ERROR(Env::Default().ReadFileIntoBuffer( - (model_path.ParentPath() / external_data_relative_path).ToPathString().c_str(), - external_data->GetOffset(), - actual_tensor_data_length, - gsl::make_span(buffer))); - - raw_data = std::move(buffer); - - return Status::OK(); +Initializer::Initializer(ONNX_NAMESPACE::TensorProto_DataType data_type, + std::string_view name, + gsl::span dims) + : name_(name), + data_(DataTypeImpl::TensorTypeFromONNXEnum(data_type)->GetElementType(), dims, std::make_shared()) { + if (!data_.IsDataTypeString()) { + memset(data_.MutableDataRaw(), 0, data_.SizeInBytes()); + } } -} // namespace onnxruntime -#endif // !(ORT_MINIMAL_BUILD) +Initializer::Initializer(const ONNX_NAMESPACE::TensorProto& tensor_proto, const Path& model_path) { + ORT_ENFORCE(utils::HasDataType(tensor_proto), "Initializer must have a datatype"); + if (utils::HasExternalData(tensor_proto)) { + ORT_ENFORCE(!model_path.IsEmpty(), + "model_path must not be empty. Ensure that a path is provided when the model is created or loaded."); + } + + auto proto_data_type = tensor_proto.data_type(); + if (utils::HasName(tensor_proto)) { + name_ = tensor_proto.name(); + } + + auto proto_dims = utils::GetTensorShapeFromTensorProto(tensor_proto); + TensorShape proto_shape(proto_dims); + + // This must be pre-allocated + Tensor w(DataTypeImpl::TensorTypeFromONNXEnum(proto_data_type)->GetElementType(), proto_shape, std::make_shared()); + ORT_THROW_IF_ERROR(utils::TensorProtoToTensor(Env::Default(), model_path.ToPathString().c_str(), tensor_proto, w)); + data_ = std::move(w); +} + +namespace { +template +struct ToFp16; + +template <> +struct ToFp16 { + uint16_t operator()(const MLFloat16& fl) const { + return fl.val; + } +}; + +template <> +struct ToFp16 { + uint16_t operator()(float f) const { + return MLFloat16(f).val; + } +}; + +template <> +struct ToFp16 { + uint16_t operator()(double d) const { + // The same code as in Eigen. We assume the loss of precision will occur + // hence static_cast + return MLFloat16(static_cast(d)).val; + } +}; + +template +struct TensorToProtoFP16 { + void operator()(const Tensor& data, ONNX_NAMESPACE::TensorProto& proto) const { + ToFp16 to_fp16; + auto span = data.DataAsSpan(); + for (const auto& v : span) { + proto.add_int32_data(to_fp16(v)); + } + } +}; + +template +struct ToBFloat16; + +template <> +struct ToBFloat16 { + uint16_t operator()(const BFloat16& bf) const { + return bf.val; + } +}; + +template <> +struct ToBFloat16 { + uint16_t operator()(float f) const { + return BFloat16(f).val; + } +}; + +template <> +struct ToBFloat16 { + uint16_t operator()(double d) const { + // The same code as in Eigen. We assume the loss of precision will occur + // hence static_cast + return BFloat16(static_cast(d)).val; + } +}; + +template +struct TensorToProtoBFloat16 { + void operator()(const Tensor& data, ONNX_NAMESPACE::TensorProto& proto) const { + ToBFloat16 to_bfloat16; + auto span = data.DataAsSpan(); + for (const auto& v : span) { + proto.add_int32_data(to_bfloat16(v)); + } + } +}; + +inline void SetNameDims(const std::string& name, + gsl::span dims, + ONNX_NAMESPACE::TensorProto_DataType dt, + ONNX_NAMESPACE::TensorProto& tensor_proto) { + tensor_proto.set_name(name); + tensor_proto.set_data_type(dt); + + for (auto d : dims) { + tensor_proto.add_dims(d); + } +} + +} // namespace + +ONNX_NAMESPACE::TensorProto Initializer::ToFP16(const std::string& name) const { + ONNX_NAMESPACE::TensorProto tensor_proto; + SetNameDims(name, data_.Shape().GetDims(), ONNX_NAMESPACE::TensorProto_DataType_FLOAT16, tensor_proto); + utils::MLTypeCallDispatcher t_disp(data_.GetElementType()); + t_disp.Invoke(data_, tensor_proto); + return tensor_proto; +} + +ONNX_NAMESPACE::TensorProto Initializer::ToBFloat16(const std::string& name) const { + ONNX_NAMESPACE::TensorProto tensor_proto; + SetNameDims(name, data_.Shape().GetDims(), ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16, tensor_proto); + utils::MLTypeCallDispatcher t_disp(data_.GetElementType()); + t_disp.Invoke(data_, tensor_proto); + return tensor_proto; +} + +namespace { + +// std::identity c++20 +template +struct ToNumeric { + using type = T; + constexpr const T& operator()(const T& v) const { + return v; + } +}; + +template <> +struct ToNumeric { + using type = float; + float operator()(const MLFloat16& v) const { + return v.ToFloat(); + } +}; + +template <> +struct ToNumeric { + using type = float; + float operator()(const BFloat16& v) const { + return v.ToFloat(); + } +}; + +template +struct OpElementWise { + void Invoke(Tensor& lhs, const Tensor& rhs) const { + Op op; + ToNumeric to_numeric; + auto dst_span = lhs.MutableDataAsSpan(); + auto src_span = rhs.DataAsSpan(); + for (size_t i = 0, limit = dst_span.size(); i < limit; ++i) { + dst_span[i] = T(op(to_numeric(dst_span[i]), to_numeric(src_span[i]))); + } + } +}; + +template +struct ScalarAdd { + void operator()(Tensor& tensor, float v) const { + ToNumeric to_numeric; + auto span = tensor.MutableDataAsSpan(); + for (auto& dst : span) { + dst = T(to_numeric(dst) + v); + } + } +}; + +template +struct Sqrt { + void operator()(Tensor& tensor) const { + ToNumeric to_numeric; + auto span = tensor.MutableDataAsSpan(); + for (auto& dst : span) { + auto v = to_numeric(dst); + dst = T(std::sqrt(v)); + } + } +}; + +template +struct ElementWiseAdd : OpElementWise::type>> { + void operator()(Tensor& lhs, const Tensor& rhs) const { + this->Invoke(lhs, rhs); + } +}; + +template +struct ElementWiseSub : OpElementWise::type>> { + void operator()(Tensor& lhs, const Tensor& rhs) const { + this->Invoke(lhs, rhs); + } +}; + +template +struct ElementWiseMul : OpElementWise::type>> { + void operator()(Tensor& lhs, const Tensor& rhs) const { + this->Invoke(lhs, rhs); + } +}; + +template +struct ElementWiseDiv : OpElementWise::type>> { + void operator()(Tensor& lhs, const Tensor& rhs) const { + this->Invoke(lhs, rhs); + } +}; +} // namespace + +Initializer& Initializer::add(float value) { + utils::MLTypeCallDispatcher t_disp(data_.GetElementType()); + t_disp.Invoke(data_, value); + return *this; +} + +Initializer& Initializer::add(const Initializer& other) { + ORT_ENFORCE(data_type() == other.data_type(), "Expecting the same data type"); + ORT_ENFORCE(size() == other.size(), "Expecting the same size"); + utils::MLTypeCallDispatcher t_disp(data_.GetElementType()); + t_disp.Invoke(data_, other.data_); + return *this; +} + +Initializer& Initializer::sub(const Initializer& other) { + ORT_ENFORCE(data_type() == other.data_type(), "Expecting the same data type"); + ORT_ENFORCE(size() == other.size(), "Expecting the same size"); + utils::MLTypeCallDispatcher t_disp(data_.GetElementType()); + t_disp.Invoke(data_, other.data_); + return *this; +} + +Initializer& Initializer::mul(const Initializer& other) { + ORT_ENFORCE(data_type() == other.data_type(), "Expecting the same data type"); + ORT_ENFORCE(size() == other.size(), "Expecting the same size"); + utils::MLTypeCallDispatcher t_disp(data_.GetElementType()); + t_disp.Invoke(data_, other.data_); + return *this; +} + +Initializer& Initializer::div(const Initializer& other) { + ORT_ENFORCE(data_type() == other.data_type(), "Expecting the same data type"); + ORT_ENFORCE(size() == other.size(), "Expecting the same size"); + utils::MLTypeCallDispatcher t_disp(data_.GetElementType()); + t_disp.Invoke(data_, other.data_); + return *this; +} + +Initializer& Initializer::sqrt() { + utils::MLTypeCallDispatcher t_disp(data_.GetElementType()); + t_disp.Invoke(data_); + return *this; +} + +namespace { +template +struct ScaleByAxis { + void operator()(Tensor& data, const Tensor& scalers, const int64_t block_size, const int64_t num_blocks) const { + ToNumeric to_numeric; + const auto scaler_size = scalers.Shape().Size(); + T* dst = data.MutableData(); + const T* scalers_data = scalers.Data(); + if (scaler_size == 1) { + const auto numeric_scaler = to_numeric(scalers_data[0]); + for (int64_t block_offset = 0, limit = block_size * num_blocks; block_offset < limit; ++block_offset) { + dst[block_offset] = T(to_numeric(dst[block_offset]) * numeric_scaler); + } + } else + for (int64_t block_offset = 0, i = 0; i < num_blocks; i++) { + const auto numeric_scaler = to_numeric(scalers_data[i]); + for (int64_t j = 0; j < block_size; ++j, ++block_offset) { + dst[block_offset] = T(to_numeric(dst[block_offset]) * numeric_scaler); + } + } + } +}; + +} // namespace + +void Initializer::scale_by_axis(const Initializer& scalers, int axis) { + ORT_ENFORCE(axis >= 0, "Axis must be non-negative"); + const int64_t block_size = data_.Shape().SizeFromDimension(gsl::narrow_cast(axis)); + const int64_t num_blocks = size() / block_size; + ORT_ENFORCE(scalers.size() == 1 || scalers.size() == num_blocks, "Invalid other(scalers) size"); + utils::MLTypeCallDispatcher t_disp(data_.GetElementType()); + t_disp.Invoke(data_, scalers.data_, block_size, num_blocks); +} + +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/initializer.h b/onnxruntime/core/optimizer/initializer.h index b80fe0c059..f5ee267370 100644 --- a/onnxruntime/core/optimizer/initializer.h +++ b/onnxruntime/core/optimizer/initializer.h @@ -4,11 +4,15 @@ #pragma once #include +#include #include #include #include "core/common/common.h" #include "core/common/path.h" +#include "core/framework/allocator.h" +#include "core/optimizer/graph_transformer.h" +#include "core/framework/tensor_shape.h" #include "core/framework/tensorprotoutils.h" #include "core/graph/onnx_protobuf.h" #include "core/util/math.h" @@ -19,804 +23,68 @@ class Initializer final { public: // Construct an initializer with the provided name and data type, with all values initialized to 0 Initializer(ONNX_NAMESPACE::TensorProto_DataType data_type, - const std::string& name, - const std::vector& dims) : dims_(dims), size_(0) { - data_type_ = data_type; - name_ = name; - size_ = std::accumulate(dims_.begin(), dims_.end(), int64_t(1), std::multiplies{}); + std::string_view name, + gsl::span dims); - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: { - float16_data_.assign(static_cast(size_), math::floatToHalf(0.f)); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: { - // Reuse float16 field - float16_data_.assign(static_cast(size_), BFloat16(0.f).val); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - float_data_.assign(static_cast(size_), 0.0f); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - double_data_.assign(static_cast(size_), 0.0); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT8: { - int8_data_.assign(static_cast(size_), 0); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_UINT8: { - uint8_data_.assign(static_cast(size_), 0); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT32: { - int32_data_.assign(static_cast(size_), 0); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT64: { - int64_data_.assign(static_cast(size_), 0); - break; - } - default: - ORT_THROW("data type ", data_type_, "is not supported."); - break; - } - } - - Initializer(const ONNX_NAMESPACE::TensorProto& tensor_proto, const Path& model_path) { - data_type_ = tensor_proto.data_type(); - if (utils::HasName(tensor_proto)) { - name_ = tensor_proto.name(); - } - dims_.reserve(tensor_proto.dims_size()); - for (int i = 0; i < tensor_proto.dims_size(); i++) { - dims_.push_back(tensor_proto.dims(i)); - } - - size_ = std::accumulate(dims_.begin(), dims_.end(), static_cast(1), std::multiplies{}); - - if (tensor_proto.data_location() != ONNX_NAMESPACE::TensorProto_DataLocation_EXTERNAL) { - if (utils::HasRawData(tensor_proto)) { - raw_data_.assign(tensor_proto.raw_data().begin(), tensor_proto.raw_data().end()); - } else { - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: { - int64_t size = tensor_proto.int32_data_size(); - ORT_ENFORCE(size_ == size, "size is different"); - for (int i = 0; i < size_; i++) { - float16_data_.push_back(static_cast(tensor_proto.int32_data(i))); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - int64_t size = tensor_proto.float_data_size(); - ORT_ENFORCE(size_ == size, "size is different"); - for (int i = 0; i < size_; i++) { - float_data_.push_back(tensor_proto.float_data(i)); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - int64_t size = tensor_proto.double_data_size(); - ORT_ENFORCE(size_ == size, "size is different"); - for (int i = 0; i < size_; i++) { - double_data_.push_back(tensor_proto.double_data(i)); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT8: { - int64_t size = tensor_proto.int32_data_size(); - ORT_ENFORCE(size_ == size, "size is different"); - for (int i = 0; i < size_; i++) { - int8_data_.push_back(static_cast(tensor_proto.int32_data(i))); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_UINT8: { - int64_t size = tensor_proto.int32_data_size(); - ORT_ENFORCE(size_ == size, "size is different"); - for (int i = 0; i < size_; i++) { - uint8_data_.push_back(static_cast(tensor_proto.int32_data(i))); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT32: { - int64_t size = tensor_proto.int32_data_size(); - ORT_ENFORCE(size_ == size, "size is different"); - for (int i = 0; i < size_; i++) { - int32_data_.push_back(tensor_proto.int32_data(i)); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT64: { - int64_t size = tensor_proto.int64_data_size(); - ORT_ENFORCE(size_ == size, "size is different"); - for (int i = 0; i < size_; i++) { - int64_data_.push_back(tensor_proto.int64_data(i)); - } - break; - } - default: - ORT_NOT_IMPLEMENTED(__FUNCTION__, "unsupported data type: ", data_type_); - break; - } - } - } else { // tensor_proto.data_location() == ONNX_NAMESPACE::TensorProto_DataLocation_EXTERNAL -#if !defined(ORT_MINIMAL_BUILD) - const auto status = ReadExternalRawData(tensor_proto, model_path, raw_data_); - ORT_ENFORCE(status.IsOK(), "ReadExternalRawData() failed: ", status.ErrorMessage()); -#else - ORT_UNUSED_PARAMETER(model_path); - ORT_THROW("External data is not supported in an ORT formal model."); -#endif - } - } + Initializer(const ONNX_NAMESPACE::TensorProto& tensor_proto, + const Path& model_path); ~Initializer() = default; - void ToProto(ONNX_NAMESPACE::TensorProto& tensor_proto) { - tensor_proto.clear_name(); - if (!name_.empty()) { - tensor_proto.set_name(name_); - } - - tensor_proto.clear_dims(); - for (auto d : dims_) { - tensor_proto.add_dims(d); - } - - tensor_proto.clear_data_type(); - tensor_proto.set_data_type(data_type_); - - if (!raw_data_.empty()) { - tensor_proto.clear_raw_data(); - tensor_proto.set_raw_data(raw_data_.data(), raw_data_.size()); - } else { - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: { - tensor_proto.clear_int32_data(); - for (int i = 0; i < size_; i++) { - tensor_proto.add_int32_data(float16_data_[i]); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - tensor_proto.clear_float_data(); - for (int i = 0; i < size_; i++) { - tensor_proto.add_float_data(float_data_[i]); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - tensor_proto.clear_double_data(); - for (int i = 0; i < size_; i++) { - tensor_proto.add_double_data(double_data_[i]); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT8: { - tensor_proto.clear_int32_data(); - for (int i = 0; i < size_; i++) { - tensor_proto.add_int32_data(int8_data_[i]); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_UINT8: { - tensor_proto.clear_int32_data(); - for (int i = 0; i < size_; i++) { - tensor_proto.add_int32_data(uint8_data_[i]); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT32: { - tensor_proto.clear_int32_data(); - for (int i = 0; i < size_; i++) { - tensor_proto.add_int32_data(int32_data_[i]); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT64: { - tensor_proto.clear_int64_data(); - for (int i = 0; i < size_; i++) { - tensor_proto.add_int64_data(int64_data_[i]); - } - break; - } - default: - ORT_NOT_IMPLEMENTED(__FUNCTION__, "data type is not supported"); - break; - } - } + void ToProto(ONNX_NAMESPACE::TensorProto& tensor_proto) const { + tensor_proto = utils::TensorToTensorProto(data_, name_); } - ONNX_NAMESPACE::TensorProto ToFP16(const std::string name) { - ONNX_NAMESPACE::TensorProto tensor_proto; - tensor_proto.set_name(name); + ONNX_NAMESPACE::TensorProto ToFP16(const std::string& name) const; - for (auto d : dims_) { - tensor_proto.add_dims(d); - } - - tensor_proto.set_data_type(ONNX_NAMESPACE::TensorProto_DataType_FLOAT16); - - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: { - uint16_t* dst = data(); - for (int i = 0; i < size_; i++) { - tensor_proto.add_int32_data(dst[i]); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - float* dst = data(); - for (int i = 0; i < size_; i++) { - tensor_proto.add_int32_data(math::floatToHalf(dst[i])); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - double* dst = data(); - for (int i = 0; i < size_; i++) { - tensor_proto.add_int32_data(math::doubleToHalf(dst[i])); - } - break; - } - default: - ORT_NOT_IMPLEMENTED(__FUNCTION__, "data type is not supported"); - break; - } - return tensor_proto; - } - - ONNX_NAMESPACE::TensorProto ToBFloat16(const std::string name) { - ONNX_NAMESPACE::TensorProto tensor_proto; - tensor_proto.set_name(name); - - for (auto d : dims_) { - tensor_proto.add_dims(d); - } - - tensor_proto.set_data_type(ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16); - - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - float* dst = data(); - for (int i = 0; i < size_; i++) { - tensor_proto.add_int32_data(BFloat16(dst[i]).val); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - double* dst = data(); - for (int i = 0; i < size_; i++) { - tensor_proto.add_int32_data(math::doubleToHalf(dst[i])); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: { - uint16_t* dst = data(); - for (int i = 0; i < size_; i++) { - tensor_proto.add_int32_data(dst[i]); - } - break; - } - default: - ORT_NOT_IMPLEMENTED(__FUNCTION__, "data type is not supported"); - break; - } - return tensor_proto; - } + ONNX_NAMESPACE::TensorProto ToBFloat16(const std::string& name) const; int data_type() const { - return data_type_; + return data_.GetElementType(); } - int& data_type() { - return data_type_; - } - - const std::string& name() { + std::string_view name() const { return name_; } template T* data() { - if (!raw_data_.empty()) { - return reinterpret_cast(raw_data_.data()); - } - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: { - return reinterpret_cast(float16_data_.data()); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - return reinterpret_cast(float_data_.data()); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - return reinterpret_cast(double_data_.data()); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT8: { - return reinterpret_cast(int8_data_.data()); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_UINT8: { - return reinterpret_cast(uint8_data_.data()); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT32: { - return reinterpret_cast(int32_data_.data()); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT64: { - return reinterpret_cast(int64_data_.data()); - break; - } - default: - break; - } - - return nullptr; + return data_.MutableData(); } template const T* data() const { - if (!raw_data_.empty()) { - return reinterpret_cast(raw_data_.data()); - } - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: { - return reinterpret_cast(float16_data_.data()); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - return reinterpret_cast(float_data_.data()); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - return reinterpret_cast(double_data_.data()); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT8: { - return reinterpret_cast(int8_data_.data()); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_UINT8: { - return reinterpret_cast(uint8_data_.data()); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT32: { - return reinterpret_cast(int32_data_.data()); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT64: { - return reinterpret_cast(int64_data_.data()); - break; - } - default: - break; - } - - return nullptr; + return data_.Data(); } - const std::vector& dims() const { - return dims_; + const int8_t* raw_data() const { + return reinterpret_cast(data_.DataRaw()); } - const std::vector& dims() { - return dims_; + gsl::span dims() const { + return data_.Shape().GetDims(); } - int64_t size() const { return size_; } + int64_t size() const { return data_.Shape().Size(); } - Initializer& add(float value) { - int64_t n = size(); - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: { - uint16_t* dst = data(); - for (int i = 0; i < n; i++) { - dst[i] = math::floatToHalf(math::halfToFloat(dst[i]) + value); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: { - uint16_t* dst = data(); - for (int i = 0; i < n; i++) { - dst[i] = BFloat16((reinterpret_cast(dst + i))->ToFloat() + value).val; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - float* dst = data(); - for (int i = 0; i < n; i++) { - dst[i] += value; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - double* dst = data(); - for (int i = 0; i < n; i++) { - dst[i] += value; - } - break; - } - default: - break; - } - return *this; - } + Initializer& add(float value); - Initializer& add(const Initializer& other) { - int64_t n = size(); - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: { - uint16_t* dst = data(); - const uint16_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] = math::floatToHalf(math::halfToFloat(dst[i]) + math::halfToFloat(src[i])); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: { - uint16_t* dst = data(); - const uint16_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] = BFloat16((reinterpret_cast(dst + i))->ToFloat() + (reinterpret_cast(src + i))->ToFloat()).val; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - float* dst = data(); - const float* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] += src[i]; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - double* dst = data(); - const double* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] += src[i]; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT32: { - int32_t* dst = data(); - const int32_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] += src[i]; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT64: { - int64_t* dst = data(); - const int64_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] += src[i]; - } - break; - } - default: - break; - } - return *this; - } - Initializer& sub(const Initializer& other) { - int64_t n = size(); - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: { - uint16_t* dst = data(); - const uint16_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] = math::floatToHalf(math::halfToFloat(dst[i]) - math::halfToFloat(src[i])); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: { - uint16_t* dst = data(); - const uint16_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] = BFloat16((reinterpret_cast(dst + i))->ToFloat() - (reinterpret_cast(src + i))->ToFloat()).val; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - float* dst = data(); - const float* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] -= src[i]; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - double* dst = data(); - const double* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] -= src[i]; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT32: { - int32_t* dst = data(); - const int32_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] -= src[i]; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT64: { - int64_t* dst = data(); - const int64_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] -= src[i]; - } - break; - } - default: - break; - } - return *this; - } + Initializer& add(const Initializer& other); - Initializer& mul(const Initializer& other) { - int64_t n = size(); - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: { - uint16_t* dst = data(); - const uint16_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] = math::floatToHalf(math::halfToFloat(dst[i]) * math::halfToFloat(src[i])); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: { - uint16_t* dst = data(); - const uint16_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] = BFloat16((reinterpret_cast(dst + i))->ToFloat() * (reinterpret_cast(src + i))->ToFloat()).val; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - float* dst = data(); - const float* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] *= src[i]; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - double* dst = data(); - const double* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] *= src[i]; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT32: { - int32_t* dst = data(); - const int32_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] *= src[i]; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT64: { - int64_t* dst = data(); - const int64_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] *= src[i]; - } - break; - } - default: - break; - } - return *this; - } - Initializer& div(const Initializer& other) { - int64_t n = size(); - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: { - uint16_t* dst = data(); - const uint16_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] = math::floatToHalf(math::halfToFloat(dst[i]) / math::halfToFloat(src[i])); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: { - uint16_t* dst = data(); - const uint16_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] = BFloat16((reinterpret_cast(dst + i))->ToFloat() / (reinterpret_cast(src + i))->ToFloat()).val; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - float* dst = data(); - const float* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] /= src[i]; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - double* dst = data(); - const double* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] /= src[i]; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT32: { - int32_t* dst = data(); - const int32_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] /= src[i]; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT64: { - int64_t* dst = data(); - const int64_t* src = other.data(); - for (int i = 0; i < n; i++) { - dst[i] /= src[i]; - } - break; - } - default: - break; - } - return *this; - } + Initializer& sub(const Initializer& other); + + Initializer& mul(const Initializer& other); - Initializer& sqrt() { - int64_t n = size(); - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: { - uint16_t* dst = data(); - for (int i = 0; i < n; i++) { - dst[i] = math::floatToHalf(std::sqrt(math::halfToFloat(dst[i]))); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: { - uint16_t* dst = data(); - for (int i = 0; i < n; i++) { - dst[i] = BFloat16(std::sqrt((reinterpret_cast(dst + i))->ToFloat())).val; - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - float* dst = data(); - for (int i = 0; i < n; i++) { - dst[i] = std::sqrt(dst[i]); - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - double* dst = data(); - for (int i = 0; i < n; i++) { - dst[i] = std::sqrt(dst[i]); - } - break; - } - default: - break; - } - return *this; - } + Initializer& div(const Initializer& other); - inline void scale_by_axis(const Initializer& other, int axis) { - int64_t num = 1; - for (size_t k = axis; k < dims_.size(); k++) { - num *= dims_[k]; - } + Initializer& sqrt(); - int64_t n = size() / num; - switch (data_type_) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: { - uint16_t* dst = data(); - const uint16_t* src = other.data(); - for (int i = 0; i < n; i++) { - int index = other.size() == 1 ? 0 : i; - for (int64_t j = 0; j < num; j++) { - auto k = i * num + j; - dst[k] = math::floatToHalf(math::halfToFloat(dst[k]) * math::halfToFloat(src[index])); - } - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: { - uint16_t* dst = data(); - const uint16_t* src = other.data(); - for (int i = 0; i < n; i++) { - int index = other.size() == 1 ? 0 : i; - for (int64_t j = 0; j < num; j++) { - auto k = i * num + j; - dst[k] = BFloat16((reinterpret_cast(dst + k))->ToFloat() * (reinterpret_cast(src + index))->ToFloat()).val; - } - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - float* dst = data(); - const float* src = other.data(); - for (int i = 0; i < n; i++) { - int index = other.size() == 1 ? 0 : i; - for (int64_t j = 0; j < num; j++) { - dst[i * num + j] *= src[index]; - } - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: { - double* dst = data(); - const double* src = other.data(); - for (int i = 0; i < n; i++) { - int index = other.size() == 1 ? 0 : i; - for (int64_t j = 0; j < num; j++) { - dst[i * num + j] *= src[index]; - } - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT32: { - int32_t* dst = data(); - const int32_t* src = other.data(); - for (int i = 0; i < n; i++) { - int index = other.size() == 1 ? 0 : i; - for (int64_t j = 0; j < num; j++) { - dst[i * num + j] *= src[index]; - } - } - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT64: { - int64_t* dst = data(); - const int64_t* src = other.data(); - for (int i = 0; i < n; i++) { - int index = other.size() == 1 ? 0 : i; - for (int64_t j = 0; j < num; j++) { - dst[i * num + j] *= src[index]; - } - } - break; - } - default: - break; - } - } + void scale_by_axis(const Initializer& other, int axis); private: -#if !defined(ORT_MINIMAL_BUILD) - static Status ReadExternalRawData( - const ONNX_NAMESPACE::TensorProto& tensor_proto, const Path& model_path, std::vector& raw_data); -#endif - int data_type_; std::string name_; - std::vector dims_; - int64_t size_; - - std::vector raw_data_; - std::vector float_data_; - std::vector float16_data_; - std::vector double_data_; - std::vector int8_data_; - std::vector uint8_data_; - std::vector int32_data_; - std::vector int64_data_; + Tensor data_; }; } // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/qdq_transformer/qdq_util.cc b/onnxruntime/core/optimizer/qdq_transformer/qdq_util.cc index 6297a45c42..d595d9e35e 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/qdq_util.cc +++ b/onnxruntime/core/optimizer/qdq_transformer/qdq_util.cc @@ -54,7 +54,7 @@ bool IsQDQPairSupported( Initializer dq_scale(*dq_scale_tensor_proto, model_path); return q_zp.data_type() == dq_zp.data_type() && - *q_zp.data() == *dq_zp.data() && + *q_zp.raw_data() == *dq_zp.raw_data() && *q_scale.data() == *dq_scale.data(); } diff --git a/onnxruntime/test/framework/data_types_test.cc b/onnxruntime/test/framework/data_types_test.cc index 22cf4b044c..da1a878f60 100644 --- a/onnxruntime/test/framework/data_types_test.cc +++ b/onnxruntime/test/framework/data_types_test.cc @@ -7,6 +7,7 @@ #include "core/common/inlined_containers.h" #include "core/framework/data_types.h" #include "core/framework/data_types_internal.h" +#include "core/framework/float16.h" #include "core/graph/onnx_protobuf.h" #include "gtest/gtest.h" @@ -666,7 +667,7 @@ TEST_F(DataTypeTest, DataUtilsTest) { } } -template +template using Calc = CalculateInlinedVectorDefaultInlinedElements; template @@ -682,11 +683,34 @@ struct TypeMinimunInlinedElements { }; TEST(InlinedVectorTests, TestDefaultInlinedCapacity) { - // We want to test all the type here TypeMinimunInlinedElements sizes; sizes.print(std::cout); - } + +TEST(TypeLiterals, Tests) { + { + // uint16_t test + MLFloat16 mlfloat{static_cast(16)}; + auto mlfloat_literal = 16_f16; + ASSERT_EQ(mlfloat, mlfloat_literal); + + BFloat16 bfloat{static_cast(16), BFloat16::FromBits()}; + auto bfloat_literal = 16_b16; + ASSERT_EQ(bfloat, bfloat_literal); + } + + { + // float + MLFloat16 mlfloat{17.0f}; + auto mlfloat_literal = 17.0_fp16; + ASSERT_EQ(mlfloat, mlfloat_literal); + + BFloat16 bfloat{17.0f}; + auto bfloat_literal = 17.0_bfp16; + ASSERT_EQ(bfloat, bfloat_literal); + } +} + } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/optimizer/graph_transform_test.cc b/onnxruntime/test/optimizer/graph_transform_test.cc index a334e88e79..591470fdd6 100644 --- a/onnxruntime/test/optimizer/graph_transform_test.cc +++ b/onnxruntime/test/optimizer/graph_transform_test.cc @@ -2075,13 +2075,13 @@ TEST_F(GraphTransformationTests, ReluClip11Fusion) { // add initializer for min_input_1 so it's constant TensorProto const_min_1; - Initializer i1(TensorProto_DataType_FLOAT16, "min_input_1", {1}); + Initializer i1(TensorProto_DataType_FLOAT16, "min_input_1", AsSpan({1})); i1.data()->val = math::floatToHalf(-1.f); i1.ToProto(const_min_1); graph.AddInitializedTensor(const_min_1); TensorProto const_min_2; - Initializer i2(TensorProto_DataType_FLOAT, "min_input_2", {1}); + Initializer i2(TensorProto_DataType_FLOAT, "min_input_2", AsSpan({1})); *i2.data() = 1.f; i2.ToProto(const_min_2); graph.AddInitializedTensor(const_min_2); diff --git a/onnxruntime/test/optimizer/initializer_test.cc b/onnxruntime/test/optimizer/initializer_test.cc index 3e9ddad3d6..19c71d4afa 100644 --- a/onnxruntime/test/optimizer/initializer_test.cc +++ b/onnxruntime/test/optimizer/initializer_test.cc @@ -108,28 +108,54 @@ TEST(OptimizerInitializerTest, LoadExternalData) { } template -ONNX_NAMESPACE::TensorProto_DataType GetTensorProtoDataType(); +constexpr ONNX_NAMESPACE::TensorProto_DataType GetTensorProtoDataType(); -#define CppTypeToTensorProto_DataType(CppType, TP_DataType) \ - template <> \ - ONNX_NAMESPACE::TensorProto_DataType GetTensorProtoDataType() { \ - return ONNX_NAMESPACE::TP_DataType; \ +#define CppTypeToTensorProto_DataType(CppType, TP_DataType) \ + template <> \ + constexpr ONNX_NAMESPACE::TensorProto_DataType GetTensorProtoDataType() { \ + return ONNX_NAMESPACE::TP_DataType; \ } -CppTypeToTensorProto_DataType(int8_t, TensorProto_DataType_INT8) -CppTypeToTensorProto_DataType(uint8_t, TensorProto_DataType_UINT8) -CppTypeToTensorProto_DataType(int32_t, TensorProto_DataType_INT32) -CppTypeToTensorProto_DataType(int64_t, TensorProto_DataType_INT64) -CppTypeToTensorProto_DataType(uint16_t, TensorProto_DataType_FLOAT16) -CppTypeToTensorProto_DataType(float, TensorProto_DataType_FLOAT) -CppTypeToTensorProto_DataType(double, TensorProto_DataType_DOUBLE) +CppTypeToTensorProto_DataType(int8_t, TensorProto_DataType_INT8); +CppTypeToTensorProto_DataType(uint8_t, TensorProto_DataType_UINT8); +CppTypeToTensorProto_DataType(int32_t, TensorProto_DataType_INT32); +CppTypeToTensorProto_DataType(int64_t, TensorProto_DataType_INT64); +CppTypeToTensorProto_DataType(MLFloat16, TensorProto_DataType_FLOAT16); +CppTypeToTensorProto_DataType(BFloat16, TensorProto_DataType_BFLOAT16); +CppTypeToTensorProto_DataType(float, TensorProto_DataType_FLOAT); +CppTypeToTensorProto_DataType(double, TensorProto_DataType_DOUBLE); template -void TestInitializerRawData() { +std::vector GetInitializerData() { std::vector data{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + return data; +} + +template <> +std::vector GetInitializerData() { + std::vector data{ + 0_f16, 1_f16, 2_f16, 3_f16, + 4_f16, 5_f16, 6_f16, 7_f16, + 8_f16, 9_f16, 10_f16, 11_f16}; + return data; +} + +template <> +std::vector GetInitializerData() { + std::vector data{ + 0_b16, 1_b16, 2_b16, 3_b16, + 4_b16, 5_b16, 6_b16, 7_b16, + 8_b16, 9_b16, 10_b16, 11_b16}; + return data; +} + + +template +void TestInitializerRawData() { + std::vector data = GetInitializerData(); ONNX_NAMESPACE::TensorProto tensor_proto; tensor_proto.set_data_type(GetTensorProtoDataType()); @@ -138,7 +164,7 @@ void TestInitializerRawData() { tensor_proto.add_dims(4); tensor_proto.set_raw_data(data.data(), data.size() * sizeof(T)); - Initializer init(tensor_proto, Path()); + const Initializer init(tensor_proto, Path()); for (size_t idx = 0; idx < data.size(); idx++) { EXPECT_EQ(data[idx], init.data()[idx]); @@ -150,36 +176,51 @@ TEST(OptimizerInitializerTest, RawData) { TestInitializerRawData(); TestInitializerRawData(); TestInitializerRawData(); - TestInitializerRawData(); + TestInitializerRawData(); + TestInitializerRawData(); TestInitializerRawData(); TestInitializerRawData(); } template -void TestInitializerDataField() { - std::vector data{ - 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11}; +void AddData(const std::vector& data, size_t idx, ONNX_NAMESPACE::TensorProto& tensor_proto) { + tensor_proto.add_int32_data(data[idx]); +} + +template <> +void AddData(const std::vector& data, size_t idx, ONNX_NAMESPACE::TensorProto& tensor_proto) { + tensor_proto.add_int32_data(data[idx].val); +} + +template <> +void AddData(const std::vector& data, size_t idx, ONNX_NAMESPACE::TensorProto& tensor_proto) { + tensor_proto.add_int32_data(data[idx].val); +} + + +template +void TestInitializerDataField() { + constexpr auto dt = GetTensorProtoDataType(); + static_assert((dt == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_INT8 || + dt == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_UINT8 || + dt == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_INT32 || + dt == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT16 || + dt == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_BFLOAT16), + "tensor type is not supported"); + + const std::vector data = GetInitializerData(); - auto dt = GetTensorProtoDataType(); ONNX_NAMESPACE::TensorProto tensor_proto; tensor_proto.set_data_type(GetTensorProtoDataType()); tensor_proto.set_name("OptimizerInitializerTest_DataField"); tensor_proto.add_dims(3); tensor_proto.add_dims(4); + for (size_t idx = 0; idx < data.size(); idx++) { - if (dt == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_INT8 || - dt == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_UINT8 || - dt == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_INT32 || - dt == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT16) { - tensor_proto.add_int32_data(data[idx]); - } else { - ORT_NOT_IMPLEMENTED("tensor type ", GetTensorProtoDataType(), " is not supported"); - } + AddData(data, idx, tensor_proto); } - Initializer init(tensor_proto, Path()); + const Initializer init(tensor_proto, Path()); for (size_t idx = 0; idx < data.size(); idx++) { EXPECT_EQ(data[idx], init.data()[idx]); @@ -203,7 +244,7 @@ void TestInitializerDataField() { tensor_proto.add_##type##_data(data[idx]); \ } \ \ - Initializer init(tensor_proto, Path()); \ + const Initializer init(tensor_proto, Path()); \ \ for (size_t idx = 0; idx < data.size(); idx++) { \ EXPECT_EQ(data[idx], init.data()[idx]); \ @@ -211,16 +252,17 @@ void TestInitializerDataField() { } typedef int64_t int64; -TestInitializerDataFieldSpecialized(float) -TestInitializerDataFieldSpecialized(double) -TestInitializerDataFieldSpecialized(int64) +TestInitializerDataFieldSpecialized(float); +TestInitializerDataFieldSpecialized(double); +TestInitializerDataFieldSpecialized(int64); TEST(OptimizerInitializerTest, DataField) { TestInitializerDataField(); TestInitializerDataField(); TestInitializerDataField(); TestInitializerDataField(); - TestInitializerDataField(); + TestInitializerDataField(); + TestInitializerDataField(); TestInitializerDataField(); TestInitializerDataField(); }