add uint8 quantized unit_test for conv2d
Signed-off-by: Jing.Deng <Jing.Deng@verisilicon.com>
This commit is contained in:
parent
9e10d88fc7
commit
8d35c4dd7a
7
BUILD
7
BUILD
|
|
@ -35,7 +35,8 @@ cc_library(
|
||||||
"src/tim/transform/permute_vector.h",
|
"src/tim/transform/permute_vector.h",
|
||||||
"src/tim/transform/layout_infer_context.h",
|
"src/tim/transform/layout_infer_context.h",
|
||||||
] + glob([
|
] + glob([
|
||||||
"src/tim/vx/ops/*.cc"
|
"src/tim/vx/ops/*.cc",
|
||||||
|
"src/tim/vx/ops/*.h"
|
||||||
], exclude = ["src/tim/vx/ops/*_test.cc"]
|
], exclude = ["src/tim/vx/ops/*_test.cc"]
|
||||||
) + glob(["src/tim/transform/ops/*.*"]),
|
) + glob(["src/tim/transform/ops/*.*"]),
|
||||||
deps = [
|
deps = [
|
||||||
|
|
@ -94,7 +95,9 @@ cc_binary(
|
||||||
cc_test (
|
cc_test (
|
||||||
name = "unit_test",
|
name = "unit_test",
|
||||||
copts = ["-std=c++14", "-Werror"],
|
copts = ["-std=c++14", "-Werror"],
|
||||||
srcs = glob(["src/tim/**/*_test.cc"]),
|
srcs = [
|
||||||
|
"src/tim/vx/test_utils.h",
|
||||||
|
] + glob(["src/tim/**/*_test.cc"]),
|
||||||
deps = [
|
deps = [
|
||||||
"@gtest//:gtest",
|
"@gtest//:gtest",
|
||||||
"@gtest//:gtest_main",
|
"@gtest//:gtest_main",
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
#include "tim/vx/ops/conv2d.h"
|
#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/transform/layout_inference.h"
|
||||||
#include "tim/vx/context.h"
|
#include "tim/vx/context.h"
|
||||||
#include "tim/vx/graph.h"
|
#include "tim/vx/graph.h"
|
||||||
|
#include "tim/vx/types.h"
|
||||||
#include "gtest/gtest.h"
|
|
||||||
|
|
||||||
TEST(Conv2d, shape_4_2_1_1_float32_PaddingTest) {
|
TEST(Conv2d, shape_4_2_1_1_float32_PaddingTest) {
|
||||||
auto ctx = tim::vx::Context::Create();
|
auto ctx = tim::vx::Context::Create();
|
||||||
|
|
@ -103,8 +104,7 @@ TEST(Conv2d, shape_4_2_2_2_float32_PointwiseTest) {
|
||||||
// Input data nchw
|
// Input data nchw
|
||||||
std::vector<float> input_data = {
|
std::vector<float> 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, 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
|
// weight data oihw
|
||||||
std::vector<float> weight_data = {
|
std::vector<float> weight_data = {
|
||||||
|
|
@ -115,10 +115,8 @@ TEST(Conv2d, shape_4_2_2_2_float32_PointwiseTest) {
|
||||||
std::vector<float> bias_data = {0};
|
std::vector<float> bias_data = {0};
|
||||||
|
|
||||||
// nchw
|
// nchw
|
||||||
std::vector<float> golden = {
|
std::vector<float> golden = {1.5, 1.5, 1.5, 1.5, 3, 3, 3, 3,
|
||||||
1.5, 1.5, 1.5, 1.5, 3, 3, 3, 3,
|
1.5, 3, 4.5, 6, 1.5, 3, 4.5, 6};
|
||||||
1.5, 3, 4.5, 6, 1.5, 3, 4.5, 6
|
|
||||||
};
|
|
||||||
|
|
||||||
auto input_tensor = graph->CreateTensor(input_spec);
|
auto input_tensor = graph->CreateTensor(input_spec);
|
||||||
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
||||||
|
|
@ -184,9 +182,7 @@ TEST(Conv2d, shape_4_2_1_2_float32_SimpleTest) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// weight data oihw
|
// weight data oihw
|
||||||
std::vector<float> weight_data = {
|
std::vector<float> weight_data = {1, 2, 3, 4, -1, 1, -1, 1, -1, -1, 1, 1};
|
||||||
1, 2, 3, 4, -1, 1, -1, 1, -1, -1, 1, 1
|
|
||||||
};
|
|
||||||
|
|
||||||
// bias data
|
// bias data
|
||||||
std::vector<float> bias_data = {1, 2, 3};
|
std::vector<float> bias_data = {1, 2, 3};
|
||||||
|
|
@ -315,9 +311,8 @@ TEST(Conv2d, shape_6_3_1_1_float32_SimpleAnisotropicStridesTest) {
|
||||||
tim::vx::TensorAttribute::OUTPUT);
|
tim::vx::TensorAttribute::OUTPUT);
|
||||||
|
|
||||||
// Input data nchw
|
// Input data nchw
|
||||||
std::vector<float> input_data = {
|
std::vector<float> input_data = {3, 2, 1, -1, -2, -3, 4, 3, 2,
|
||||||
3, 2, 1, -1, -2, -3, 4, 3, 2, -2, -3, -4, 5, 4, 3, -3, -4, -5
|
-2, -3, -4, 5, 4, 3, -3, -4, -5};
|
||||||
};
|
|
||||||
|
|
||||||
// weight data oihw
|
// weight data oihw
|
||||||
std::vector<float> weight_data = {
|
std::vector<float> weight_data = {
|
||||||
|
|
@ -388,23 +383,17 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedTest) {
|
||||||
tim::vx::TensorAttribute::OUTPUT);
|
tim::vx::TensorAttribute::OUTPUT);
|
||||||
|
|
||||||
// Input data nchw
|
// Input data nchw
|
||||||
std::vector<float> input_data = {
|
std::vector<float> input_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
|
|
||||||
};
|
|
||||||
|
|
||||||
// weight data oihw
|
// weight data oihw
|
||||||
std::vector<float> weight_data = {
|
std::vector<float> weight_data = {1, 4, 7, 2, 5, 8, 3, 6, 9};
|
||||||
1, 4, 7, 2, 5, 8, 3, 6, 9
|
|
||||||
};
|
|
||||||
|
|
||||||
// bias data
|
// bias data
|
||||||
std::vector<float> bias_data = {0};
|
std::vector<float> bias_data = {0};
|
||||||
|
|
||||||
// nchw
|
// nchw
|
||||||
std::vector<float> golden = {
|
std::vector<float> golden = {105, 150, 183, 95, 235, 312,
|
||||||
105, 150, 183, 95, 235, 312,
|
357, 178, 187, 234, 261, 121};
|
||||||
357, 178, 187, 234, 261, 121
|
|
||||||
};
|
|
||||||
|
|
||||||
auto input_tensor = graph->CreateTensor(input_spec);
|
auto input_tensor = graph->CreateTensor(input_spec);
|
||||||
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
||||||
|
|
@ -460,23 +449,17 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedConstFilterTest) {
|
||||||
tim::vx::TensorAttribute::OUTPUT);
|
tim::vx::TensorAttribute::OUTPUT);
|
||||||
|
|
||||||
// Input data nchw
|
// Input data nchw
|
||||||
std::vector<float> input_data = {
|
std::vector<float> input_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
|
|
||||||
};
|
|
||||||
|
|
||||||
// weight data oihw
|
// weight data oihw
|
||||||
std::vector<float> weight_data = {
|
std::vector<float> weight_data = {1, 4, 7, 2, 5, 8, 3, 6, 9};
|
||||||
1, 4, 7, 2, 5, 8, 3, 6, 9
|
|
||||||
};
|
|
||||||
|
|
||||||
// bias data
|
// bias data
|
||||||
std::vector<float> bias_data = {0};
|
std::vector<float> bias_data = {0};
|
||||||
|
|
||||||
// nchw
|
// nchw
|
||||||
std::vector<float> golden = {
|
std::vector<float> golden = {105, 150, 183, 95, 235, 312,
|
||||||
105, 150, 183, 95, 235, 312,
|
357, 178, 187, 234, 261, 121};
|
||||||
357, 178, 187, 234, 261, 121
|
|
||||||
};
|
|
||||||
|
|
||||||
auto input_tensor = graph->CreateTensor(input_spec);
|
auto input_tensor = graph->CreateTensor(input_spec);
|
||||||
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
||||||
|
|
@ -532,22 +515,17 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedBiasTest) {
|
||||||
tim::vx::TensorAttribute::OUTPUT);
|
tim::vx::TensorAttribute::OUTPUT);
|
||||||
|
|
||||||
// Input data nchw
|
// Input data nchw
|
||||||
std::vector<float> input_data = {
|
std::vector<float> input_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
|
|
||||||
};
|
|
||||||
|
|
||||||
// weight data oihw
|
// weight data oihw
|
||||||
std::vector<float> weight_data = {
|
std::vector<float> weight_data = {1, 4, 7, 2, 5, 8, 3, 6, 9};
|
||||||
1, 4, 7, 2, 5, 8, 3, 6, 9
|
|
||||||
};
|
|
||||||
|
|
||||||
// bias data
|
// bias data
|
||||||
std::vector<float> bias_data = {10};
|
std::vector<float> bias_data = {10};
|
||||||
|
|
||||||
// nchw
|
// nchw
|
||||||
std::vector<float> golden = {
|
std::vector<float> golden = {115, 160, 193, 105, 245, 322,
|
||||||
115, 160, 193, 105, 245, 322, 367, 188, 197, 244, 271, 131
|
367, 188, 197, 244, 271, 131};
|
||||||
};
|
|
||||||
|
|
||||||
auto input_tensor = graph->CreateTensor(input_spec);
|
auto input_tensor = graph->CreateTensor(input_spec);
|
||||||
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
||||||
|
|
@ -603,22 +581,16 @@ TEST(Conv2d, shape_4_3_1_1_float32_HandCalculatedValidTest) {
|
||||||
tim::vx::TensorAttribute::OUTPUT);
|
tim::vx::TensorAttribute::OUTPUT);
|
||||||
|
|
||||||
// Input data nchw
|
// Input data nchw
|
||||||
std::vector<float> input_data = {
|
std::vector<float> input_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
|
|
||||||
};
|
|
||||||
|
|
||||||
// weight data oihw
|
// weight data oihw
|
||||||
std::vector<float> weight_data = {
|
std::vector<float> weight_data = {1, 4, 7, 2, 5, 8, 3, 6, 9};
|
||||||
1, 4, 7, 2, 5, 8, 3, 6, 9
|
|
||||||
};
|
|
||||||
|
|
||||||
// bias data
|
// bias data
|
||||||
std::vector<float> bias_data = {0};
|
std::vector<float> bias_data = {0};
|
||||||
|
|
||||||
// nchw
|
// nchw
|
||||||
std::vector<float> golden = {
|
std::vector<float> golden = {312, 357};
|
||||||
312, 357
|
|
||||||
};
|
|
||||||
|
|
||||||
auto input_tensor = graph->CreateTensor(input_spec);
|
auto input_tensor = graph->CreateTensor(input_spec);
|
||||||
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
||||||
|
|
@ -676,13 +648,10 @@ TEST(Conv2d, shape_4_2_2_2_float32_DisabledPointwiseMultifilterTest) {
|
||||||
// Input data nchw
|
// Input data nchw
|
||||||
std::vector<float> input_data = {
|
std::vector<float> 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, 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
|
// weight data oihw
|
||||||
std::vector<float> weight_data = {
|
std::vector<float> weight_data = {1, 2, 2, 3};
|
||||||
1, 2, 2, 3
|
|
||||||
};
|
|
||||||
|
|
||||||
// bias data
|
// bias data
|
||||||
std::vector<float> bias_data = {0};
|
std::vector<float> bias_data = {0};
|
||||||
|
|
@ -690,8 +659,7 @@ TEST(Conv2d, shape_4_2_2_2_float32_DisabledPointwiseMultifilterTest) {
|
||||||
// nchw
|
// nchw
|
||||||
std::vector<float> golden = {
|
std::vector<float> 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, 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 input_tensor = graph->CreateTensor(input_spec);
|
||||||
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
||||||
|
|
@ -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, 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, 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, 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
|
// weight data oihw
|
||||||
std::vector<float> weight_data = {
|
std::vector<float> weight_data = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||||
1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
||||||
};
|
|
||||||
|
|
||||||
// bias data
|
// bias data
|
||||||
std::vector<float> bias_data = {0};
|
std::vector<float> bias_data = {0};
|
||||||
|
|
@ -819,22 +784,18 @@ TEST(Conv2d, shape_4_2_1_2_float32_StrideTest) {
|
||||||
tim::vx::TensorAttribute::OUTPUT);
|
tim::vx::TensorAttribute::OUTPUT);
|
||||||
|
|
||||||
// Input data nchw
|
// Input data nchw
|
||||||
std::vector<float> input_data = {
|
std::vector<float> input_data = {1, 1, 1, 1, 2, 2, 3, 2,
|
||||||
1, 1, 1, 1, 2, 2, 3, 2, 1, 2, 3, 4, 1, 2, 4, 4
|
1, 2, 3, 4, 1, 2, 4, 4};
|
||||||
};
|
|
||||||
|
|
||||||
// weight data oihw
|
// weight data oihw
|
||||||
std::vector<float> weight_data = {
|
std::vector<float> weight_data = {1, 2, 3, 4, -1, 1, -1, 1, -1, -1, 1, 1};
|
||||||
1, 2, 3, 4, -1, 1, -1, 1, -1, -1, 1, 1
|
|
||||||
};
|
|
||||||
|
|
||||||
// bias data
|
// bias data
|
||||||
std::vector<float> bias_data = {1, 2, 3};
|
std::vector<float> bias_data = {1, 2, 3};
|
||||||
|
|
||||||
// nchw
|
// nchw
|
||||||
std::vector<float> golden = {
|
std::vector<float> golden = {18, 22, 21, 2, 3, 1, 5, 6, 6,
|
||||||
18, 22, 21, 2, 3, 1, 5, 6, 6, 17, 31, 40, 4, 5, 3, 3, 4, 4
|
17, 31, 40, 4, 5, 3, 3, 4, 4};
|
||||||
};
|
|
||||||
|
|
||||||
auto input_tensor = graph->CreateTensor(input_spec);
|
auto input_tensor = graph->CreateTensor(input_spec);
|
||||||
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
||||||
|
|
@ -890,22 +851,17 @@ TEST(Conv2d, shape_4_2_1_2_float32_InputAndFilterSameWidthHeightTest) {
|
||||||
tim::vx::TensorAttribute::OUTPUT);
|
tim::vx::TensorAttribute::OUTPUT);
|
||||||
|
|
||||||
// Input data nchw
|
// Input data nchw
|
||||||
std::vector<float> input_data = {
|
std::vector<float> input_data = {1, 1, 1, 1, 2, 2, 2, 2,
|
||||||
1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 3, 4, 1, 2, 3, 4
|
1, 2, 3, 4, 1, 2, 3, 4};
|
||||||
};
|
|
||||||
|
|
||||||
// weight data oihw
|
// weight data oihw
|
||||||
std::vector<float> weight_data = {
|
std::vector<float> weight_data = {1, 2, 3, 4, -1, -1, 1, 1};
|
||||||
1, 2, 3, 4, -1, -1, 1, 1
|
|
||||||
};
|
|
||||||
|
|
||||||
// bias data
|
// bias data
|
||||||
std::vector<float> bias_data = {0};
|
std::vector<float> bias_data = {0};
|
||||||
|
|
||||||
// nchw
|
// nchw
|
||||||
std::vector<float> golden = {
|
std::vector<float> golden = {10, 34};
|
||||||
10, 34
|
|
||||||
};
|
|
||||||
|
|
||||||
auto input_tensor = graph->CreateTensor(input_spec);
|
auto input_tensor = graph->CreateTensor(input_spec);
|
||||||
auto weight_tensor = graph->CreateTensor(weight_spec, weight_data.data());
|
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_TRUE(output_tensor->CopyDataFromTensor(output.data()));
|
||||||
EXPECT_EQ(golden, output);
|
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<float, int32_t> scalesAndZp;
|
||||||
|
|
||||||
|
scalesAndZp = QuantizationParams<u_int8_t>(InputMin, InputMax);
|
||||||
|
std::vector<float> scalesInput = {scalesAndZp.first};
|
||||||
|
std::vector<int32_t> zeroPointsInput = {scalesAndZp.second};
|
||||||
|
|
||||||
|
scalesAndZp = QuantizationParams<u_int8_t>(WeightMin, WeightMax);
|
||||||
|
std::vector<float> scalesWeight = {scalesAndZp.first};
|
||||||
|
std::vector<int32_t> zeroPointsWeight = {scalesAndZp.second};
|
||||||
|
|
||||||
|
std::vector<float> scalesBias = {scalesInput[0] * scalesWeight[0]};
|
||||||
|
std::vector<int32_t> zeroPointsBias = {0};
|
||||||
|
|
||||||
|
scalesAndZp = QuantizationParams<u_int8_t>(OutputMin, OutputMax);
|
||||||
|
std::vector<float> scalesOutput = {scalesAndZp.first};
|
||||||
|
std::vector<int32_t> 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<float> 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<float> weight_data_float = {1, 2, 3, 4, -1, 1,
|
||||||
|
-1, 1, -1, -1, 1, 1};
|
||||||
|
// bias data
|
||||||
|
// scale:0.25 Zp:0
|
||||||
|
std::vector<float> bias_data_float = {1, 2, 3};
|
||||||
|
// golden data
|
||||||
|
//min:-127 max:128 scale:1 Zp:-1
|
||||||
|
std::vector<float> golden_float = {18, 18, 2, 2, 5, 5, 17, 37, 4, 4, 3, 3};
|
||||||
|
|
||||||
|
std::vector<u_int8_t> input_data =
|
||||||
|
Quantize<uint8_t>(input_data_float, scalesInput[0], zeroPointsInput[0]);
|
||||||
|
std::vector<u_int8_t> weight_data =
|
||||||
|
Quantize<uint8_t>(weight_data_float, scalesWeight[0], zeroPointsInput[0]);
|
||||||
|
std::vector<int32_t> bias_data =
|
||||||
|
Quantize<int32_t>(bias_data_float, scalesBias[0], zeroPointsBias[0]);
|
||||||
|
std::vector<u_int8_t> golden =
|
||||||
|
Quantize<uint8_t>(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<uint32_t, 2> ksize({weight_shape[1], weight_shape[2]});
|
||||||
|
std::array<uint32_t, 2> stride({2, 2});
|
||||||
|
std::array<uint32_t, 2> dilation({1, 1});
|
||||||
|
auto padding = tim::vx::PadType::VALID;
|
||||||
|
|
||||||
|
auto conv2d = graph->CreateOperation<tim::vx::ops::Conv2d>(
|
||||||
|
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<u_int8_t> 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<float, int32_t> scalesAndZp;
|
||||||
|
|
||||||
|
scalesAndZp = QuantizationParams<u_int8_t>(InputMin, InputMax);
|
||||||
|
std::vector<float> scalesInput = {scalesAndZp.first};
|
||||||
|
std::vector<int32_t> zeroPointsInput = {scalesAndZp.second};
|
||||||
|
|
||||||
|
scalesAndZp = QuantizationParams<u_int8_t>(WeightMin, WeightMax);
|
||||||
|
std::vector<float> scalesWeight = {scalesAndZp.first};
|
||||||
|
std::vector<int32_t> zeroPointsWeight = {scalesAndZp.second};
|
||||||
|
|
||||||
|
std::vector<float> scalesBias = {scalesInput[0] * scalesWeight[0]};
|
||||||
|
std::vector<int32_t> zeroPointsBias = {0};
|
||||||
|
|
||||||
|
scalesAndZp = QuantizationParams<u_int8_t>(OutputMin, OutputMax);
|
||||||
|
std::vector<float> scalesOutput = {scalesAndZp.first};
|
||||||
|
std::vector<int32_t> 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<float> 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<float> weight_data_float = {1, 2, 3, 4, -1, 1,
|
||||||
|
-1, 1, -1, -1, 1, 1};
|
||||||
|
// bias data
|
||||||
|
// scale:1.0116 Zp:0
|
||||||
|
std::vector<float> bias_data_float = {1, 2, 3};
|
||||||
|
// golden data
|
||||||
|
// min:-127 max:128 scale:1 Zp:-1
|
||||||
|
std::vector<float> golden_float = {18, 18, 2, 2, 5, 5, 17, 37, 4, 4, 3, 3};
|
||||||
|
|
||||||
|
std::vector<u_int8_t> input_data =
|
||||||
|
Quantize<uint8_t>(input_data_float, scalesInput[0], zeroPointsInput[0]);
|
||||||
|
std::vector<u_int8_t> weight_data =
|
||||||
|
Quantize<uint8_t>(weight_data_float, scalesWeight[0], zeroPointsInput[0]);
|
||||||
|
std::vector<int32_t> bias_data =
|
||||||
|
Quantize<int32_t>(bias_data_float, scalesBias[0], zeroPointsBias[0]);
|
||||||
|
std::vector<u_int8_t> golden =
|
||||||
|
Quantize<uint8_t>(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<uint32_t, 2> ksize({weight_shape[1], weight_shape[2]});
|
||||||
|
std::array<uint32_t, 2> stride({2, 2});
|
||||||
|
std::array<uint32_t, 2> dilation({1, 1});
|
||||||
|
auto padding = tim::vx::PadType::VALID;
|
||||||
|
|
||||||
|
auto conv2d = graph->CreateOperation<tim::vx::ops::Conv2d>(
|
||||||
|
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<u_int8_t> 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<float, int32_t> scalesAndZp;
|
||||||
|
|
||||||
|
scalesAndZp = QuantizationParams<u_int8_t>(InputMin, InputMax);
|
||||||
|
std::vector<float> scalesInput = {scalesAndZp.first};
|
||||||
|
std::vector<int32_t> zeroPointsInput = {scalesAndZp.second};
|
||||||
|
|
||||||
|
scalesAndZp = QuantizationParams<u_int8_t>(WeightMin, WeightMax);
|
||||||
|
std::vector<float> scalesWeight = {scalesAndZp.first};
|
||||||
|
std::vector<int32_t> zeroPointsWeight = {scalesAndZp.second};
|
||||||
|
|
||||||
|
std::vector<float> scalesBias = {scalesInput[0] * scalesWeight[0]};
|
||||||
|
std::vector<int32_t> zeroPointsBias = {0};
|
||||||
|
|
||||||
|
scalesAndZp = QuantizationParams<u_int8_t>(OutputMin, OutputMax);
|
||||||
|
std::vector<float> scalesOutput = {scalesAndZp.first};
|
||||||
|
std::vector<int32_t> 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<float> 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<float> weight_data_float = {1, 2, 3, 4};
|
||||||
|
// bias data
|
||||||
|
// scale:0.25 Zp:0
|
||||||
|
std::vector<float> bias_data_float = {-1};
|
||||||
|
// golden data
|
||||||
|
//min:-127 max:128 scale:1 Zp:-1
|
||||||
|
std::vector<float> golden_float = {30, -24, 40, -34};
|
||||||
|
|
||||||
|
std::vector<u_int8_t> input_data =
|
||||||
|
Quantize<uint8_t>(input_data_float, scalesInput[0], zeroPointsInput[0]);
|
||||||
|
std::vector<u_int8_t> weight_data =
|
||||||
|
Quantize<uint8_t>(weight_data_float, scalesWeight[0], zeroPointsInput[0]);
|
||||||
|
std::vector<int32_t> bias_data =
|
||||||
|
Quantize<int32_t>(bias_data_float, scalesBias[0], zeroPointsBias[0]);
|
||||||
|
std::vector<u_int8_t> golden =
|
||||||
|
Quantize<uint8_t>(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<uint32_t, 2> ksize({weight_shape[1], weight_shape[2]});
|
||||||
|
std::array<uint32_t, 2> stride({3, 1});
|
||||||
|
std::array<uint32_t, 2> dilation({1, 1});
|
||||||
|
auto padding = tim::vx::PadType::VALID;
|
||||||
|
|
||||||
|
auto conv2d = graph->CreateOperation<tim::vx::ops::Conv2d>(
|
||||||
|
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<u_int8_t> 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<float, int32_t> scalesAndZp;
|
||||||
|
|
||||||
|
scalesAndZp = QuantizationParams<u_int8_t>(InputMin, InputMax);
|
||||||
|
std::vector<float> scalesInput = {scalesAndZp.first};
|
||||||
|
std::vector<int32_t> zeroPointsInput = {scalesAndZp.second};
|
||||||
|
|
||||||
|
scalesAndZp = QuantizationParams<u_int8_t>(WeightMin, WeightMax);
|
||||||
|
std::vector<float> scalesWeight = {scalesAndZp.first};
|
||||||
|
std::vector<int32_t> zeroPointsWeight = {scalesAndZp.second};
|
||||||
|
|
||||||
|
std::vector<float> scalesBias = {scalesInput[0] * scalesWeight[0]};
|
||||||
|
std::vector<int32_t> zeroPointsBias = {0};
|
||||||
|
|
||||||
|
scalesAndZp = QuantizationParams<u_int8_t>(OutputMin, OutputMax);
|
||||||
|
std::vector<float> scalesOutput = {scalesAndZp.first};
|
||||||
|
std::vector<int32_t> 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<float> 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<float> weight_data_float = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||||
|
// bias data
|
||||||
|
// scale:1 Zp:0
|
||||||
|
std::vector<float> bias_data_float = {0};
|
||||||
|
// golden data
|
||||||
|
// min:0 max:255 scale:1 Zp:-128
|
||||||
|
std::vector<float> golden_float = {5, 5, 5, 5, 5, 5, 5, 5, 5};
|
||||||
|
|
||||||
|
std::vector<u_int8_t> input_data =
|
||||||
|
Quantize<uint8_t>(input_data_float, scalesInput[0], zeroPointsInput[0]);
|
||||||
|
std::vector<u_int8_t> weight_data =
|
||||||
|
Quantize<uint8_t>(weight_data_float, scalesWeight[0], zeroPointsInput[0]);
|
||||||
|
std::vector<int32_t> bias_data =
|
||||||
|
Quantize<int32_t>(bias_data_float, scalesBias[0], zeroPointsBias[0]);
|
||||||
|
std::vector<u_int8_t> golden =
|
||||||
|
Quantize<uint8_t>(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<uint32_t, 2> ksize({weight_shape[1], weight_shape[2]});
|
||||||
|
std::array<uint32_t, 2> stride({1, 1});
|
||||||
|
std::array<uint32_t, 2> dilation({3, 3});
|
||||||
|
auto padding = tim::vx::PadType::VALID;
|
||||||
|
|
||||||
|
auto conv2d = graph->CreateOperation<tim::vx::ops::Conv2d>(
|
||||||
|
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<u_int8_t> output(output_size);
|
||||||
|
EXPECT_TRUE(output_tensor->CopyDataFromTensor(output.data()));
|
||||||
|
EXPECT_EQ(golden, output);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
#ifndef TIM_VX_TEST_UTILS_H_
|
||||||
|
#define TIM_VX_TEST_UTILS_H_
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::pair<float, int32_t> QuantizationParams(float f_min, float f_max) {
|
||||||
|
int32_t zero_point = 0;
|
||||||
|
float scale = 0;
|
||||||
|
const T qmin = std::numeric_limits<T>::min();
|
||||||
|
const T qmax = std::numeric_limits<T>::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<T>(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 <typename T>
|
||||||
|
inline std::vector<T> Quantize(const std::vector<float>& data, float scale,
|
||||||
|
int32_t zero_point) {
|
||||||
|
std::vector<T> q;
|
||||||
|
for (const auto& f : data) {
|
||||||
|
q.push_back(static_cast<T>(std::max<float>(
|
||||||
|
std::numeric_limits<T>::min(),
|
||||||
|
std::min<float>(std::numeric_limits<T>::max(),
|
||||||
|
std::round(zero_point + (f / scale))))));
|
||||||
|
}
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* TIM_VX_TEST_UTILS_H_ */
|
||||||
Loading…
Reference in New Issue