Commit 7d69434a authored by Michał Karzyński's avatar Michał Karzyński Committed by Scott Cyphers

[ONNX] Unit tests for QuantizeLinear (#2690)

* [ONNX] Unit tests for QuantizeLinear

* Fix some syntax issues

* get tests passing

* adding prototxt files with correct names

* disable new tests in the GPU

* cleanup

* style
parent 6c8284a3
......@@ -40,20 +40,36 @@ namespace ngraph
std::shared_ptr<ngraph::Node> y_scale = inputs.at(1);
std::shared_ptr<ngraph::Node> y_zero_point = inputs.at(2);
// get axis twice with two default values to see if it is set
int64_t axis_0{node.get_attribute_value<int64_t>("axis", 0)};
int64_t axis_1{node.get_attribute_value<int64_t>("axis", 1)};
AxisSet axes;
// if axis attribute is set
if (axis_0 == axis_1)
{
// positive axis
if (axis_0 >= 0)
{
axes.insert(axis_0);
}
// negative axis
else if (axis_0 < 0)
{
axes.insert(x->get_shape().size() + axis_0);
}
}
Shape y_scale_shape = y_scale->get_shape();
Shape y_zero_point_shape = y_zero_point->get_shape();
ASSERT_VALID_ARGUMENT(node, y_scale_shape.size() == 0)
<< "y_scale must be a scalar.";
ASSERT_VALID_ARGUMENT(node, y_zero_point_shape.size() == 0)
<< "y_zero_point must be a scalar.";
return {std::make_shared<ngraph::op::Quantize>(
x,
y_scale,
y_zero_point,
y_zero_point->get_element_type(),
AxisSet{},
axes,
ngraph::op::Quantize::RoundMode::ROUND_NEAREST_TOWARD_EVEN)};
}
......
......@@ -116,6 +116,9 @@ pad_reflect_2d_with_neg
# Quantized operators are not supported on gpu backend
model_dequantize_linear
model_quantize_linear
model_quantize_linear_zero_point
quantize_linear_axis_zero
model_quantize_linear_axis_negative
model_quant_conv_linear
# This should be implemented
......
......@@ -69,5 +69,5 @@ graph {
}
}
opset_import {
version: 4
version: 10
}
ir_version: 3
producer_name: "ngraph ONNXImporter"
graph {
node {
input: "X"
input: "scale"
input: "zero_point"
output: "Y"
name: "node1"
op_type: "QuantizeLinear"
attribute {
name: "axis"
i: -2
type: INT
}
}
name: "test"
input {
name: "X"
type {
tensor_type {
elem_type: 1
shape {
dim {
dim_value: 3
}
dim {
dim_value: 4
}
}
}
}
}
input {
name: "scale"
type {
tensor_type {
elem_type: 1
shape {
dim {
dim_value: 3
}
}
}
}
}
input {
name: "zero_point"
type {
tensor_type {
elem_type: 2
shape {
dim {
dim_value: 3
}
}
}
}
}
output {
name: "Y"
type {
tensor_type {
elem_type: 2
shape {
dim {
dim_value: 3
}
dim {
dim_value: 4
}
}
}
}
}
}
opset_import {
version: 10
}
ir_version: 3
producer_name: "ngraph ONNXImporter"
graph {
node {
input: "X"
input: "scale"
input: "zero_point"
output: "Y"
name: "node1"
op_type: "QuantizeLinear"
attribute {
name: "axis"
i: 0
type: INT
}
}
name: "test"
input {
name: "X"
type {
tensor_type {
elem_type: 1
shape {
dim {
dim_value: 3
}
dim {
dim_value: 4
}
}
}
}
}
input {
name: "scale"
type {
tensor_type {
elem_type: 1
shape {
dim {
dim_value: 3
}
}
}
}
}
input {
name: "zero_point"
type {
tensor_type {
elem_type: 2
shape {
dim {
dim_value: 3
}
}
}
}
}
output {
name: "Y"
type {
tensor_type {
elem_type: 2
shape {
dim {
dim_value: 3
}
dim {
dim_value: 4
}
}
}
}
}
}
opset_import {
version: 10
}
ir_version: 3
producer_name: "ngraph ONNXImporter"
graph {
node {
input: "x"
input: "y_scale"
input: "y_zero_point"
output: "y"
name: "node1"
op_type: "QuantizeLinear"
}
name: "test"
input {
name: "x"
type {
tensor_type {
elem_type: 1
shape {
dim {
dim_value: 6
}
}
}
}
}
input {
name: "y_scale"
type {
tensor_type {
elem_type: 1
shape {
}
}
}
}
input {
name: "y_zero_point"
type {
tensor_type {
elem_type: 2
shape {
}
}
}
}
output {
name: "y"
type {
tensor_type {
elem_type: 2
shape {
dim {
dim_value: 6
}
}
}
}
}
}
opset_import {
version: 10
}
......@@ -2325,7 +2325,7 @@ NGRAPH_TEST(onnx_${BACKEND_NAME}, model_lstm_fwd_mixed_seq)
NGRAPH_TEST(onnx_${BACKEND_NAME}, model_quantize_linear)
{
auto function = onnx_import::import_onnx_model(
file_util::path_join(SERIALIZED_ZOO, "onnx/quant_lin.prototxt"));
file_util::path_join(SERIALIZED_ZOO, "onnx/quantize_linear.prototxt"));
Inputs inputs;
inputs.emplace_back(std::vector<float>{32.25f, 48.34f, 50.f, 83.f});
......@@ -2339,6 +2339,70 @@ NGRAPH_TEST(onnx_${BACKEND_NAME}, model_quantize_linear)
EXPECT_TRUE(test::all_close(expected_output.front(), outputs.front()));
}
NGRAPH_TEST(onnx_${BACKEND_NAME}, model_quantize_linear_zero_point)
{
auto function = onnx_import::import_onnx_model(
file_util::path_join(SERIALIZED_ZOO, "onnx/quantize_linear_zero_point.prototxt"));
Inputs inputs;
inputs.emplace_back(std::vector<float>{0.f, 2.f, 3.f, 1000.f, -254.f, -1000.f}); // x
inputs.emplace_back(std::vector<float>{2.0f}); // y_scale
std::vector<std::vector<std::uint8_t>> int_inputs;
int_inputs.emplace_back(std::vector<std::uint8_t>{128}); // y_zero_point
std::vector<std::vector<std::uint8_t>> expected_output{
std::vector<std::uint8_t>{128, 129, 130, 255, 1, 0}};
std::vector<std::vector<std::uint8_t>> outputs{execute<float, std::uint8_t, std::uint8_t>(
function, inputs, int_inputs, "${BACKEND_NAME}")};
EXPECT_TRUE(test::all_close(expected_output.front(), outputs.front()));
}
NGRAPH_TEST(onnx_${BACKEND_NAME}, quantize_linear_axis_zero)
{
auto function = onnx_import::import_onnx_model(
file_util::path_join(SERIALIZED_ZOO, "onnx/quantize_linear_axis_zero.prototxt"));
Inputs inputs;
inputs.emplace_back(std::vector<float>{
0.f, 2.f, 3.f, 1000.f, 0.f, 2.f, 3.f, 1000.f, 0.f, 2.f, 3.f, 1000.f}); // x
inputs.emplace_back(std::vector<float>{1.f, 2.f, 4.f}); // y_scale
std::vector<std::vector<std::uint8_t>> int_inputs;
int_inputs.emplace_back(std::vector<std::uint8_t>{0, 0, 0}); // y_zero_point
std::vector<std::vector<std::uint8_t>> expected_output{
// std::vector<std::uint8_t>{0, 2, 3, 255, 0, 1, 2, 255, 0, 1, 1, 250}}; <- bad expected output given HALF_TO_EVEN round mode
std::vector<std::uint8_t>{0, 2, 3, 255, 0, 1, 2, 255, 0, 0, 1, 250}};
std::vector<std::vector<std::uint8_t>> outputs{execute<float, std::uint8_t, std::uint8_t>(
function, inputs, int_inputs, "${BACKEND_NAME}")};
EXPECT_EQ(expected_output.front(), outputs.front());
}
NGRAPH_TEST(onnx_${BACKEND_NAME}, model_quantize_linear_axis_negative)
{
auto function = onnx_import::import_onnx_model(
file_util::path_join(SERIALIZED_ZOO, "onnx/quantize_linear_axis_negative.prototxt"));
Inputs inputs;
inputs.emplace_back(std::vector<float>{
0.f, 2.f, 3.f, 1000.f, 0.f, 2.f, 3.f, 1000.f, 0.f, 2.f, 3.f, 1000.f}); // x
inputs.emplace_back(std::vector<float>{1.f, 2.f, 4.f}); // y_scale
std::vector<std::vector<std::uint8_t>> int_inputs;
int_inputs.emplace_back(std::vector<std::uint8_t>{0, 0, 0}); // y_zero_point
std::vector<std::vector<std::uint8_t>> expected_output{
// std::vector<std::uint8_t>{0, 2, 3, 255, 0, 1, 2, 255, 0, 1, 1, 250}}; <- bad expected output given HALF_TO_EVEN round mode
std::vector<std::uint8_t>{0, 2, 3, 255, 0, 1, 2, 255, 0, 0, 1, 250}};
std::vector<std::vector<std::uint8_t>> outputs{execute<float, std::uint8_t, std::uint8_t>(
function, inputs, int_inputs, "${BACKEND_NAME}")};
EXPECT_TRUE(test::all_close(expected_output.front(), outputs.front()));
}
NGRAPH_TEST(onnx_${BACKEND_NAME}, model_dequantize_linear)
{
auto function = onnx_import::import_onnx_model(
......
......@@ -129,27 +129,43 @@ void init_real_tv(ngraph::runtime::Tensor* tv, std::default_random_engine& engin
void random_init(ngraph::runtime::Tensor* tv, std::default_random_engine& engine);
template <typename T>
template <typename T1, typename T2>
std::vector<std::shared_ptr<ngraph::runtime::Tensor>>
prepare_and_run(const std::shared_ptr<ngraph::Function>& function,
std::vector<std::vector<T>> args,
std::vector<std::vector<T1>> t1args,
std::vector<std::vector<T2>> t2args,
const std::string& backend_id)
{
auto backend = ngraph::runtime::Backend::create(backend_id);
auto parms = function->get_parameters();
if (parms.size() != args.size())
if (parms.size() != t1args.size() + t2args.size())
{
throw ngraph::ngraph_error("number of parameters and arguments don't match");
}
std::vector<std::shared_ptr<ngraph::runtime::Tensor>> arg_tensors(args.size());
for (size_t i = 0; i < args.size(); i++)
std::vector<std::shared_ptr<ngraph::runtime::Tensor>> arg_tensors(t1args.size() +
t2args.size());
size_t total_arg_count = 0;
for (size_t i = 0; i < t1args.size(); i++)
{
auto t = backend->create_tensor(parms.at(i)->get_element_type(), parms.at(i)->get_shape());
copy_data(t, args.at(i));
arg_tensors.at(i) = t;
auto t = backend->create_tensor(parms.at(total_arg_count)->get_element_type(),
parms.at(total_arg_count)->get_shape());
auto x = t1args.at(i);
copy_data(t, x);
arg_tensors.at(total_arg_count) = t;
total_arg_count++;
}
for (size_t i = 0; i < t2args.size(); i++)
{
auto t = backend->create_tensor(parms.at(total_arg_count)->get_element_type(),
parms.at(total_arg_count)->get_shape());
copy_data(t, t2args.at(i));
arg_tensors.at(total_arg_count) = t;
total_arg_count++;
}
auto results = function->get_results();
......@@ -163,25 +179,46 @@ std::vector<std::shared_ptr<ngraph::runtime::Tensor>>
auto handle = backend->compile(function);
handle->call_with_validate(result_tensors, arg_tensors);
return result_tensors;
}
template <typename T, typename T1 = T>
std::vector<std::vector<T1>> execute(const std::shared_ptr<ngraph::Function>& function,
std::vector<std::vector<T>> args,
const std::string& backend_id)
template <typename T>
std::vector<std::shared_ptr<ngraph::runtime::Tensor>>
prepare_and_run(const std::shared_ptr<ngraph::Function>& function,
std::vector<std::vector<T>> args,
const std::string& backend_id)
{
std::vector<std::vector<T>> emptyargs;
return prepare_and_run<T, T>(function, args, emptyargs, backend_id);
}
template <typename TIN1, typename TIN2, typename TOUT>
std::vector<std::vector<TOUT>> execute(const std::shared_ptr<ngraph::Function>& function,
std::vector<std::vector<TIN1>> t1args,
std::vector<std::vector<TIN2>> t2args,
const std::string& backend_id)
{
std::vector<std::shared_ptr<ngraph::runtime::Tensor>> result_tensors =
prepare_and_run(function, args, backend_id);
prepare_and_run(function, t1args, t2args, backend_id);
std::vector<std::vector<T1>> result_vectors;
std::vector<std::vector<TOUT>> result_vectors;
for (auto rt : result_tensors)
{
result_vectors.push_back(read_vector<T1>(rt));
result_vectors.push_back(read_vector<TOUT>(rt));
}
return result_vectors;
}
template <typename TIN, typename TOUT = TIN>
std::vector<std::vector<TOUT>> execute(const std::shared_ptr<ngraph::Function>& function,
std::vector<std::vector<TIN>> args,
const std::string& backend_id)
{
std::vector<std::vector<TIN>> emptyargs;
return execute<TIN, TIN, TOUT>(function, args, emptyargs, backend_id);
}
template <typename T>
std::string
get_results_str(std::vector<T>& ref_data, std::vector<T>& actual_data, size_t max_results = 16)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment