// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "core/framework/tensorprotoutils.h" #include "core/graph/onnx_protobuf.h" #include "test/util/include/asserts.h" #include "gtest/gtest.h" #include "gmock/gmock.h" using namespace ::onnxruntime::utils; using namespace ONNX_NAMESPACE; namespace onnxruntime { namespace test { //T must be float for double, and it must match with the 'type' argument template void test_unpack_float_tensor(TensorProto_DataType type) { TensorProto float_tensor_proto; float_tensor_proto.set_data_type(type); T f[4] = {1.1f, 2.2f, 3.3f, 4.4f}; const size_t len = sizeof(T) * 4; char rawdata[len]; for (int i = 0; i < 4; ++i) { memcpy(rawdata + i * sizeof(T), &(f[i]), sizeof(T)); } float_tensor_proto.set_raw_data(rawdata, len); T float_data2[4]; auto status = UnpackTensor(float_tensor_proto, float_data2, 4); EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); EXPECT_EQ(1.1f, float_data2[0]); EXPECT_EQ(2.2f, float_data2[1]); EXPECT_EQ(3.3f, float_data2[2]); EXPECT_EQ(4.4f, float_data2[3]); } TEST(TensorParseTest, TensorUtilsTest) { TensorProto bool_tensor_proto; bool_tensor_proto.set_data_type(TensorProto_DataType_BOOL); bool_tensor_proto.add_int32_data(1); bool bool_data[1]; auto status = UnpackTensor(bool_tensor_proto, bool_data, 1); EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); EXPECT_TRUE(bool_data[0]); float float_data[1]; status = UnpackTensor(bool_tensor_proto, float_data, 1); EXPECT_FALSE(status.IsOK()); test_unpack_float_tensor(TensorProto_DataType_FLOAT); test_unpack_float_tensor(TensorProto_DataType_DOUBLE); TensorProto string_tensor_proto; string_tensor_proto.set_data_type(TensorProto_DataType_STRING); string_tensor_proto.add_string_data("a"); string_tensor_proto.add_string_data("b"); std::string string_data[2]; status = UnpackTensor(string_tensor_proto, string_data, 2); EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); EXPECT_EQ("a", string_data[0]); EXPECT_EQ("b", string_data[1]); status = UnpackTensor(bool_tensor_proto, string_data, 2); EXPECT_FALSE(status.IsOK()); } template static std::vector CreateValues() { return {1, 2, 3, 4}; } template <> std::vector CreateValues() { return {"one", "two", "three", "four"}; } template static NodeProto CreateConstantNode(const std::string& attrib_name, AttributeProto_AttributeType type, std::function add_data) { NodeProto constant_node; constant_node.set_op_type("Constant"); constant_node.add_output("Constant_output"); AttributeProto& attrib = *constant_node.mutable_attribute()->Add(); attrib.set_name(attrib_name); attrib.set_type(type); add_data(attrib); return constant_node; } template static void TestConstantNodeConversion(const std::string& attrib_name, AttributeProto_AttributeType type, std::function& data)> add_data, std::function(const TensorProto&)> get_data, int64_t num_elements) { auto input = CreateValues(); if (num_elements == -1) { num_elements = static_cast(input.size()); } else { input.resize(num_elements); } auto c = CreateConstantNode( attrib_name, type, [&input, &add_data](AttributeProto& attrib) { add_data(attrib, input); }); TensorProto tp; EXPECT_STATUS_OK(utils::ConstantNodeProtoToTensorProto(c, tp)); EXPECT_THAT(get_data(tp), ::testing::ContainerEq(input)); } TEST(TensorProtoUtilsTest, ConstantTensorProto) { TestConstantNodeConversion( "value_float", AttributeProto_AttributeType_FLOAT, [](AttributeProto& attrib, const std::vector& data) { attrib.set_f(data[0]); }, [](const TensorProto& tp) { return std::vector(tp.float_data().cbegin(), tp.float_data().cend()); }, 1); TestConstantNodeConversion( "value_floats", AttributeProto_AttributeType_FLOATS, [](AttributeProto& attrib, const std::vector& data) { *attrib.mutable_floats() = {data.cbegin(), data.cend()}; }, [](const TensorProto& tp) { return std::vector(tp.float_data().cbegin(), tp.float_data().cend()); }, -1); TestConstantNodeConversion( "value_int", AttributeProto_AttributeType_INT, [](AttributeProto& attrib, const std::vector& data) { attrib.set_i(data[0]); }, [](const TensorProto& tp) { return std::vector(tp.int64_data().cbegin(), tp.int64_data().cend()); }, 1); TestConstantNodeConversion( "value_ints", AttributeProto_AttributeType_INTS, [](AttributeProto& attrib, const std::vector& data) { *attrib.mutable_ints() = {data.cbegin(), data.cend()}; }, [](const TensorProto& tp) { return std::vector(tp.int64_data().cbegin(), tp.int64_data().cend()); }, -1); TestConstantNodeConversion( "value_string", AttributeProto_AttributeType_STRING, [](AttributeProto& attrib, const std::vector& data) { attrib.set_s(data[0]); }, [](const TensorProto& tp) { return std::vector(tp.string_data().cbegin(), tp.string_data().cend()); }, 1); TestConstantNodeConversion( "value_strings", AttributeProto_AttributeType_STRINGS, [](AttributeProto& attrib, const std::vector& data) { // for (const auto& s : data) *attrib.mutable_strings() = {data.cbegin(), data.cend()}; }, [](const TensorProto& tp) { return std::vector(tp.string_data().cbegin(), tp.string_data().cend()); }, -1); // sparse_tensor is covered by SparseTensorConversionTests.TestConstantNodeConversion } } // namespace test } // namespace onnxruntime