diff --git a/src/tim/vx/ops/conv2d_test.cc b/src/tim/vx/ops/conv2d_test.cc index 5119b60..791024f 100644 --- a/src/tim/vx/ops/conv2d_test.cc +++ b/src/tim/vx/ops/conv2d_test.cc @@ -2,7 +2,6 @@ #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 "tim/vx/types.h" @@ -54,13 +53,12 @@ TEST(Conv2d, shape_4_2_1_1_float32_PaddingTest) { auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); + auto padding = tim::vx::PadType::SAME; 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); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -124,13 +122,12 @@ TEST(Conv2d, shape_4_2_2_2_float32_PointwiseTest) { auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); + auto padding = tim::vx::PadType::SAME; 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); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -196,13 +193,12 @@ TEST(Conv2d, shape_4_2_1_2_float32_SimpleTest) { auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); + auto padding = tim::vx::PadType::SAME; std::array stride({2, 2}); std::array dilation({0, 0}); - auto padding = tim::vx::PadType::SAME; auto conv2d = graph->CreateOperation( - weight_shape[3], padding, ksize, stride, dilation); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -263,13 +259,12 @@ TEST(Conv2d, shape_4_2_2_2_float32_SimpleChannelsTest) { auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); + auto padding = tim::vx::PadType::SAME; std::array stride({2, 2}); std::array dilation({0, 0}); - auto padding = tim::vx::PadType::SAME; auto conv2d = graph->CreateOperation( - weight_shape[3], padding, ksize, stride, dilation); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -335,13 +330,12 @@ TEST(Conv2d, shape_6_3_1_1_float32_SimpleAnisotropicStridesTest) { auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); + auto padding = tim::vx::PadType::VALID; std::array stride({3, 1}); std::array dilation({0, 0}); - auto padding = tim::vx::PadType::VALID; auto conv2d = graph->CreateOperation( - weight_shape[3], padding, ksize, stride, dilation); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -401,13 +395,12 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedTest) { auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); + auto padding = tim::vx::PadType::SAME; 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); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -467,13 +460,12 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedConstFilterTest) { auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); + auto padding = tim::vx::PadType::SAME; 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); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -533,13 +525,12 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedBiasTest) { auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); + auto padding = tim::vx::PadType::SAME; 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); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -598,13 +589,12 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedValidTest) { auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); + auto padding = tim::vx::PadType::VALID; std::array stride({1, 1}); std::array dilation({0, 0}); - auto padding = tim::vx::PadType::VALID; auto conv2d = graph->CreateOperation( - weight_shape[3], padding, ksize, stride, dilation); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -667,13 +657,12 @@ TEST(Conv2d, shape_4_2_2_2_float32_DisabledPointwiseMultifilterTest) { auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); + auto padding = tim::vx::PadType::VALID; std::array stride({1, 1}); std::array dilation({0, 0}); - auto padding = tim::vx::PadType::VALID; auto conv2d = graph->CreateOperation( - weight_shape[3], padding, ksize, stride, dilation); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -736,13 +725,12 @@ TEST(Conv2d, shape_9_9_1_1_float32_SimpleDilationTest) { auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); + auto padding = tim::vx::PadType::VALID; 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); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -803,13 +791,12 @@ TEST(Conv2d, shape_4_2_1_2_float32_StrideTest) { auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); + auto padding = tim::vx::PadType::VALID; std::array stride({1, 1}); std::array dilation({0, 0}); - auto padding = tim::vx::PadType::VALID; auto conv2d = graph->CreateOperation( - weight_shape[3], padding, ksize, stride, dilation); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -869,13 +856,12 @@ TEST(Conv2d, shape_4_2_1_2_float32_InputAndFilterSameWidthHeightTest) { auto output_tensor = graph->CreateTensor(output_spec); - std::array ksize({weight_shape[1], weight_shape[2]}); + auto padding = tim::vx::PadType::VALID; std::array stride({1, 1}); std::array dilation({0, 0}); - auto padding = tim::vx::PadType::VALID; auto conv2d = graph->CreateOperation( - weight_shape[3], padding, ksize, stride, dilation); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -974,13 +960,12 @@ TEST(Conv2d, shape_4_2_1_2_uint8_QuantizedTest1) { 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]}); + auto padding = tim::vx::PadType::VALID; 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); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -1080,13 +1065,12 @@ TEST(Conv2d, shape_4_2_1_2_uint8_QuantizedTest2) { 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]}); + auto padding = tim::vx::PadType::VALID; 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); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -1185,13 +1169,12 @@ TEST(Conv2d, shape_6_3_1_1_uint8_AnisotropicStridesQuantizedTest) { 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]}); + auto padding = tim::vx::PadType::VALID; 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); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -1293,13 +1276,12 @@ TEST(Conv2d, shape_9_9_1_1_uint8_DilationQuantizedTest) { 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]}); + auto padding = tim::vx::PadType::VALID; 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); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -1397,13 +1379,12 @@ TEST(Conv2d, shape_3_2_2_1_int8_QuantizedPerTensorTest) { 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]}); + auto padding = tim::vx::PadType::VALID; std::array stride({1, 1}); std::array dilation({1, 1}); - auto padding = tim::vx::PadType::VALID; auto conv2d = graph->CreateOperation( - weight_shape[3], padding, ksize, stride, dilation); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) @@ -1500,13 +1481,12 @@ TEST(Conv2d, shape_3_2_2_1_int8_QuantizedPerChannelTest) { 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]}); + auto padding = tim::vx::PadType::VALID; std::array stride({1, 1}); std::array dilation({1, 1}); - auto padding = tim::vx::PadType::VALID; auto conv2d = graph->CreateOperation( - weight_shape[3], padding, ksize, stride, dilation); + padding, stride, dilation); (*conv2d) .BindInput(input_tensor) .BindInput(weight_tensor) diff --git a/src/tim/vx/ops/depthwiseConv_test.cc b/src/tim/vx/ops/depthwiseConv_test.cc index c6c55c2..699270d 100644 --- a/src/tim/vx/ops/depthwiseConv_test.cc +++ b/src/tim/vx/ops/depthwiseConv_test.cc @@ -1,4 +1,5 @@ #include "gtest/gtest.h" +#include "src/tim/vx/test_utils.h" #include "tim/vx/context.h" #include "tim/vx/graph.h" #include "tim/vx/ops/conv2d.h" @@ -70,7 +71,7 @@ TEST(DepthwiseConv, shape_2_3_2_1_float32_SimpleTest) { EXPECT_EQ(golden, output); } -TEST(DepthwiseConv, shape_2_3_2_1_float32_StrideTest) { +TEST(DepthwiseConv, shape_2_3_2_1_float32_StrideValidTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); @@ -136,6 +137,138 @@ TEST(DepthwiseConv, shape_2_3_2_1_float32_StrideTest) { EXPECT_EQ(golden, output); } +TEST(DepthwiseConv, shape_2_3_2_1_float32_StrideSameTest) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType input_shape({2, 3, 2, 1}); //whcn + tim::vx::ShapeType weight_shape({2, 2, 4, 1}); //whoi + tim::vx::ShapeType bias_shape({weight_shape[2]}); + tim::vx::ShapeType output_shape( + {1, 2, weight_shape[2], input_shape[3]}); //whcn + + tim::vx::TensorSpec input_spec(tim::vx::DataType::FLOAT32, input_shape, + tim::vx::TensorAttribute::INPUT); + tim::vx::TensorSpec weight_spec(tim::vx::DataType::FLOAT32, weight_shape, + tim::vx::TensorAttribute::CONSTANT); + tim::vx::TensorSpec bias_spec(tim::vx::DataType::FLOAT32, bias_shape, + tim::vx::TensorAttribute::CONSTANT); + tim::vx::TensorSpec output_spec(tim::vx::DataType::FLOAT32, output_shape, + tim::vx::TensorAttribute::OUTPUT); + + // Input data nchw + std::vector input_data = {1, 7, 3, 9, 5, 11, 2, 8, 4, 10, 6, 12}; + + // weight data iohw + std::vector weight_data = {1, -9, 5, 13, 2, 10, 6, -14, + 3, -11, 7, 15, 4, 12, 8, -16}; + + // bias data + std::vector bias_data = {1, 2, 3, 4}; + + // nchw + std::vector golden = {71, -93, -34, 122, 99, -111, -20, 172}; + + 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 padding = tim::vx::PadType::SAME; + std::array stride({2, 2}); + std::array dilation({1, 1}); + int32_t multiplier = weight_shape[2] / input_shape[2]; + + auto conv2d = graph->CreateOperation( + padding, stride, dilation, multiplier); + (*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(DepthwiseConv, shape_2_3_2_1_float32_StrideSameDilationTest) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType input_shape({2, 3, 2, 1}); //whcn + tim::vx::ShapeType weight_shape({2, 2, 4, 1}); //whoi + tim::vx::ShapeType bias_shape({weight_shape[2]}); + tim::vx::ShapeType output_shape( + {1, 2, weight_shape[2], input_shape[3]}); //whcn + + tim::vx::TensorSpec input_spec(tim::vx::DataType::FLOAT32, input_shape, + tim::vx::TensorAttribute::INPUT); + tim::vx::TensorSpec weight_spec(tim::vx::DataType::FLOAT32, weight_shape, + tim::vx::TensorAttribute::CONSTANT); + tim::vx::TensorSpec bias_spec(tim::vx::DataType::FLOAT32, bias_shape, + tim::vx::TensorAttribute::CONSTANT); + tim::vx::TensorSpec output_spec(tim::vx::DataType::FLOAT32, output_shape, + tim::vx::TensorAttribute::OUTPUT); + + // Input data nchw + std::vector input_data = {1, 7, 3, 9, 5, 11, 2, 8, 4, 10, 6, 12}; + + // weight data iohw + std::vector weight_data = {1, -9, 5, 13, 2, 10, 6, -14, + 3, -11, 7, 15, 4, 12, 8, -16}; + + // bias data + std::vector bias_data = {1, 2, 3, 4}; + + // nchw + std::vector golden = {1, 1, 2, 2, 3, 3, 4, 4}; + + 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 padding = tim::vx::PadType::SAME; + std::array stride({2, 2}); + std::array dilation({10, 10}); + int32_t multiplier = weight_shape[2] / input_shape[2]; + + auto conv2d = graph->CreateOperation( + padding, stride, dilation, multiplier); + (*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(DepthwiseConv, shape_2_3_2_1_float32_PaddingTest) { auto ctx = tim::vx::Context::Create(); auto graph = ctx->CreateGraph(); @@ -471,3 +604,772 @@ TEST(DepthwiseConv, shape_2_2_1_4_float32_BatchSameTest) { EXPECT_TRUE(output_tensor->CopyDataFromTensor(output.data())); EXPECT_EQ(golden, output); } + +TEST(DepthwiseConv, shape_2_3_2_1_uint8_QuantizedTest) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType input_shape({2, 3, 2, 1}); //whcn + tim::vx::ShapeType weight_shape({2, 2, 4, 1}); //whoi + tim::vx::ShapeType bias_shape({weight_shape[2]}); + tim::vx::ShapeType output_shape( + {1, 2, weight_shape[2], 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, 7, 3, 9, 5, 11, 2, 8, 4, 10, 6, 12}; + std::vector input_data = + Quantize(input_data_float, scalesInput[0], zeroPointsInput[0]); + + // weight data iohw + // min:-63.5 max:64 scale:0.5 Zp:-1 + std::vector weight_data_float = {1, -9, 5, 13, 2, 10, 6, -14, + 3, -11, 7, 15, 4, 12, 8, -16}; + std::vector weight_data = + Quantize(weight_data_float, scalesWeight[0], zeroPointsInput[0]); + + // bias data + // scale:0.25 Zp:0 + std::vector bias_data_float = {1, 2, 3, 4}; + std::vector bias_data = + Quantize(bias_data_float, scalesBias[0], zeroPointsBias[0]); + + // golden + // min:-127 max:128 scale:1 Zp:-1 + std::vector golden_float = {71, 91, -34, -26, 99, 127, -20, -4}; + 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); + + auto padding = tim::vx::PadType::VALID; + std::array stride({1, 1}); + std::array dilation({1, 1}); + int32_t multiplier = weight_shape[2] / input_shape[2]; + + auto conv2d = graph->CreateOperation( + padding, stride, dilation, multiplier); + (*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(DepthwiseConv, shape_9_9_1_1_uint8_QuantizedDilationdValidTest) { + 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}); //whoi + tim::vx::ShapeType bias_shape({weight_shape[2]}); + tim::vx::ShapeType output_shape( + {3, 3, weight_shape[2], input_shape[3]}); //whcn + + float InputMin = 0, InputMax = 255, WeightMin = 0, WeightMax = 255, + 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:0 max:255 scale:1 Zp:-128 + 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}; + std::vector input_data = + Quantize(input_data_float, scalesInput[0], zeroPointsInput[0]); + + // weight data iohw + // min:0 max:255 scale:1 Zp:-128 + std::vector weight_data_float = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector weight_data = + Quantize(weight_data_float, scalesWeight[0], zeroPointsInput[0]); + + // bias data + // scale:1 Zp:0 + std::vector bias_data_float = {0}; + std::vector bias_data = + Quantize(bias_data_float, scalesBias[0], zeroPointsBias[0]); + + // golden + // min:0 max:255 scale:1 Zp:-128 + std::vector golden_float = {5, 5, 5, 5, 5, 5, 5, 5, 5}; + 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); + + auto padding = tim::vx::PadType::VALID; + std::array stride({1, 1}); + std::array dilation({3, 3}); + int32_t multiplier = weight_shape[2] / input_shape[2]; + + auto conv2d = graph->CreateOperation( + padding, stride, dilation, multiplier); + (*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(DepthwiseConv, shape_3_3_1_1_uint8_QuantizedDilationdSameTest) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType input_shape({3, 3, 1, 1}); //whcn + tim::vx::ShapeType weight_shape({2, 2, 1, 1}); //whoi + tim::vx::ShapeType bias_shape({weight_shape[2]}); + tim::vx::ShapeType output_shape( + {3, 3, weight_shape[2], input_shape[3]}); //whcn + + float InputMin = 0, InputMax = 255, WeightMin = 0, WeightMax = 255, + 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:0 max:255 scale:1 Zp:-128 + std::vector input_data_float = {1, 1, 1, 1, 1, 1, 1, 1, 1}; + std::vector input_data = + Quantize(input_data_float, scalesInput[0], zeroPointsInput[0]); + + // weight data iohw + // min:0 max:255 scale:1 Zp:-128 + std::vector weight_data_float = {1, 2, 3, 4}; + std::vector weight_data = + Quantize(weight_data_float, scalesWeight[0], zeroPointsInput[0]); + + // bias data + // scale:1 Zp:0 + std::vector bias_data_float = {0}; + std::vector bias_data = + Quantize(bias_data_float, scalesBias[0], zeroPointsBias[0]); + + // golden + // min:0 max:255 scale:1 Zp:-128 + std::vector golden_float = {4, 7, 3, 6, 10, 4, 2, 3, 1}; + 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); + + auto padding = tim::vx::PadType::SAME; + std::array stride({1, 1}); + std::array dilation({2, 2}); + int32_t multiplier = weight_shape[2] / input_shape[2]; + + auto conv2d = graph->CreateOperation( + padding, stride, dilation, multiplier); + (*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(DepthwiseConv, shape_3_2_2_1_int8_PerTensorTest) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType input_shape({3, 2, 2, 1}); //whcn + tim::vx::ShapeType weight_shape({2, 2, 4, 1}); //whoi + tim::vx::ShapeType bias_shape({weight_shape[2]}); + tim::vx::ShapeType output_shape( + {2, 1, weight_shape[2], input_shape[3]}); //whcn + + float InputMin = -63.5, InputMax = 64, OutputMin = -63.5, OutputMax = 64; + + std::pair scalesAndZp; + + scalesAndZp = QuantizationParams(InputMin, InputMax); + std::vector scalesInput = {scalesAndZp.first}; + std::vector zeroPointsInput = {scalesAndZp.second}; + + std::vector scalesWeight = {1}; + std::vector zeroPointsWeight = {0}; + + int32_t sizeofweight = scalesWeight.size(); + std::vector scalesBias(sizeofweight); + std::vector zeroPointsBias(sizeofweight); + for (int i = 0; i < sizeofweight; i++) { + scalesBias[i] = scalesInput[0] * scalesWeight[i]; + zeroPointsBias[i] = 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::INT8, input_shape, + tim::vx::TensorAttribute::INPUT, quantInput); + tim::vx::TensorSpec weight_spec(tim::vx::DataType::INT8, 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::INT8, 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, 1, -2, 4, 2, -3, + 2, -1, -3, 3, -2, -4}; + std::vector input_data = + Quantize(input_data_float, scalesInput[0], zeroPointsInput[0]); + + // weight data iohw + std::vector weight_data_float = {1, 3, 7, 3, 2, 4, 8, 4, + 3, 5, 5, 1, 4, 6, 6, 2}; + std::vector weight_data = + Quantize(weight_data_float, scalesWeight[0], zeroPointsWeight[0]); + + // bias data + std::vector bias_data = {6, -4, 8, 12}; + + // golden + // min:-63.5 max:64 scale:0.5 Zp:-1 + std::vector golden_float = {43, 3, 48, -4, 18, -28, 22, -36}; + 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); + + auto padding = tim::vx::PadType::VALID; + std::array stride({1, 1}); + std::array dilation({1, 1}); + int32_t multiplier = weight_shape[2] / input_shape[2]; + + auto conv2d = graph->CreateOperation( + padding, stride, dilation, multiplier); + (*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(DepthwiseConv, shape_3_2_2_1_int8_PerAxisTest) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType input_shape({3, 2, 2, 1}); //whcn + tim::vx::ShapeType weight_shape({2, 2, 4, 1}); //whoi + tim::vx::ShapeType bias_shape({weight_shape[2]}); + tim::vx::ShapeType output_shape( + {2, 1, weight_shape[2], input_shape[3]}); //whcn + + float InputMin = -63.5, InputMax = 64, OutputMin = -63.5, OutputMax = 64; + + std::pair scalesAndZp; + + scalesAndZp = QuantizationParams(InputMin, InputMax); + std::vector scalesInput = {scalesAndZp.first}; + std::vector zeroPointsInput = {scalesAndZp.second}; + + std::vector scalesWeight = {1, 2, 3, 4}; + std::vector zeroPointsWeight = {0, 0, 0, 0}; + + int32_t sizeofweight = scalesWeight.size(); + std::vector scalesBias(sizeofweight); + std::vector zeroPointsBias(sizeofweight); + for (int i = 0; i < sizeofweight; i++) { + scalesBias[i] = scalesInput[0] * scalesWeight[i]; + zeroPointsBias[i] = 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::SYMMETRIC_PER_CHANNEL, + 2, scalesWeight, zeroPointsWeight); + tim::vx::Quantization quantBias(tim::vx::QuantType::SYMMETRIC_PER_CHANNEL, 0, + scalesBias, zeroPointsBias); + tim::vx::Quantization quantOutput(tim::vx::QuantType::ASYMMETRIC, 2, + scalesOutput, zeroPointsOutput); + + tim::vx::TensorSpec input_spec(tim::vx::DataType::INT8, input_shape, + tim::vx::TensorAttribute::INPUT, quantInput); + tim::vx::TensorSpec weight_spec(tim::vx::DataType::INT8, 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::INT8, 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, 1, -2, 4, 2, -3, + 2, -1, -3, 3, -2, -4}; + + std::vector input_data = + Quantize(input_data_float, scalesInput[0], zeroPointsInput[0]); + + // weight data iohw + std::vector weight_data = {1, 3, 7, 3, 1, 2, 4, 2, + 1, 2, 2, 0, 1, 2, 2, 1}; + + // bias data + std::vector bias_data = {6, -2, 2, 3}; + + // golden + // min:-63.5 max:64 scale:0.5 Zp:-1 + std::vector golden_float = {43, 3, 48, -4, 21, -30, 22, -54}; + 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); + + auto padding = tim::vx::PadType::VALID; + std::array stride({1, 1}); + std::array dilation({1, 1}); + int32_t multiplier = weight_shape[2] / input_shape[2]; + + auto conv2d = graph->CreateOperation( + padding, stride, dilation, multiplier); + (*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(DepthwiseConv, shape_3_3_8_1_int8_PerChannelValidTest) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType input_shape({3, 3, 8, 1}); //whcn + tim::vx::ShapeType weight_shape({3, 3, 8, 1}); //whoi + tim::vx::ShapeType bias_shape({weight_shape[2]}); + tim::vx::ShapeType output_shape( + {1, 1, weight_shape[2], input_shape[3]}); //whcn + + float InputMin = -63.5, InputMax = 64, OutputMin = -63.5, OutputMax = 64; + + std::pair scalesAndZp; + + scalesAndZp = QuantizationParams(InputMin, InputMax); + std::vector scalesInput = {scalesAndZp.first}; + std::vector zeroPointsInput = {scalesAndZp.second}; + + std::vector scalesWeight = {0.1, 0.2, 0.3, 0.4, 0.4, 0.3, 0.2, 0.1}; + std::vector zeroPointsWeight = {0, 0, 0, 0, 0, 0, 0, 0}; + + int32_t sizeofweight = scalesWeight.size(); + std::vector scalesBias(sizeofweight); + std::vector zeroPointsBias(sizeofweight); + for (int i = 0; i < sizeofweight; i++) { + scalesBias[i] = scalesInput[0] * scalesWeight[i]; + zeroPointsBias[i] = 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::SYMMETRIC_PER_CHANNEL, + 2, scalesWeight, zeroPointsWeight); + tim::vx::Quantization quantBias(tim::vx::QuantType::SYMMETRIC_PER_CHANNEL, 0, + scalesBias, zeroPointsBias); + tim::vx::Quantization quantOutput(tim::vx::QuantType::ASYMMETRIC, 2, + scalesOutput, zeroPointsOutput); + + tim::vx::TensorSpec input_spec(tim::vx::DataType::INT8, input_shape, + tim::vx::TensorAttribute::INPUT, quantInput); + tim::vx::TensorSpec weight_spec(tim::vx::DataType::INT8, 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::INT8, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + std::vector input_data = + Quantize(input_data_float, scalesInput[0], zeroPointsInput[0]); + + // weight data iohw + std::vector weight_data = { + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 80, 80, 80, 80, 80, 80, 80, 80, 80}; + + // bias data + std::vector bias_data = {0, 0, 0, 0, 0, 0, 0, 0}; + + // golden + // min:-63.5 max:64 scale:0.5 Zp:-1 + std::vector golden_float = {9, 18, 0, 0, 47, 54, 0, 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); + + auto padding = tim::vx::PadType::VALID; + std::array stride({1, 1}); + std::array dilation({1, 1}); + int32_t multiplier = weight_shape[2] / input_shape[2]; + + auto conv2d = graph->CreateOperation( + padding, stride, dilation, multiplier); + (*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(DepthwiseConv, shape_3_3_8_1_int8_PerChannelSameTest) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType input_shape({3, 3, 8, 1}); //whcn + tim::vx::ShapeType weight_shape({3, 3, 8, 1}); //whoi + tim::vx::ShapeType bias_shape({weight_shape[2]}); + tim::vx::ShapeType output_shape( + {3, 3, weight_shape[2], input_shape[3]}); //whcn + + float InputMin = -63.5, InputMax = 64, OutputMin = -63.5, OutputMax = 64; + + std::pair scalesAndZp; + + scalesAndZp = QuantizationParams(InputMin, InputMax); + std::vector scalesInput = {scalesAndZp.first}; + std::vector zeroPointsInput = {scalesAndZp.second}; + + std::vector scalesWeight = {0.1, 0.2, 0.3, 0.4, 0.4, 0.3, 0.2, 0.1}; + std::vector zeroPointsWeight = {0, 0, 0, 0, 0, 0, 0, 0}; + + int32_t sizeofweight = scalesWeight.size(); + std::vector scalesBias(sizeofweight); + std::vector zeroPointsBias(sizeofweight); + for (int i = 0; i < sizeofweight; i++) { + scalesBias[i] = scalesInput[0] * scalesWeight[i]; + zeroPointsBias[i] = 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::SYMMETRIC_PER_CHANNEL, + 2, scalesWeight, zeroPointsWeight); + tim::vx::Quantization quantBias(tim::vx::QuantType::SYMMETRIC_PER_CHANNEL, 0, + scalesBias, zeroPointsBias); + tim::vx::Quantization quantOutput(tim::vx::QuantType::ASYMMETRIC, 2, + scalesOutput, zeroPointsOutput); + + tim::vx::TensorSpec input_spec(tim::vx::DataType::INT8, input_shape, + tim::vx::TensorAttribute::INPUT, quantInput); + tim::vx::TensorSpec weight_spec(tim::vx::DataType::INT8, 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::INT8, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + std::vector input_data = + Quantize(input_data_float, scalesInput[0], zeroPointsInput[0]); + + // weight data iohw + std::vector weight_data = { + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 80, 80, 80, 80, 80, 80, 80, 80, 80}; + + // bias data + std::vector bias_data = {0, 0, 0, 0, 0, 0, 0, 0}; + + // golden + // min:-63.5 max:64 scale:0.5 Zp:-1 + std::vector golden_float = { + 4, 6, 4, 6, 9, 6, 4, 6, 4, 8, 12, 8, 12, 18, 12, 8, 12, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 21, 31, 21, 31, 47, 31, 21, 31, 21, 24, 36, 24, 36, 54, 36, 24, 36, 24, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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); + + auto padding = tim::vx::PadType::SAME; + std::array stride({1, 1}); + std::array dilation({1, 1}); + int32_t multiplier = weight_shape[2] / input_shape[2]; + + auto conv2d = graph->CreateOperation( + padding, stride, dilation, multiplier); + (*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); +}