diff --git a/BUILD b/BUILD index 79e910f..a4d6616 100644 --- a/BUILD +++ b/BUILD @@ -35,7 +35,8 @@ cc_library( "src/tim/transform/permute_vector.h", "src/tim/transform/layout_infer_context.h", ] + glob([ - "src/tim/vx/ops/*.cc" + "src/tim/vx/ops/*.cc", + "src/tim/vx/ops/*.h" ], exclude = ["src/tim/vx/ops/*_test.cc"] ) + glob(["src/tim/transform/ops/*.*"]), deps = [ @@ -94,7 +95,9 @@ cc_binary( cc_test ( name = "unit_test", copts = ["-std=c++14", "-Werror"], - srcs = glob(["src/tim/**/*_test.cc"]), + srcs = [ + "src/tim/vx/test_utils.h", + ] + glob(["src/tim/**/*_test.cc"]), deps = [ "@gtest//:gtest", "@gtest//:gtest_main", diff --git a/src/tim/vx/ops/conv2d_test.cc b/src/tim/vx/ops/conv2d_test.cc index fb683b6..0e49bd0 100644 --- a/src/tim/vx/ops/conv2d_test.cc +++ b/src/tim/vx/ops/conv2d_test.cc @@ -1,17 +1,18 @@ #include "tim/vx/ops/conv2d.h" +#include "gtest/gtest.h" +#include "src/tim/vx/test_utils.h" #include "tim/transform/layout_inference.h" #include "tim/vx/context.h" #include "tim/vx/graph.h" - -#include "gtest/gtest.h" +#include "tim/vx/types.h" TEST(Conv2d, shape_4_2_1_1_float32_PaddingTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); - tim::vx::ShapeType input_shape({4, 2, 1, 1}); //whcn - tim::vx::ShapeType weight_shape({2, 2, 1, 3}); //whio + tim::vx::ShapeType input_shape({4, 2, 1, 1}); //whcn + tim::vx::ShapeType weight_shape({2, 2, 1, 3}); //whio tim::vx::ShapeType bias_shape({weight_shape[3]}); tim::vx::ShapeType output_shape( {4, 2, weight_shape[3], input_shape[3]}); //whcn @@ -85,8 +86,8 @@ TEST(Conv2d, shape_4_2_2_2_float32_PointwiseTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); - tim::vx::ShapeType input_shape({4, 2, 2, 2}); //whcn - tim::vx::ShapeType weight_shape({1, 1, 2, 1}); //whio + tim::vx::ShapeType input_shape({4, 2, 2, 2}); //whcn + tim::vx::ShapeType weight_shape({1, 1, 2, 1}); //whio tim::vx::ShapeType bias_shape({weight_shape[3]}); tim::vx::ShapeType output_shape( {4, 2, weight_shape[3], input_shape[3]}); //whcn @@ -103,51 +104,48 @@ TEST(Conv2d, shape_4_2_2_2_float32_PointwiseTest) { // Input data nchw std::vector input_data = { 0.5, 0.5, 0.5, 0.5, 1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5, 1, 1, 1, 1, - 0.5, 1, 1.5, 2, 0.5, 1, 1.5, 2, 0.5, 1, 1.5, 2, 0.5, 1, 1.5, 2 - }; + 0.5, 1, 1.5, 2, 0.5, 1, 1.5, 2, 0.5, 1, 1.5, 2, 0.5, 1, 1.5, 2}; // weight data oihw std::vector weight_data = { - 1, 2 // first filter - }; + 1, 2 // first filter + }; - // bias data - std::vector bias_data = {0}; + // bias data + std::vector bias_data = {0}; - // nchw - std::vector golden = { - 1.5, 1.5, 1.5, 1.5, 3, 3, 3, 3, - 1.5, 3, 4.5, 6, 1.5, 3, 4.5, 6 - }; + // nchw + std::vector golden = {1.5, 1.5, 1.5, 1.5, 3, 3, 3, 3, + 1.5, 3, 4.5, 6, 1.5, 3, 4.5, 6}; - auto input_tensor = graph->CreateTensor(input_spec); - auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); - auto bias_tensor = graph->CreateTensor(bias_spec, bias_data.data()); + auto input_tensor = graph->CreateTensor(input_spec); + auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); + auto bias_tensor = graph->CreateTensor(bias_spec, bias_data.data()); - auto output_tensor = graph->CreateTensor(output_spec); + auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); - std::array stride({1, 1}); - std::array dilation({0, 0}); - auto padding = tim::vx::PadType::SAME; + std::array ksize({weight_shape[1], weight_shape[2]}); + std::array stride({1, 1}); + std::array dilation({0, 0}); + auto padding = tim::vx::PadType::SAME; - auto conv2d = graph->CreateOperation( - weight_shape[3], padding, ksize, stride, dilation); - (*conv2d) - .BindInput(input_tensor) - .BindInput(weight_tensor) - .BindInput(bias_tensor) - .BindOutput(output_tensor); + auto conv2d = graph->CreateOperation( + weight_shape[3], padding, ksize, stride, dilation); + (*conv2d) + .BindInput(input_tensor) + .BindInput(weight_tensor) + .BindInput(bias_tensor) + .BindOutput(output_tensor); - EXPECT_TRUE(graph->Compile()); + EXPECT_TRUE(graph->Compile()); - input_tensor->CopyDataToTensor(input_data.data()); + input_tensor->CopyDataToTensor(input_data.data()); - EXPECT_TRUE(graph->Run()); + EXPECT_TRUE(graph->Run()); - uint32_t output_size = 1; - for (auto i : output_tensor->GetShape()) { - output_size *= i; + uint32_t output_size = 1; + for (auto i : output_tensor->GetShape()) { + output_size *= i; } std::vector output(output_size); EXPECT_TRUE(output_tensor->CopyDataFromTensor(output.data())); @@ -158,8 +156,8 @@ TEST(Conv2d, shape_4_2_1_2_float32_SimpleTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); - tim::vx::ShapeType input_shape({4, 2, 1, 2}); //whcn - tim::vx::ShapeType weight_shape({2, 2, 1, 3}); //whio + tim::vx::ShapeType input_shape({4, 2, 1, 2}); //whcn + tim::vx::ShapeType weight_shape({2, 2, 1, 3}); //whio tim::vx::ShapeType bias_shape({weight_shape[3]}); tim::vx::ShapeType output_shape( {2, 1, weight_shape[3], input_shape[3]}); //whcn @@ -184,9 +182,7 @@ TEST(Conv2d, shape_4_2_1_2_float32_SimpleTest) { }; // weight data oihw - std::vector weight_data = { - 1, 2, 3, 4, -1, 1, -1, 1, -1, -1, 1, 1 - }; + std::vector weight_data = {1, 2, 3, 4, -1, 1, -1, 1, -1, -1, 1, 1}; // bias data std::vector bias_data = {1, 2, 3}; @@ -299,8 +295,8 @@ TEST(Conv2d, shape_6_3_1_1_float32_SimpleAnisotropicStridesTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); - tim::vx::ShapeType input_shape({6, 3, 1, 1}); //whcn - tim::vx::ShapeType weight_shape({2, 2, 1, 1}); //whio + tim::vx::ShapeType input_shape({6, 3, 1, 1}); //whcn + tim::vx::ShapeType weight_shape({2, 2, 1, 1}); //whio tim::vx::ShapeType bias_shape({weight_shape[3]}); tim::vx::ShapeType output_shape( {2, 2, weight_shape[3], input_shape[3]}); //whcn @@ -315,9 +311,8 @@ TEST(Conv2d, shape_6_3_1_1_float32_SimpleAnisotropicStridesTest) { tim::vx::TensorAttribute::OUTPUT); // Input data nchw - std::vector input_data = { - 3, 2, 1, -1, -2, -3, 4, 3, 2, -2, -3, -4, 5, 4, 3, -3, -4, -5 - }; + std::vector input_data = {3, 2, 1, -1, -2, -3, 4, 3, 2, + -2, -3, -4, 5, 4, 3, -3, -4, -5}; // weight data oihw std::vector weight_data = { @@ -332,7 +327,7 @@ TEST(Conv2d, shape_6_3_1_1_float32_SimpleAnisotropicStridesTest) { std::vector golden = { 30, -24, // 40, -34, // - }; + }; auto input_tensor = graph->CreateTensor(input_spec); auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); @@ -372,8 +367,8 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); - tim::vx::ShapeType input_shape({4, 3, 1, 1}); //whcn - tim::vx::ShapeType weight_shape({3, 3, 1, 1}); //whio + tim::vx::ShapeType input_shape({4, 3, 1, 1}); //whcn + tim::vx::ShapeType weight_shape({3, 3, 1, 1}); //whio tim::vx::ShapeType bias_shape({weight_shape[3]}); tim::vx::ShapeType output_shape( {4, 3, weight_shape[3], input_shape[3]}); //whcn @@ -388,23 +383,17 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedTest) { tim::vx::TensorAttribute::OUTPUT); // Input data nchw - std::vector input_data = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 - }; + std::vector input_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; // weight data oihw - std::vector weight_data = { - 1, 4, 7, 2, 5, 8, 3, 6, 9 - }; + std::vector weight_data = {1, 4, 7, 2, 5, 8, 3, 6, 9}; // bias data std::vector bias_data = {0}; // nchw - std::vector golden = { - 105, 150, 183, 95, 235, 312, - 357, 178, 187, 234, 261, 121 - }; + std::vector golden = {105, 150, 183, 95, 235, 312, + 357, 178, 187, 234, 261, 121}; auto input_tensor = graph->CreateTensor(input_spec); auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); @@ -444,8 +433,8 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedConstFilterTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); - tim::vx::ShapeType input_shape({4, 3, 1, 1}); //whcn - tim::vx::ShapeType weight_shape({3, 3, 1, 1}); //whio + tim::vx::ShapeType input_shape({4, 3, 1, 1}); //whcn + tim::vx::ShapeType weight_shape({3, 3, 1, 1}); //whio tim::vx::ShapeType bias_shape({weight_shape[3]}); tim::vx::ShapeType output_shape( {4, 3, weight_shape[3], input_shape[3]}); //whcn @@ -460,23 +449,17 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedConstFilterTest) { tim::vx::TensorAttribute::OUTPUT); // Input data nchw - std::vector input_data = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 - }; + std::vector input_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; // weight data oihw - std::vector weight_data = { - 1, 4, 7, 2, 5, 8, 3, 6, 9 - }; + std::vector weight_data = {1, 4, 7, 2, 5, 8, 3, 6, 9}; // bias data std::vector bias_data = {0}; // nchw - std::vector golden = { - 105, 150, 183, 95, 235, 312, - 357, 178, 187, 234, 261, 121 - }; + std::vector golden = {105, 150, 183, 95, 235, 312, + 357, 178, 187, 234, 261, 121}; auto input_tensor = graph->CreateTensor(input_spec); auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); @@ -516,8 +499,8 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedBiasTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); - tim::vx::ShapeType input_shape({4, 3, 1, 1}); //whcn - tim::vx::ShapeType weight_shape({3, 3, 1, 1}); //whio + tim::vx::ShapeType input_shape({4, 3, 1, 1}); //whcn + tim::vx::ShapeType weight_shape({3, 3, 1, 1}); //whio tim::vx::ShapeType bias_shape({weight_shape[3]}); tim::vx::ShapeType output_shape( {4, 3, weight_shape[3], input_shape[3]}); //whcn @@ -532,22 +515,17 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedBiasTest) { tim::vx::TensorAttribute::OUTPUT); // Input data nchw - std::vector input_data = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 - }; + std::vector input_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; // weight data oihw - std::vector weight_data = { - 1, 4, 7, 2, 5, 8, 3, 6, 9 - }; + std::vector weight_data = {1, 4, 7, 2, 5, 8, 3, 6, 9}; // bias data std::vector bias_data = {10}; // nchw - std::vector golden = { - 115, 160, 193, 105, 245, 322, 367, 188, 197, 244, 271, 131 - }; + std::vector golden = {115, 160, 193, 105, 245, 322, + 367, 188, 197, 244, 271, 131}; auto input_tensor = graph->CreateTensor(input_spec); auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); @@ -587,8 +565,8 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedValidTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); - tim::vx::ShapeType input_shape({4, 3, 1, 1}); //whcn - tim::vx::ShapeType weight_shape({3, 3, 1, 1}); //whio + tim::vx::ShapeType input_shape({4, 3, 1, 1}); //whcn + tim::vx::ShapeType weight_shape({3, 3, 1, 1}); //whio tim::vx::ShapeType bias_shape({weight_shape[3]}); tim::vx::ShapeType output_shape( {2, 1, weight_shape[3], input_shape[3]}); //whcn @@ -603,22 +581,16 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedValidTest) { tim::vx::TensorAttribute::OUTPUT); // Input data nchw - std::vector input_data = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 - }; + std::vector input_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; // weight data oihw - std::vector weight_data = { - 1, 4, 7, 2, 5, 8, 3, 6, 9 - }; + std::vector weight_data = {1, 4, 7, 2, 5, 8, 3, 6, 9}; // bias data std::vector bias_data = {0}; // nchw - std::vector golden = { - 312, 357 - }; + std::vector golden = {312, 357}; auto input_tensor = graph->CreateTensor(input_spec); auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); @@ -658,8 +630,8 @@ TEST(Conv2d, shape_4_2_2_2_float32_DisabledPointwiseMultifilterTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); - tim::vx::ShapeType input_shape({4, 2, 2, 2}); //whcn - tim::vx::ShapeType weight_shape({1, 1, 2, 2}); //whio + tim::vx::ShapeType input_shape({4, 2, 2, 2}); //whcn + tim::vx::ShapeType weight_shape({1, 1, 2, 2}); //whio tim::vx::ShapeType bias_shape({weight_shape[3]}); tim::vx::ShapeType output_shape( {4, 2, weight_shape[3], input_shape[3]}); //whcn @@ -676,13 +648,10 @@ TEST(Conv2d, shape_4_2_2_2_float32_DisabledPointwiseMultifilterTest) { // Input data nchw std::vector input_data = { 0.5, 0.5, 0.5, 0.5, 1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5, 1, 1, 1, 1, - 0.5, 1, 1.5, 2, 0.5, 1, 1.5, 2, 0.5, 1, 1.5, 2, 0.5, 1, 1.5, 2 - }; + 0.5, 1, 1.5, 2, 0.5, 1, 1.5, 2, 0.5, 1, 1.5, 2, 0.5, 1, 1.5, 2}; // weight data oihw - std::vector weight_data = { - 1, 2, 2, 3 - }; + std::vector weight_data = {1, 2, 2, 3}; // bias data std::vector bias_data = {0}; @@ -690,8 +659,7 @@ TEST(Conv2d, shape_4_2_2_2_float32_DisabledPointwiseMultifilterTest) { // nchw std::vector golden = { 1.5, 1.5, 1.5, 1.5, 3, 3, 3, 3, 2.5, 2.5, 2.5, 2.5, 5, 5, 5, 5, - 1.5, 3, 4.5, 6, 1.5, 3, 4.5, 6, 2.5, 5, 7.5, 10, 2.5, 5, 7.5, 10 - }; + 1.5, 3, 4.5, 6, 1.5, 3, 4.5, 6, 2.5, 5, 7.5, 10, 2.5, 5, 7.5, 10}; auto input_tensor = graph->CreateTensor(input_spec); auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); @@ -731,8 +699,8 @@ TEST(Conv2d, shape_9_9_1_1_float32_SimpleDilationTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); - tim::vx::ShapeType input_shape({9, 9, 1, 1}); //whcn - tim::vx::ShapeType weight_shape({3, 3, 1, 1}); //whio + tim::vx::ShapeType input_shape({9, 9, 1, 1}); //whcn + tim::vx::ShapeType weight_shape({3, 3, 1, 1}); //whio tim::vx::ShapeType bias_shape({weight_shape[3]}); tim::vx::ShapeType output_shape( {3, 3, weight_shape[3], input_shape[3]}); //whcn @@ -751,13 +719,10 @@ TEST(Conv2d, shape_9_9_1_1_float32_SimpleDilationTest) { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // weight data oihw - std::vector weight_data = { - 1, 2, 3, 4, 5, 6, 7, 8, 9 - }; + std::vector weight_data = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // bias data std::vector bias_data = {0}; @@ -803,8 +768,8 @@ TEST(Conv2d, shape_4_2_1_2_float32_StrideTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); - tim::vx::ShapeType input_shape({4, 2, 1, 2}); //whcn - tim::vx::ShapeType weight_shape({2, 2, 1, 3}); //whio + tim::vx::ShapeType input_shape({4, 2, 1, 2}); //whcn + tim::vx::ShapeType weight_shape({2, 2, 1, 3}); //whio tim::vx::ShapeType bias_shape({weight_shape[3]}); tim::vx::ShapeType output_shape( {3, 1, weight_shape[3], input_shape[3]}); //whcn @@ -819,22 +784,18 @@ TEST(Conv2d, shape_4_2_1_2_float32_StrideTest) { tim::vx::TensorAttribute::OUTPUT); // Input data nchw - std::vector input_data = { - 1, 1, 1, 1, 2, 2, 3, 2, 1, 2, 3, 4, 1, 2, 4, 4 - }; + std::vector input_data = {1, 1, 1, 1, 2, 2, 3, 2, + 1, 2, 3, 4, 1, 2, 4, 4}; // weight data oihw - std::vector weight_data = { - 1, 2, 3, 4, -1, 1, -1, 1, -1, -1, 1, 1 - }; + std::vector weight_data = {1, 2, 3, 4, -1, 1, -1, 1, -1, -1, 1, 1}; // bias data std::vector bias_data = {1, 2, 3}; // nchw - std::vector golden = { - 18, 22, 21, 2, 3, 1, 5, 6, 6, 17, 31, 40, 4, 5, 3, 3, 4, 4 - }; + std::vector golden = {18, 22, 21, 2, 3, 1, 5, 6, 6, + 17, 31, 40, 4, 5, 3, 3, 4, 4}; auto input_tensor = graph->CreateTensor(input_spec); auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); @@ -874,8 +835,8 @@ TEST(Conv2d, shape_4_2_1_2_float32_InputAndFilterSameWidthHeightTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); - tim::vx::ShapeType input_shape({4, 2, 1, 2}); //whcn - tim::vx::ShapeType weight_shape({4, 2, 1, 1}); //whio + tim::vx::ShapeType input_shape({4, 2, 1, 2}); //whcn + tim::vx::ShapeType weight_shape({4, 2, 1, 1}); //whio tim::vx::ShapeType bias_shape({weight_shape[3]}); tim::vx::ShapeType output_shape( {1, 1, weight_shape[3], input_shape[3]}); //whcn @@ -890,22 +851,17 @@ TEST(Conv2d, shape_4_2_1_2_float32_InputAndFilterSameWidthHeightTest) { tim::vx::TensorAttribute::OUTPUT); // Input data nchw - std::vector input_data = { - 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 3, 4, 1, 2, 3, 4 - }; + std::vector input_data = {1, 1, 1, 1, 2, 2, 2, 2, + 1, 2, 3, 4, 1, 2, 3, 4}; // weight data oihw - std::vector weight_data = { - 1, 2, 3, 4, -1, -1, 1, 1 - }; + std::vector weight_data = {1, 2, 3, 4, -1, -1, 1, 1}; // bias data std::vector bias_data = {0}; // nchw - std::vector golden = { - 10, 34 - }; + std::vector golden = {10, 34}; auto input_tensor = graph->CreateTensor(input_spec); auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); @@ -940,3 +896,427 @@ TEST(Conv2d, shape_4_2_1_2_float32_InputAndFilterSameWidthHeightTest) { EXPECT_TRUE(output_tensor->CopyDataFromTensor(output.data())); EXPECT_EQ(golden, output); } + +TEST(Conv2d, shape_4_2_1_2_uint8_QuantizedTest1) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + tim::vx::ShapeType input_shape({4, 2, 1, 2}); //whcn + tim::vx::ShapeType weight_shape({2, 2, 1, 3}); //whio + tim::vx::ShapeType bias_shape({weight_shape[3]}); + tim::vx::ShapeType output_shape( + {2, 1, weight_shape[3], input_shape[3]}); //whcn + + float InputMin = -63.5, InputMax = 64, WeightMin = -63.5, WeightMax = 64, + OutputMin = -127, OutputMax = 128; + + std::pair scalesAndZp; + + scalesAndZp = QuantizationParams(InputMin, InputMax); + std::vector scalesInput = {scalesAndZp.first}; + std::vector zeroPointsInput = {scalesAndZp.second}; + + scalesAndZp = QuantizationParams(WeightMin, WeightMax); + std::vector scalesWeight = {scalesAndZp.first}; + std::vector zeroPointsWeight = {scalesAndZp.second}; + + std::vector scalesBias = {scalesInput[0] * scalesWeight[0]}; + std::vector zeroPointsBias = {0}; + + scalesAndZp = QuantizationParams(OutputMin, OutputMax); + std::vector scalesOutput = {scalesAndZp.first}; + std::vector zeroPointsOutput = {scalesAndZp.second}; + + tim::vx::Quantization quantInput(tim::vx::QuantType::ASYMMETRIC, 2, + scalesInput, zeroPointsInput); + tim::vx::Quantization quantWeight(tim::vx::QuantType::ASYMMETRIC, 2, + scalesWeight, zeroPointsWeight); + tim::vx::Quantization quantBias(tim::vx::QuantType::ASYMMETRIC, 2, scalesBias, + zeroPointsBias); + tim::vx::Quantization quantOutput(tim::vx::QuantType::ASYMMETRIC, 2, + scalesOutput, zeroPointsOutput); + + tim::vx::TensorSpec input_spec(tim::vx::DataType::UINT8, input_shape, + tim::vx::TensorAttribute::INPUT, quantInput); + tim::vx::TensorSpec weight_spec(tim::vx::DataType::UINT8, weight_shape, + tim::vx::TensorAttribute::CONSTANT, + quantWeight); + tim::vx::TensorSpec bias_spec(tim::vx::DataType::INT32, bias_shape, + tim::vx::TensorAttribute::CONSTANT, quantBias); + tim::vx::TensorSpec output_spec(tim::vx::DataType::UINT8, output_shape, + tim::vx::TensorAttribute::OUTPUT, + quantOutput); + + // Input data nchw + // min:-63.5 max:64 scale:0.5 Zp:-1 + std::vector input_data_float = {1, 1, 1, 1, 2, 2, 2, 2, + 1, 2, 3, 4, 1, 2, 3, 4}; + // weight data oihw + // min:-63.5 max:64 scale:0.5 Zp:-1 + std::vector weight_data_float = {1, 2, 3, 4, -1, 1, + -1, 1, -1, -1, 1, 1}; + // bias data + // scale:0.25 Zp:0 + std::vector bias_data_float = {1, 2, 3}; + // golden data + //min:-127 max:128 scale:1 Zp:-1 + std::vector golden_float = {18, 18, 2, 2, 5, 5, 17, 37, 4, 4, 3, 3}; + + std::vector input_data = + Quantize(input_data_float, scalesInput[0], zeroPointsInput[0]); + std::vector weight_data = + Quantize(weight_data_float, scalesWeight[0], zeroPointsInput[0]); + std::vector bias_data = + Quantize(bias_data_float, scalesBias[0], zeroPointsBias[0]); + std::vector golden = + Quantize(golden_float, scalesOutput[0], zeroPointsOutput[0]); + auto input_tensor = graph->CreateTensor(input_spec); + auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); + auto bias_tensor = graph->CreateTensor(bias_spec, bias_data.data()); + auto output_tensor = graph->CreateTensor(output_spec); + + std::array ksize({weight_shape[1], weight_shape[2]}); + std::array stride({2, 2}); + std::array dilation({1, 1}); + auto padding = tim::vx::PadType::VALID; + + auto conv2d = graph->CreateOperation( + weight_shape[3], padding, ksize, stride, dilation); + (*conv2d) + .BindInput(input_tensor) + .BindInput(weight_tensor) + .BindInput(bias_tensor) + .BindOutput(output_tensor); + + EXPECT_TRUE(graph->Compile()); + + input_tensor->CopyDataToTensor(input_data.data()); + + EXPECT_TRUE(graph->Run()); + + uint32_t output_size = 1; + for (auto i : output_tensor->GetShape()) { + output_size *= i; + } + std::vector output(output_size); + EXPECT_TRUE(output_tensor->CopyDataFromTensor(output.data())); + EXPECT_EQ(golden, output); +} + +TEST(Conv2d, shape_4_2_1_2_uint8_QuantizedTest2) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + tim::vx::ShapeType input_shape({4, 2, 1, 2}); //whcn + tim::vx::ShapeType weight_shape({2, 2, 1, 3}); //whio + tim::vx::ShapeType bias_shape({weight_shape[3]}); + tim::vx::ShapeType output_shape( + {2, 1, weight_shape[3], input_shape[3]}); //whcn + + float InputMin = -128.5, InputMax = 128, WeightMin = -128.5, WeightMax = 128, + OutputMin = -127, OutputMax = 128; + + std::pair scalesAndZp; + + scalesAndZp = QuantizationParams(InputMin, InputMax); + std::vector scalesInput = {scalesAndZp.first}; + std::vector zeroPointsInput = {scalesAndZp.second}; + + scalesAndZp = QuantizationParams(WeightMin, WeightMax); + std::vector scalesWeight = {scalesAndZp.first}; + std::vector zeroPointsWeight = {scalesAndZp.second}; + + std::vector scalesBias = {scalesInput[0] * scalesWeight[0]}; + std::vector zeroPointsBias = {0}; + + scalesAndZp = QuantizationParams(OutputMin, OutputMax); + std::vector scalesOutput = {scalesAndZp.first}; + std::vector zeroPointsOutput = {scalesAndZp.second}; + + tim::vx::Quantization quantInput(tim::vx::QuantType::ASYMMETRIC, 2, + scalesInput, zeroPointsInput); + tim::vx::Quantization quantWeight(tim::vx::QuantType::ASYMMETRIC, 2, + scalesWeight, zeroPointsWeight); + tim::vx::Quantization quantBias(tim::vx::QuantType::ASYMMETRIC, 2, scalesBias, + zeroPointsBias); + tim::vx::Quantization quantOutput(tim::vx::QuantType::ASYMMETRIC, 2, + scalesOutput, zeroPointsOutput); + + tim::vx::TensorSpec input_spec(tim::vx::DataType::UINT8, input_shape, + tim::vx::TensorAttribute::INPUT, quantInput); + tim::vx::TensorSpec weight_spec(tim::vx::DataType::UINT8, weight_shape, + tim::vx::TensorAttribute::CONSTANT, + quantWeight); + tim::vx::TensorSpec bias_spec(tim::vx::DataType::INT32, bias_shape, + tim::vx::TensorAttribute::CONSTANT, quantBias); + tim::vx::TensorSpec output_spec(tim::vx::DataType::UINT8, output_shape, + tim::vx::TensorAttribute::OUTPUT, + quantOutput); + + // Input data nchw + // min:-128.5 max:128 scale:1.00588 Zp:0 + std::vector input_data_float = {1, 1, 1, 1, 2, 2, 2, 2, + 1, 2, 3, 4, 1, 2, 3, 4}; + // weight data oihw + // min:-128.5 max:128 scale:1.00588 Zp:0 + std::vector weight_data_float = {1, 2, 3, 4, -1, 1, + -1, 1, -1, -1, 1, 1}; + // bias data + // scale:1.0116 Zp:0 + std::vector bias_data_float = {1, 2, 3}; + // golden data + // min:-127 max:128 scale:1 Zp:-1 + std::vector golden_float = {18, 18, 2, 2, 5, 5, 17, 37, 4, 4, 3, 3}; + + std::vector input_data = + Quantize(input_data_float, scalesInput[0], zeroPointsInput[0]); + std::vector weight_data = + Quantize(weight_data_float, scalesWeight[0], zeroPointsInput[0]); + std::vector bias_data = + Quantize(bias_data_float, scalesBias[0], zeroPointsBias[0]); + std::vector golden = + Quantize(golden_float, scalesOutput[0], zeroPointsOutput[0]); + + auto input_tensor = graph->CreateTensor(input_spec); + auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); + auto bias_tensor = graph->CreateTensor(bias_spec, bias_data.data()); + auto output_tensor = graph->CreateTensor(output_spec); + + std::array ksize({weight_shape[1], weight_shape[2]}); + std::array stride({2, 2}); + std::array dilation({1, 1}); + auto padding = tim::vx::PadType::VALID; + + auto conv2d = graph->CreateOperation( + weight_shape[3], padding, ksize, stride, dilation); + (*conv2d) + .BindInput(input_tensor) + .BindInput(weight_tensor) + .BindInput(bias_tensor) + .BindOutput(output_tensor); + + EXPECT_TRUE(graph->Compile()); + + input_tensor->CopyDataToTensor(input_data.data()); + + EXPECT_TRUE(graph->Run()); + + uint32_t output_size = 1; + for (auto i : output_tensor->GetShape()) { + output_size *= i; + } + std::vector output(output_size); + EXPECT_TRUE(output_tensor->CopyDataFromTensor(output.data())); + EXPECT_EQ(golden, output); +} + +TEST(Conv2d, shape_6_3_1_1_uint8_AnisotropicStridesQuantizedTest) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + tim::vx::ShapeType input_shape({6, 3, 1, 1}); //whcn + tim::vx::ShapeType weight_shape({2, 2, 1, 1}); //whio + tim::vx::ShapeType bias_shape({weight_shape[3]}); + tim::vx::ShapeType output_shape( + {2, 2, weight_shape[3], input_shape[3]}); //whcn + + float InputMin = -63.5, InputMax = 64, WeightMin = -63.5, WeightMax = 64, + OutputMin = -127, OutputMax = 128; + + std::pair scalesAndZp; + + scalesAndZp = QuantizationParams(InputMin, InputMax); + std::vector scalesInput = {scalesAndZp.first}; + std::vector zeroPointsInput = {scalesAndZp.second}; + + scalesAndZp = QuantizationParams(WeightMin, WeightMax); + std::vector scalesWeight = {scalesAndZp.first}; + std::vector zeroPointsWeight = {scalesAndZp.second}; + + std::vector scalesBias = {scalesInput[0] * scalesWeight[0]}; + std::vector zeroPointsBias = {0}; + + scalesAndZp = QuantizationParams(OutputMin, OutputMax); + std::vector scalesOutput = {scalesAndZp.first}; + std::vector zeroPointsOutput = {scalesAndZp.second}; + + tim::vx::Quantization quantInput(tim::vx::QuantType::ASYMMETRIC, 2, + scalesInput, zeroPointsInput); + tim::vx::Quantization quantWeight(tim::vx::QuantType::ASYMMETRIC, 2, + scalesWeight, zeroPointsWeight); + tim::vx::Quantization quantBias(tim::vx::QuantType::ASYMMETRIC, 2, scalesBias, + zeroPointsBias); + tim::vx::Quantization quantOutput(tim::vx::QuantType::ASYMMETRIC, 2, + scalesOutput, zeroPointsOutput); + + tim::vx::TensorSpec input_spec(tim::vx::DataType::UINT8, input_shape, + tim::vx::TensorAttribute::INPUT, quantInput); + tim::vx::TensorSpec weight_spec(tim::vx::DataType::UINT8, weight_shape, + tim::vx::TensorAttribute::CONSTANT, + quantWeight); + tim::vx::TensorSpec bias_spec(tim::vx::DataType::INT32, bias_shape, + tim::vx::TensorAttribute::CONSTANT, quantBias); + tim::vx::TensorSpec output_spec(tim::vx::DataType::UINT8, output_shape, + tim::vx::TensorAttribute::OUTPUT, + quantOutput); + + // Input data nchw + // min:-63.5 max:64 scale:0.5 Zp:-1 + std::vector input_data_float = {3, 2, 1, -1, -2, -3, 4, 3, 2, + -2, -3, -4, 5, 4, 3, -3, -4, -5}; + // weight data oihw + // min:-63.5 max:64 scale:0.5 Zp:-1 + std::vector weight_data_float = {1, 2, 3, 4}; + // bias data + // scale:0.25 Zp:0 + std::vector bias_data_float = {-1}; + // golden data + //min:-127 max:128 scale:1 Zp:-1 + std::vector golden_float = {30, -24, 40, -34}; + + std::vector input_data = + Quantize(input_data_float, scalesInput[0], zeroPointsInput[0]); + std::vector weight_data = + Quantize(weight_data_float, scalesWeight[0], zeroPointsInput[0]); + std::vector bias_data = + Quantize(bias_data_float, scalesBias[0], zeroPointsBias[0]); + std::vector golden = + Quantize(golden_float, scalesOutput[0], zeroPointsOutput[0]); + + auto input_tensor = graph->CreateTensor(input_spec); + auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); + auto bias_tensor = graph->CreateTensor(bias_spec, bias_data.data()); + auto output_tensor = graph->CreateTensor(output_spec); + + std::array ksize({weight_shape[1], weight_shape[2]}); + std::array stride({3, 1}); + std::array dilation({1, 1}); + auto padding = tim::vx::PadType::VALID; + + auto conv2d = graph->CreateOperation( + weight_shape[3], padding, ksize, stride, dilation); + (*conv2d) + .BindInput(input_tensor) + .BindInput(weight_tensor) + .BindInput(bias_tensor) + .BindOutput(output_tensor); + + EXPECT_TRUE(graph->Compile()); + + input_tensor->CopyDataToTensor(input_data.data()); + + EXPECT_TRUE(graph->Run()); + + uint32_t output_size = 1; + for (auto i : output_tensor->GetShape()) { + output_size *= i; + } + std::vector output(output_size); + EXPECT_TRUE(output_tensor->CopyDataFromTensor(output.data())); + EXPECT_EQ(golden, output); +} + +TEST(Conv2d, shape_9_9_1_1_uint8_DilationQuantizedTest) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + tim::vx::ShapeType input_shape({9, 9, 1, 1}); //whcn + tim::vx::ShapeType weight_shape({3, 3, 1, 1}); //whio + tim::vx::ShapeType bias_shape({weight_shape[3]}); + tim::vx::ShapeType output_shape( + {3, 3, weight_shape[3], input_shape[3]}); //whcn + + float InputMin = -128, InputMax = 127, WeightMin = -128, WeightMax = 127, + OutputMin = 0, OutputMax = 255; + + std::pair scalesAndZp; + + scalesAndZp = QuantizationParams(InputMin, InputMax); + std::vector scalesInput = {scalesAndZp.first}; + std::vector zeroPointsInput = {scalesAndZp.second}; + + scalesAndZp = QuantizationParams(WeightMin, WeightMax); + std::vector scalesWeight = {scalesAndZp.first}; + std::vector zeroPointsWeight = {scalesAndZp.second}; + + std::vector scalesBias = {scalesInput[0] * scalesWeight[0]}; + std::vector zeroPointsBias = {0}; + + scalesAndZp = QuantizationParams(OutputMin, OutputMax); + std::vector scalesOutput = {scalesAndZp.first}; + std::vector zeroPointsOutput = {scalesAndZp.second}; + + tim::vx::Quantization quantInput(tim::vx::QuantType::ASYMMETRIC, 2, + scalesInput, zeroPointsInput); + tim::vx::Quantization quantWeight(tim::vx::QuantType::ASYMMETRIC, 2, + scalesWeight, zeroPointsWeight); + tim::vx::Quantization quantBias(tim::vx::QuantType::ASYMMETRIC, 2, scalesBias, + zeroPointsBias); + tim::vx::Quantization quantOutput(tim::vx::QuantType::ASYMMETRIC, 2, + scalesOutput, zeroPointsOutput); + + tim::vx::TensorSpec input_spec(tim::vx::DataType::UINT8, input_shape, + tim::vx::TensorAttribute::INPUT, quantInput); + tim::vx::TensorSpec weight_spec(tim::vx::DataType::UINT8, weight_shape, + tim::vx::TensorAttribute::CONSTANT, + quantWeight); + tim::vx::TensorSpec bias_spec(tim::vx::DataType::INT32, bias_shape, + tim::vx::TensorAttribute::CONSTANT, quantBias); + tim::vx::TensorSpec output_spec(tim::vx::DataType::UINT8, output_shape, + tim::vx::TensorAttribute::OUTPUT, + quantOutput); + + // Input data nchw + // min:-128 max:127 scale:1 Zp:0 + std::vector input_data_float = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + // weight data oihw + // min:-128 max:127 scale:1 Zp:0 + std::vector weight_data_float = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + // bias data + // scale:1 Zp:0 + std::vector bias_data_float = {0}; + // golden data + // min:0 max:255 scale:1 Zp:-128 + std::vector golden_float = {5, 5, 5, 5, 5, 5, 5, 5, 5}; + + std::vector input_data = + Quantize(input_data_float, scalesInput[0], zeroPointsInput[0]); + std::vector weight_data = + Quantize(weight_data_float, scalesWeight[0], zeroPointsInput[0]); + std::vector bias_data = + Quantize(bias_data_float, scalesBias[0], zeroPointsBias[0]); + std::vector golden = + Quantize(golden_float, scalesOutput[0], zeroPointsOutput[0]); + + auto input_tensor = graph->CreateTensor(input_spec); + auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data()); + auto bias_tensor = graph->CreateTensor(bias_spec, bias_data.data()); + auto output_tensor = graph->CreateTensor(output_spec); + + std::array ksize({weight_shape[1], weight_shape[2]}); + std::array stride({1, 1}); + std::array dilation({3, 3}); + auto padding = tim::vx::PadType::VALID; + + auto conv2d = graph->CreateOperation( + weight_shape[3], padding, ksize, stride, dilation); + (*conv2d) + .BindInput(input_tensor) + .BindInput(weight_tensor) + .BindInput(bias_tensor) + .BindOutput(output_tensor); + + EXPECT_TRUE(graph->Compile()); + + input_tensor->CopyDataToTensor(input_data.data()); + + EXPECT_TRUE(graph->Run()); + + uint32_t output_size = 1; + for (auto i : output_tensor->GetShape()) { + output_size *= i; + } + std::vector output(output_size); + EXPECT_TRUE(output_tensor->CopyDataFromTensor(output.data())); + EXPECT_EQ(golden, output); +} diff --git a/src/tim/vx/test_utils.h b/src/tim/vx/test_utils.h new file mode 100644 index 0000000..d6d4ff1 --- /dev/null +++ b/src/tim/vx/test_utils.h @@ -0,0 +1,87 @@ +#ifndef TIM_VX_TEST_UTILS_H_ +#define TIM_VX_TEST_UTILS_H_ + +#include +#include +#include +#include + +template +std::pair QuantizationParams(float f_min, float f_max) { + int32_t zero_point = 0; + float scale = 0; + const T qmin = std::numeric_limits::min(); + const T qmax = std::numeric_limits::max(); + const float qmin_double = qmin; + const float qmax_double = qmax; + // 0 should always be a representable value. Let's assume that the initial + // min,max range contains 0. + if (f_min == f_max) { + // Special case where the min,max range is a point. Should be {0}. + return {scale, zero_point}; + } + + // General case. + // + // First determine the scale. + scale = (f_max - f_min) / (qmax_double - qmin_double); + + // Zero-point computation. + // First the initial floating-point computation. The zero-point can be + // determined from solving an affine equation for any known pair + // (real value, corresponding quantized value). + // We know two such pairs: (rmin, qmin) and (rmax, qmax). + // The arithmetic error on the zero point computed from either pair + // will be roughly machine_epsilon * (sum of absolute values of terms) + // so we want to use the variant that adds the smaller terms. + const float zero_point_from_min = qmin_double - f_min / scale; + const float zero_point_from_max = qmax_double - f_max / scale; + + const float zero_point_from_min_error = + std::abs(qmin_double) + std::abs(f_min / scale); + + const float zero_point_from_max_error = + std::abs(qmax_double) + std::abs(f_max / scale); + + const float zero_point_double = + zero_point_from_min_error < zero_point_from_max_error + ? zero_point_from_min + : zero_point_from_max; + + // Now we need to nudge the zero point to be an integer + // (our zero points are integer, and this is motivated by the requirement + // to be able to represent the real value "0" exactly as a quantized value, + // which is required in multiple places, for example in Im2col with SAME + // padding). + + T nudged_zero_point = 0; + if (zero_point_double < qmin_double) { + nudged_zero_point = qmin; + } else if (zero_point_double > qmax_double) { + nudged_zero_point = qmax; + } else { + nudged_zero_point = static_cast(std::round(zero_point_double)); + } + + // The zero point should always be in the range of quantized value, + // // [qmin, qmax]. + + zero_point = nudged_zero_point; + // finally, return the values + return {scale, zero_point}; +} + +template +inline std::vector Quantize(const std::vector& data, float scale, + int32_t zero_point) { + std::vector q; + for (const auto& f : data) { + q.push_back(static_cast(std::max( + std::numeric_limits::min(), + std::min(std::numeric_limits::max(), + std::round(zero_point + (f / scale)))))); + } + return q; +} + +#endif /* TIM_VX_TEST_UTILS_H_ */ \ No newline at end of file