Commit c75f7db3 authored by nishant.b.patel's avatar nishant.b.patel

Move quantized conv tests from test/builder to test/backend

parent baf1cb00
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include "ngraph/op/passthrough.hpp" #include "ngraph/op/passthrough.hpp"
#include "ngraph/op/product.hpp" #include "ngraph/op/product.hpp"
#include "ngraph/op/quantize.hpp" #include "ngraph/op/quantize.hpp"
#include "ngraph/op/quantized_convolution.hpp"
#include "ngraph/op/replace_slice.hpp" #include "ngraph/op/replace_slice.hpp"
#include "ngraph/op/reshape.hpp" #include "ngraph/op/reshape.hpp"
#include "ngraph/op/result.hpp" #include "ngraph/op/result.hpp"
...@@ -1134,12 +1135,75 @@ private: ...@@ -1134,12 +1135,75 @@ private:
break; break;
} }
case OP_TYPEID::QuantizedConvolution:
{
const op::QuantizedConvolution* qc =
static_cast<const op::QuantizedConvolution*>(&node);
auto input_element_type = qc->get_input_element_type(0);
auto filter_element_type = qc->get_input_element_type(1);
auto output_element_type = qc->get_output_element_type(0);
if (input_element_type == element::u8 && filter_element_type == element::i8 &&
output_element_type == element::i8)
{
reference::convolution<uint8_t, int8_t, int8_t, int32_t>(
args[0]->get_data_ptr<const uint8_t>(),
args[1]->get_data_ptr<const int8_t>(),
out[0]->get_data_ptr<int8_t>(),
node.get_input_shape(0),
node.get_input_shape(1),
node.get_output_shape(0),
qc->get_window_movement_strides(),
qc->get_window_dilation_strides(),
qc->get_padding_below(),
qc->get_padding_above(),
qc->get_data_dilation_strides(),
args[2]->get_data_ptr<const float>(),
args[3]->get_data_ptr<const uint8_t>(),
args[4]->get_data_ptr<const float>(),
args[5]->get_data_ptr<const int8_t>(),
args[6]->get_data_ptr<const float>(),
args[7]->get_data_ptr<const int8_t>());
}
else if (input_element_type == element::u8 && filter_element_type == element::u8 &&
output_element_type == element::u8)
{
reference::convolution<uint8_t, uint8_t, uint8_t, int32_t>(
args[0]->get_data_ptr<const uint8_t>(),
args[1]->get_data_ptr<const uint8_t>(),
out[0]->get_data_ptr<uint8_t>(),
node.get_input_shape(0),
node.get_input_shape(1),
node.get_output_shape(0),
qc->get_window_movement_strides(),
qc->get_window_dilation_strides(),
qc->get_padding_below(),
qc->get_padding_above(),
qc->get_data_dilation_strides(),
args[2]->get_data_ptr<const float>(),
args[3]->get_data_ptr<const uint8_t>(),
args[4]->get_data_ptr<const float>(),
args[5]->get_data_ptr<const uint8_t>(),
args[6]->get_data_ptr<const float>(),
args[7]->get_data_ptr<const uint8_t>());
}
else
{
std::stringstream ss;
ss << "unsupported element type";
throw std::runtime_error(ss.str());
}
break;
}
case OP_TYPEID::QuantizedAvgPool: case OP_TYPEID::QuantizedAvgPool:
case OP_TYPEID::QuantizedConvolutionBias: case OP_TYPEID::QuantizedConvolutionBias:
case OP_TYPEID::QuantizedConvolutionBiasAdd: case OP_TYPEID::QuantizedConvolutionBiasAdd:
case OP_TYPEID::QuantizedConvolutionBiasSignedAdd: case OP_TYPEID::QuantizedConvolutionBiasSignedAdd:
case OP_TYPEID::QuantizedConvolutionRelu: case OP_TYPEID::QuantizedConvolutionRelu:
case OP_TYPEID::QuantizedConvolution:
case OP_TYPEID::QuantizedMaxPool: case OP_TYPEID::QuantizedMaxPool:
case OP_TYPEID::QuantizedDotBias: case OP_TYPEID::QuantizedDotBias:
case OP_TYPEID::QuantizedDot: case OP_TYPEID::QuantizedDot:
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "ngraph/autodiff/adjoints.hpp" #include "ngraph/autodiff/adjoints.hpp"
#include "ngraph/builder/quantized_conv_builder.hpp"
#include "ngraph/graph_util.hpp" #include "ngraph/graph_util.hpp"
#include "ngraph/log.hpp" #include "ngraph/log.hpp"
#include "ngraph/ngraph.hpp" #include "ngraph/ngraph.hpp"
...@@ -7489,3 +7490,183 @@ NGRAPH_TEST(${BACKEND_NAME}, validate_function_for_dynamic_shape) ...@@ -7489,3 +7490,183 @@ NGRAPH_TEST(${BACKEND_NAME}, validate_function_for_dynamic_shape)
EXPECT_EQ(true, make_function(true)->is_dynamic()); EXPECT_EQ(true, make_function(true)->is_dynamic());
EXPECT_EQ(false, make_function(false)->is_dynamic()); EXPECT_EQ(false, make_function(false)->is_dynamic());
} }
NGRAPH_TEST(${BACKEND_NAME}, quantized_convolution)
{
Shape shape_a{1, 1, 3, 4};
Shape shape_b{1, 1, 3, 3};
Shape shape_r{1, 1, 3, 4};
vector<uint8_t> a_data = {1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4};
vector<int8_t> b_data = {1, 2, 3, 4, 5, 0, 0, 1, 2};
auto A = make_shared<op::Parameter>(element::u8, shape_a);
auto B = make_shared<op::Parameter>(element::i8, shape_b);
auto C = make_shared<op::Parameter>(element::f32, Shape{1});
auto D = make_shared<op::Parameter>(element::f32, Shape{1});
auto E = make_shared<op::Parameter>(element::f32, Shape{1});
auto F = make_shared<op::Parameter>(element::f32, Shape{1});
auto G = make_shared<op::Parameter>(element::f32, Shape{1});
auto H = make_shared<op::Parameter>(element::f32, Shape{1});
auto CV = ngraph::builder::QuantizedConvolutionBuilder(A,
B,
Strides{1, 1},
Strides{1, 1},
CoordinateDiff{1, 1},
CoordinateDiff{1, 1},
Strides{1, 1},
C,
D,
E,
F,
G,
H,
element::i8,
AxisSet{});
auto f = make_shared<Function>(NodeVector{CV}, ParameterVector{A, B, C, D, E, F, G, H});
auto backend = runtime::Backend::create("${BACKEND_NAME}");
// Create some tensors for input/output
auto a = backend->create_tensor(element::u8, shape_a);
copy_data(a, a_data);
auto b = backend->create_tensor(element::i8, shape_b);
copy_data(b, b_data);
auto d = backend->create_tensor(element::f32, Shape{1});
copy_data(d, vector<float>{0.0f});
auto e = backend->create_tensor(element::f32, Shape{1});
copy_data(e, vector<float>{255.0f});
auto e_a = backend->create_tensor(element::f32, Shape{1});
copy_data(e_a, vector<float>{-127.0f});
auto g = backend->create_tensor(element::f32, Shape{1});
copy_data(g, vector<float>{127.0f});
auto h = backend->create_tensor(element::f32, Shape{1});
copy_data(h, vector<float>{22.0f});
auto i = backend->create_tensor(element::f32, Shape{1});
copy_data(i, vector<float>{90.0f});
auto result = backend->create_tensor(element::i8, shape_r);
auto handle = backend->compile(f);
handle->call_with_validate({result}, {a, b, d, e, e_a, g, h, i});
EXPECT_EQ((vector<int8_t>{31, 48, 42, 45, 54, 102, 127, 61, 47, 73, 61, 55}),
read_vector<int8_t>(result));
}
NGRAPH_TEST(${BACKEND_NAME}, quantized_conv_non_zero_zero_point)
{
Shape shape_a{1, 1, 7, 7}; // input shape
Shape shape_b{1, 1, 1, 1}; // filter shape
Shape shape_r{1, 1, 7, 7};
vector<float> X = {0.45246148109436035f, 0.15498268604278564f, 0.11199361085891724f,
-0.39421093463897705f, 0.2626858949661255f, 0.13414543867111206f,
-0.27184486389160156f, -0.43028733134269714f, -0.26825493574142456f,
0.3893144130706787f, -0.13631996512413025f, -0.009590476751327515f,
-0.48771554231643677f, -0.25256502628326416f, -0.2812897562980652f,
0.4043201804161072f, 0.07795023918151855f, 0.326981782913208f,
0.13114392757415771f, -0.4416425824165344f, 0.12446999549865723f,
0.36739975214004517f, 0.1698915958404541f, 0.2008744478225708f,
0.23339951038360596f, 0.38613730669021606f, 0.11117297410964966f,
0.3877097964286804f, 0.20812749862670898f, -0.34297940135002136f,
-0.029246658086776733f, -0.20483523607254028f, -0.19244328141212463f,
-0.11104947328567505f, -0.32830488681793213f, -0.01800677180290222f,
0.3618946671485901f, -0.40949052572250366f, -0.18248388171195984f,
-0.3349453806877136f, -0.34091079235076904f, 0.006497859954833984f,
0.4537564516067505f, 0.08006560802459717f, -0.14788749814033508f,
0.034442365169525146f, -0.33322954177856445f, 0.06049239635467529f,
0.42619407176971436f};
vector<float> W = {-0.4406261742115021f};
vector<float> expected_vals = {
-0.19936637580394745f, -0.06828942894935608f, -0.04934731498360634f,
0.17369966208934784f, -0.11574628204107285f, -0.05910799279808998f,
0.1197819635272026f, 0.18959586322307587f, 0.1182001456618309f,
-0.17154212296009064f, 0.06006614491343498f, 0.0042258151806890965f,
0.21490024030208588f, 0.11128675937652588f, 0.12394362688064575f,
-0.17815405130386353f, -0.034346915781497955f, -0.14407673478126526f,
-0.05778544768691063f, 0.19459928572177887f, -0.05484473705291748f,
-0.16188594698905945f, -0.07485868036746979f, -0.08851054310798645f,
-0.10284193605184555f, -0.17014220356941223f, -0.04898572340607643f,
-0.17083507776260376f, -0.09170642495155334f, 0.1511256992816925f,
0.012886842712759972f, 0.09025576710700989f, 0.08479554951190948f,
0.0489313043653965f, 0.14465972781181335f, 0.007934254594147205f,
-0.15946026146411896f, 0.1804322451353073f, 0.08040717244148254f,
0.1475857049226761f, 0.15021422505378723f, -0.0028631272725760937f,
-0.19993697106838226f, -0.03527900204062462f, 0.06516310572624207f,
-0.015176207758486271f, 0.14682966470718384f, -0.02665453404188156f,
-0.18779225647449493f};
auto lhs = make_shared<op::Parameter>(element::f32, shape_a);
auto rhs = make_shared<op::Parameter>(element::f32, shape_b);
auto result = make_shared<op::Parameter>(element::f32, shape_r);
AxisSet quantization_axes;
op::Quantize::RoundMode round_mode = op::Quantize::RoundMode::ROUND_NEAREST_TOWARD_EVEN;
auto lhs_scale = op::Constant::create(element::f32, Shape{}, {0.00369205});
auto lhs_zero_point = op::Constant::create(element::u8, Shape{}, {132});
auto rhs_scale = op::Constant::create(element::f32, Shape{}, {0.00172795});
auto rhs_zero_point = op::Constant::create(element::u8, Shape{}, {255});
auto result_scale = op::Constant::create(element::f32, Shape{}, {0.00162681});
auto result_zero_point = op::Constant::create(element::u8, Shape{}, {123});
auto quantize_lhs = make_shared<op::Quantize>(
lhs, lhs_scale, lhs_zero_point, element::u8, quantization_axes, round_mode);
auto quantize_rhs = make_shared<op::Quantize>(
rhs, rhs_scale, rhs_zero_point, element::u8, quantization_axes, round_mode);
auto quantize_result = make_shared<op::Quantize>(
result, result_scale, result_zero_point, element::u8, quantization_axes, round_mode);
auto lhs_f = make_shared<Function>(quantize_lhs, ParameterVector{lhs});
auto rhs_f = make_shared<Function>(quantize_rhs, ParameterVector{rhs});
auto result_f = make_shared<Function>(quantize_result, ParameterVector{result});
auto backend = runtime::Backend::create("${BACKEND_NAME}");
auto lhs_data = backend->create_tensor(element::f32, shape_a);
auto rhs_data = backend->create_tensor(element::f32, shape_b);
auto result_data = backend->create_tensor(element::f32, shape_r);
auto lhs_output = backend->create_tensor(element::u8, shape_a);
auto rhs_output = backend->create_tensor(element::u8, shape_b);
auto result_output = backend->create_tensor(element::u8, shape_r);
copy_data(lhs_data, X);
copy_data(rhs_data, W);
copy_data(result_data, expected_vals);
auto lhs_handle = backend->compile(lhs_f);
auto rhs_handle = backend->compile(rhs_f);
auto result_handle = backend->compile(result_f);
lhs_handle->call_with_validate({lhs_output}, {lhs_data});
rhs_handle->call_with_validate({rhs_output}, {rhs_data});
result_handle->call_with_validate({result_output}, {result_data});
auto A = make_shared<op::Parameter>(element::u8, shape_a);
auto B = make_shared<op::Parameter>(element::u8, shape_b);
auto CV = make_shared<ngraph::op::QuantizedConvolution>(A,
B,
Strides{1, 1}, // move_strides
Strides{1, 1}, // filter_dilation
CoordinateDiff{0, 0}, // below_pads
CoordinateDiff{0, 0}, // above_pads
Strides{1, 1}, // data_dilation
lhs_scale,
lhs_zero_point,
rhs_scale,
rhs_zero_point,
result_scale,
result_zero_point,
element::u8,
AxisSet{});
auto f = make_shared<Function>(NodeVector{CV}, ParameterVector{A, B});
// Create some tensors for input/output
auto a = backend->create_tensor(element::u8, shape_a);
copy_data(a, read_vector<uint8_t>(lhs_output));
auto b = backend->create_tensor(element::u8, shape_b);
copy_data(b, read_vector<uint8_t>(rhs_output));
auto final_result = backend->create_tensor(element::u8, shape_r);
auto handle = backend->compile(f);
handle->call_with_validate({final_result}, {a, b});
for (int i = 0; i < 49; ++i)
{
EXPECT_EQ((read_vector<uint8_t>(result_output))[i], (read_vector<uint8_t>(final_result))[i])
<< "Vectors x and y differ at index " << i;
}
}
...@@ -146,108 +146,6 @@ static void constant_fold(std::shared_ptr<Function> f) ...@@ -146,108 +146,6 @@ static void constant_fold(std::shared_ptr<Function> f)
pass_manager.run_passes(f); pass_manager.run_passes(f);
} }
TEST(builder, scaled_QC)
{
Shape shape_a{1, 1, 3, 4}; // input shape
Shape shape_b{1, 1, 3, 3}; // filter shape
Shape shape_r{1, 1, 3, 4}; // output shape
vector<uint8_t> a_data = {1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4};
vector<int8_t> b_data = {1, 2, 3, 4, 5, 0, 0, 1, 2};
auto A = make_shared<op::Parameter>(element::u8, shape_a);
auto B = make_shared<op::Parameter>(element::i8, shape_b);
auto C = op::Constant::create(element::f32, Shape{1}, {0.0f});
auto D = op::Constant::create(element::f32, Shape{1}, {255.0f});
auto E = op::Constant::create(element::f32, Shape{1}, {-127.0f});
auto F = op::Constant::create(element::f32, Shape{1}, {127.0f});
auto G = op::Constant::create(element::f32, Shape{1}, {22.0f});
auto H = op::Constant::create(element::f32, Shape{1}, {90.0f});
auto CV = ngraph::builder::QuantizedConvolutionBuilder(A,
B,
Strides{1, 1}, // move_strides
Strides{1, 1}, // filter_dilation
CoordinateDiff{1, 1}, // below_pads
CoordinateDiff{1, 1}, // above_pads
Strides{1, 1}, // data_dilation
C,
D,
E,
F,
G,
H,
element::i8,
AxisSet{});
auto f = make_shared<Function>(NodeVector{CV}, ParameterVector{A, B});
constant_fold(f);
auto backend = runtime::Backend::create("CPU");
// Create some tensors for input/output
auto a = backend->create_tensor(element::u8, shape_a);
copy_data(a, a_data);
auto b = backend->create_tensor(element::i8, shape_b);
copy_data(b, b_data);
auto result = backend->create_tensor(element::i8, shape_r);
auto handle = backend->compile(f);
handle->call_with_validate({result}, {a, b});
EXPECT_EQ((vector<int8_t>{31, 48, 42, 45, 54, 102, 127, 61, 47, 74, 61, 55}),
read_vector<int8_t>(result));
}
TEST(builder, dynamic_scaled_QC)
{
Shape shape_a{1, 1, 3, 4}; // input shape
Shape shape_b{1, 1, 3, 3}; // filter shape
Shape shape_r{1, 1, 3, 4}; // output shape
vector<uint8_t> a_data = {1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4};
vector<int8_t> b_data = {1, 2, 3, 4, 5, 0, 0, 1, 2};
auto A = make_shared<op::Parameter>(element::u8, shape_a);
auto B = make_shared<op::Parameter>(element::i8, shape_b);
auto C = make_shared<op::Parameter>(element::f32, Shape{1});
auto D = make_shared<op::Parameter>(element::f32, Shape{1});
auto E = make_shared<op::Parameter>(element::f32, Shape{1});
auto F = make_shared<op::Parameter>(element::f32, Shape{1});
auto G = make_shared<op::Parameter>(element::f32, Shape{1});
auto H = make_shared<op::Parameter>(element::f32, Shape{1});
auto CV = ngraph::builder::QuantizedConvolutionBuilder(A,
B,
Strides{1, 1}, // move_strides
Strides{1, 1}, // filter_dilation
CoordinateDiff{1, 1}, // below_pads
CoordinateDiff{1, 1}, // above_pads
Strides{1, 1}, // data_dilation
C,
D,
E,
F,
G,
H,
element::i8,
AxisSet{});
auto f = make_shared<Function>(NodeVector{CV}, ParameterVector{A, B, C, D, E, F, G, H});
auto backend = runtime::Backend::create("CPU");
// Create some tensors for input/output
auto a = backend->create_tensor(element::u8, shape_a);
copy_data(a, a_data);
auto b = backend->create_tensor(element::i8, shape_b);
copy_data(b, b_data);
auto d = backend->create_tensor(element::f32, Shape{1});
copy_data(d, vector<float>{0.0f});
auto e = backend->create_tensor(element::f32, Shape{1});
copy_data(e, vector<float>{255.0f});
auto e_a = backend->create_tensor(element::f32, Shape{1});
copy_data(e_a, vector<float>{-127.0f});
auto g = backend->create_tensor(element::f32, Shape{1});
copy_data(g, vector<float>{127.0f});
auto h = backend->create_tensor(element::f32, Shape{1});
copy_data(h, vector<float>{22.0f});
auto i = backend->create_tensor(element::f32, Shape{1});
copy_data(i, vector<float>{90.0f});
auto result = backend->create_tensor(element::i8, shape_r);
auto handle = backend->compile(f);
handle->call_with_validate({result}, {a, b, d, e, e_a, g, h, i});
EXPECT_EQ((vector<int8_t>{31, 48, 42, 45, 54, 102, 127, 61, 47, 74, 61, 55}),
read_vector<int8_t>(result));
}
TEST(builder, scaled_QC_with_relu) TEST(builder, scaled_QC_with_relu)
{ {
Shape shape_a{1, 1, 3, 3}; // input shape Shape shape_a{1, 1, 3, 3}; // input shape
......
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