onnxruntime/onnxruntime/test/framework/tensorutils_test.cc
Scott McKay ace741680d
Constant-12 support (#3304)
1. Support the new fields for Constant in opset 12
2. Support SparseTensor in the Constant node by converting to dense tensor when lifting the Constant to an initializer. Will make a model with a sparse tensor in a Constant work but isn't an overly efficient approach.
2020-03-30 23:13:52 -07:00

178 lines
6.1 KiB
C++

// 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 <typename T>
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<float>(TensorProto_DataType_FLOAT);
test_unpack_float_tensor<double>(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 <typename T>
static std::vector<T> CreateValues() {
return {1, 2, 3, 4};
}
template <>
std::vector<std::string> CreateValues<std::string>() {
return {"one", "two", "three", "four"};
}
template <typename T>
static NodeProto CreateConstantNode(const std::string& attrib_name, AttributeProto_AttributeType type,
std::function<void(AttributeProto&)> 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 <typename T>
static void TestConstantNodeConversion(const std::string& attrib_name,
AttributeProto_AttributeType type,
std::function<void(AttributeProto&, const std::vector<T>& data)> add_data,
std::function<std::vector<T>(const TensorProto&)> get_data,
int64_t num_elements) {
auto input = CreateValues<T>();
if (num_elements == -1) {
num_elements = static_cast<int64_t>(input.size());
} else {
input.resize(num_elements);
}
auto c = CreateConstantNode<T>(
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<float>(
"value_float", AttributeProto_AttributeType_FLOAT,
[](AttributeProto& attrib, const std::vector<float>& data) { attrib.set_f(data[0]); },
[](const TensorProto& tp) {
return std::vector<float>(tp.float_data().cbegin(), tp.float_data().cend());
},
1);
TestConstantNodeConversion<float>(
"value_floats", AttributeProto_AttributeType_FLOATS,
[](AttributeProto& attrib, const std::vector<float>& data) {
*attrib.mutable_floats() = {data.cbegin(), data.cend()};
},
[](const TensorProto& tp) {
return std::vector<float>(tp.float_data().cbegin(), tp.float_data().cend());
},
-1);
TestConstantNodeConversion<int64_t>(
"value_int", AttributeProto_AttributeType_INT,
[](AttributeProto& attrib, const std::vector<int64_t>& data) { attrib.set_i(data[0]); },
[](const TensorProto& tp) {
return std::vector<int64_t>(tp.int64_data().cbegin(), tp.int64_data().cend());
},
1);
TestConstantNodeConversion<int64_t>(
"value_ints", AttributeProto_AttributeType_INTS,
[](AttributeProto& attrib, const std::vector<int64_t>& data) {
*attrib.mutable_ints() = {data.cbegin(), data.cend()};
},
[](const TensorProto& tp) {
return std::vector<int64_t>(tp.int64_data().cbegin(), tp.int64_data().cend());
},
-1);
TestConstantNodeConversion<std::string>(
"value_string", AttributeProto_AttributeType_STRING,
[](AttributeProto& attrib, const std::vector<std::string>& data) { attrib.set_s(data[0]); },
[](const TensorProto& tp) {
return std::vector<std::string>(tp.string_data().cbegin(), tp.string_data().cend());
},
1);
TestConstantNodeConversion<std::string>(
"value_strings", AttributeProto_AttributeType_STRINGS,
[](AttributeProto& attrib, const std::vector<std::string>& data) {
// for (const auto& s : data)
*attrib.mutable_strings() = {data.cbegin(), data.cend()};
},
[](const TensorProto& tp) {
return std::vector<std::string>(tp.string_data().cbegin(), tp.string_data().cend());
},
-1);
// sparse_tensor is covered by SparseTensorConversionTests.TestConstantNodeConversion
}
} // namespace test
} // namespace onnxruntime