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 ...@@ -40,20 +40,36 @@ namespace ngraph
std::shared_ptr<ngraph::Node> y_scale = inputs.at(1); std::shared_ptr<ngraph::Node> y_scale = inputs.at(1);
std::shared_ptr<ngraph::Node> y_zero_point = inputs.at(2); 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_scale_shape = y_scale->get_shape();
Shape y_zero_point_shape = y_zero_point->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>( return {std::make_shared<ngraph::op::Quantize>(
x, x,
y_scale, y_scale,
y_zero_point, y_zero_point,
y_zero_point->get_element_type(), y_zero_point->get_element_type(),
AxisSet{}, axes,
ngraph::op::Quantize::RoundMode::ROUND_NEAREST_TOWARD_EVEN)}; ngraph::op::Quantize::RoundMode::ROUND_NEAREST_TOWARD_EVEN)};
} }
......
...@@ -116,6 +116,9 @@ pad_reflect_2d_with_neg ...@@ -116,6 +116,9 @@ pad_reflect_2d_with_neg
# Quantized operators are not supported on gpu backend # Quantized operators are not supported on gpu backend
model_dequantize_linear model_dequantize_linear
model_quantize_linear model_quantize_linear
model_quantize_linear_zero_point
quantize_linear_axis_zero
model_quantize_linear_axis_negative
model_quant_conv_linear model_quant_conv_linear
# This should be implemented # This should be implemented
......
...@@ -69,5 +69,5 @@ graph { ...@@ -69,5 +69,5 @@ graph {
} }
} }
opset_import { 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) ...@@ -2325,7 +2325,7 @@ NGRAPH_TEST(onnx_${BACKEND_NAME}, model_lstm_fwd_mixed_seq)
NGRAPH_TEST(onnx_${BACKEND_NAME}, model_quantize_linear) NGRAPH_TEST(onnx_${BACKEND_NAME}, model_quantize_linear)
{ {
auto function = onnx_import::import_onnx_model( 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 inputs;
inputs.emplace_back(std::vector<float>{32.25f, 48.34f, 50.f, 83.f}); 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) ...@@ -2339,6 +2339,70 @@ NGRAPH_TEST(onnx_${BACKEND_NAME}, model_quantize_linear)
EXPECT_TRUE(test::all_close(expected_output.front(), outputs.front())); 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) NGRAPH_TEST(onnx_${BACKEND_NAME}, model_dequantize_linear)
{ {
auto function = onnx_import::import_onnx_model( auto function = onnx_import::import_onnx_model(
......
...@@ -129,27 +129,43 @@ void init_real_tv(ngraph::runtime::Tensor* tv, std::default_random_engine& engin ...@@ -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); 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>> std::vector<std::shared_ptr<ngraph::runtime::Tensor>>
prepare_and_run(const std::shared_ptr<ngraph::Function>& function, 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) const std::string& backend_id)
{ {
auto backend = ngraph::runtime::Backend::create(backend_id); auto backend = ngraph::runtime::Backend::create(backend_id);
auto parms = function->get_parameters(); 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"); throw ngraph::ngraph_error("number of parameters and arguments don't match");
} }
std::vector<std::shared_ptr<ngraph::runtime::Tensor>> arg_tensors(args.size()); std::vector<std::shared_ptr<ngraph::runtime::Tensor>> arg_tensors(t1args.size() +
for (size_t i = 0; i < args.size(); i++) 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()); auto t = backend->create_tensor(parms.at(total_arg_count)->get_element_type(),
copy_data(t, args.at(i)); parms.at(total_arg_count)->get_shape());
arg_tensors.at(i) = t; 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(); auto results = function->get_results();
...@@ -163,25 +179,46 @@ std::vector<std::shared_ptr<ngraph::runtime::Tensor>> ...@@ -163,25 +179,46 @@ std::vector<std::shared_ptr<ngraph::runtime::Tensor>>
auto handle = backend->compile(function); auto handle = backend->compile(function);
handle->call_with_validate(result_tensors, arg_tensors); handle->call_with_validate(result_tensors, arg_tensors);
return result_tensors; return result_tensors;
} }
template <typename T, typename T1 = T> template <typename T>
std::vector<std::vector<T1>> execute(const std::shared_ptr<ngraph::Function>& function, std::vector<std::shared_ptr<ngraph::runtime::Tensor>>
std::vector<std::vector<T>> args, prepare_and_run(const std::shared_ptr<ngraph::Function>& function,
const std::string& backend_id) 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 = 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) for (auto rt : result_tensors)
{ {
result_vectors.push_back(read_vector<T1>(rt)); result_vectors.push_back(read_vector<TOUT>(rt));
} }
return result_vectors; 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> template <typename T>
std::string std::string
get_results_str(std::vector<T>& ref_data, std::vector<T>& actual_data, size_t max_results = 16) 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