56ae2962fc060de621c5f30b9b36818863179ee7
[platform/core/ml/nnfw.git] / tests / nnfw_api / src / one_op_tests / DepthwiseConv2D.cc
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "GenModelTest.h"
18
19 TEST_F(GenModelTest, OneOp_DepthwiseConv2D)
20 {
21   CircleGen cgen;
22   std::vector<float> weight_data{1, 2, 3, 4, -9, 10, -11, 12, 5, 6, 7, 8, 13, -14, 15, -16};
23   uint32_t weight_buf = cgen.addBuffer(weight_data);
24   std::vector<float> bias_data{1, 2, 3, 4};
25   uint32_t bias_buf = cgen.addBuffer(bias_data);
26   int in = cgen.addTensor({{1, 3, 2, 2}, circle::TensorType::TensorType_FLOAT32});
27   int weight = cgen.addTensor({{1, 2, 2, 4}, circle::TensorType::TensorType_FLOAT32, weight_buf});
28   int bias = cgen.addTensor({{1, 1, 1, 4}, circle::TensorType::TensorType_FLOAT32, bias_buf});
29   int out = cgen.addTensor({{1, 2, 1, 4}, circle::TensorType::TensorType_FLOAT32});
30   cgen.addOperatorDepthwiseConv2D({{in, weight, bias}, {out}}, circle::Padding_VALID, 1, 1, 2,
31                                   circle::ActivationFunctionType_NONE);
32   cgen.setInputsAndOutputs({in}, {out});
33
34   _context = std::make_unique<GenModelTestContext>(cgen.finish());
35   _context->addTestCase(uniformTCD<float>({{1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12}},
36                                           {{71, -34, 99, -20, 91, -26, 127, -4}}));
37   _context->setBackends({"acl_cl", "acl_neon", "cpu"});
38
39   SUCCEED();
40 }
41
42 TEST_F(GenModelTest, OneOp_DepthwiseConv2D_Dilation)
43 {
44   CircleGen cgen;
45   std::vector<float> weight_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
46   uint32_t weight_buf = cgen.addBuffer(weight_data);
47   std::vector<float> bias_data{0, 0, 0, 0};
48   uint32_t bias_buf = cgen.addBuffer(bias_data);
49   int in = cgen.addTensor({{1, 4, 4, 2}, circle::TensorType::TensorType_FLOAT32});
50   int weight = cgen.addTensor({{1, 2, 2, 4}, circle::TensorType::TensorType_FLOAT32, weight_buf});
51   int bias = cgen.addTensor({{1, 1, 1, 4}, circle::TensorType::TensorType_FLOAT32, bias_buf});
52   int out = cgen.addTensor({{1, 2, 2, 4}, circle::TensorType::TensorType_FLOAT32});
53   cgen.addOperatorDepthwiseConv2D({{in, weight, bias}, {out}}, circle::Padding_VALID, 1, 1, 2,
54                                   circle::ActivationFunctionType_NONE, 2, 2);
55   cgen.setInputsAndOutputs({in}, {out});
56
57   _context = std::make_unique<GenModelTestContext>(cgen.finish());
58   _context->addTestCase(uniformTCD<float>({{
59                                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
60                                               0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61                                           }},
62                                           {{13, 14, 0, 0, 0, 0, 11, 12, 5, 6, 0, 0, 0, 0, 3, 4}}));
63   _context->setBackends({"acl_cl", "acl_neon", "cpu"});
64
65   SUCCEED();
66 }
67
68 TEST_F(GenModelTest, OneOp_DepthwiseConv2D_Dilation_N_Stride)
69 {
70   CircleGen cgen;
71   std::vector<float> weight_data{1, 2, 3, 4};
72   uint32_t weight_buf = cgen.addBuffer(weight_data);
73   std::vector<float> bias_data{0, 0, 0, 0};
74   uint32_t bias_buf = cgen.addBuffer(bias_data);
75   int in = cgen.addTensor({{1, 6, 6, 1}, circle::TensorType::TensorType_FLOAT32});
76   int weight = cgen.addTensor({{1, 2, 2, 1}, circle::TensorType::TensorType_FLOAT32, weight_buf});
77   int bias = cgen.addTensor({{1, 1, 1, 1}, circle::TensorType::TensorType_FLOAT32, bias_buf});
78   int out = cgen.addTensor({{1, 3, 3, 1}, circle::TensorType::TensorType_FLOAT32});
79   cgen.addOperatorDepthwiseConv2D({{in, weight, bias}, {out}}, circle::Padding_SAME, 2, 2, 1,
80                                   circle::ActivationFunctionType_NONE, 3, 3);
81   cgen.setInputsAndOutputs({in}, {out});
82
83   _context = std::make_unique<GenModelTestContext>(cgen.finish());
84   _context->addTestCase(uniformTCD<float>({{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
85                                             0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
86                                           {{4, 0, 3, 0, 0, 0, 2, 0, 1}}));
87   _context->setBackends({"acl_cl", "acl_neon", "cpu"});
88
89   SUCCEED();
90 }
91
92 TEST_F(GenModelTest, neg_OneOp_DepthwiseConv2D_Stride)
93 {
94   CircleGen cgen;
95   std::vector<float> weight_data{1, 2, 3, 4, -9, 10, -11, 12, 5, 6, 7, 8, 13, -14, 15, -16};
96   uint32_t weight_buf = cgen.addBuffer(weight_data);
97   std::vector<float> bias_data{1, 2, 3, 4};
98   uint32_t bias_buf = cgen.addBuffer(bias_data);
99   int in = cgen.addTensor({{1, 3, 2, 2}, circle::TensorType::TensorType_FLOAT32});
100   int weight = cgen.addTensor({{1, 2, 2, 4}, circle::TensorType::TensorType_FLOAT32, weight_buf});
101   int bias = cgen.addTensor({{1, 1, 1, 4}, circle::TensorType::TensorType_FLOAT32, bias_buf});
102   int out = cgen.addTensor({{1, 2, 1, 4}, circle::TensorType::TensorType_FLOAT32});
103   cgen.addOperatorDepthwiseConv2D({{in, weight, bias}, {out}}, circle::Padding_VALID, 0, 0, 2,
104                                   circle::ActivationFunctionType_NONE);
105   cgen.setInputsAndOutputs({in}, {out});
106
107   _context = std::make_unique<GenModelTestContext>(cgen.finish());
108   _context->expectFailModelLoad();
109
110   SUCCEED();
111 }
112
113 TEST_F(GenModelTest, neg_OneOp_DepthwiseConv2D_Dilation)
114 {
115   CircleGen cgen;
116   std::vector<float> weight_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
117   uint32_t weight_buf = cgen.addBuffer(weight_data);
118   std::vector<float> bias_data{0, 0, 0, 0};
119   uint32_t bias_buf = cgen.addBuffer(bias_data);
120   int in = cgen.addTensor({{1, 4, 4, 2}, circle::TensorType::TensorType_FLOAT32});
121   int weight = cgen.addTensor({{1, 2, 2, 4}, circle::TensorType::TensorType_FLOAT32, weight_buf});
122   int bias = cgen.addTensor({{1, 1, 1, 4}, circle::TensorType::TensorType_FLOAT32, bias_buf});
123   int out = cgen.addTensor({{1, 2, 2, 4}, circle::TensorType::TensorType_FLOAT32});
124   cgen.addOperatorDepthwiseConv2D({{in, weight, bias}, {out}}, circle::Padding_VALID, 1, 1, 2,
125                                   circle::ActivationFunctionType_NONE, 0, 0);
126   cgen.setInputsAndOutputs({in}, {out});
127
128   _context = std::make_unique<GenModelTestContext>(cgen.finish());
129   _context->expectFailModelLoad();
130
131   SUCCEED();
132 }
133
134 TEST_F(GenModelTest, neg_OneOp_DepthwiseConv2D_Type)
135 {
136   CircleGen cgen;
137   std::vector<float> weight_data{1, 2, 3, 4, -9, 10, -11, 12, 5, 6, 7, 8, 13, -14, 15, -16};
138   uint32_t weight_buf = cgen.addBuffer(weight_data);
139   std::vector<float> bias_data{1, 2, 3, 4};
140   uint32_t bias_buf = cgen.addBuffer(bias_data);
141   int in = cgen.addTensor({{1, 3, 2, 2}, circle::TensorType::TensorType_FLOAT32});
142   int weight = cgen.addTensor({{1, 2, 2, 4}, circle::TensorType::TensorType_FLOAT32, weight_buf});
143   int bias = cgen.addTensor({{1, 1, 1, 4}, circle::TensorType::TensorType_FLOAT32, bias_buf});
144   int out = cgen.addTensor({{1, 2, 1, 4}, circle::TensorType::TensorType_UINT8});
145   cgen.addOperatorDepthwiseConv2D({{in, weight, bias}, {out}}, circle::Padding_VALID, 1, 1, 2,
146                                   circle::ActivationFunctionType_NONE);
147   cgen.setInputsAndOutputs({in}, {out});
148
149   _context = std::make_unique<GenModelTestContext>(cgen.finish());
150   _context->expectFailModelLoad();
151
152   SUCCEED();
153 }
154
155 // Generate a model for negative test cases
156 CircleBuffer genNegTestDepthwiseConv2DModel(circle::Padding padding, int stride_w, int stride_h,
157                                             int depth_multiplier,
158                                             circle::ActivationFunctionType actfn)
159 {
160   CircleGen cgen;
161   uint32_t ker_buf = cgen.addBuffer(std::vector<uint8_t>{0, 1, 2, 3, 0, 1, 2, 3});
162   uint32_t bias_buf = cgen.addBuffer(std::vector<int32_t>{0, 0});
163   int in = cgen.addTensor({{1, 2, 2, 2}, circle::TensorType_UINT8}, 0.5, 0);
164   int ker = cgen.addTensor({{1, 2, 2, 2}, circle::TensorType_UINT8, ker_buf}, 0.5, 0);
165   int bias = cgen.addTensor({{2}, circle::TensorType_INT32, bias_buf}, 0.25, 0);
166   int out = cgen.addTensor({{1, 1, 1, 2}, circle::TensorType_UINT8}, 1, 0);
167   cgen.addOperatorDepthwiseConv2D({{in, ker, bias}, {out}}, padding, stride_w, stride_h,
168                                   depth_multiplier, actfn, 0, 0);
169   cgen.setInputsAndOutputs({in}, {out});
170   return cgen.finish();
171 }
172
173 CircleBuffer genSimpleDepthwiseConv2DQuantizedModel(int stride, int input_depth,
174                                                     int depth_multiplier)
175 {
176   assert(1 <= stride && stride <= 2);
177   assert(1 <= input_depth && input_depth <= 16);
178   assert(1 <= depth_multiplier && depth_multiplier <= 32);
179
180   const int output_depth = input_depth * depth_multiplier;
181   assert(1 <= output_depth && output_depth <= 32);
182
183   CircleGen cgen;
184   uint32_t ker_buf = cgen.addBuffer(std::vector<uint8_t>{
185       0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1,
186       2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
187       0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1,
188       2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
189       0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3});
190   uint32_t bias_buf = cgen.addBuffer(std::vector<int32_t>(output_depth, 0));
191   int in = cgen.addTensor({{1, 2, 2, input_depth}, circle::TensorType_UINT8}, 0.5, 0);
192   int ker = cgen.addTensor({{1, 2, 2, output_depth}, circle::TensorType_UINT8, ker_buf}, 0.5, 0);
193   int bias = cgen.addTensor({{output_depth}, circle::TensorType_INT32, bias_buf}, 0.25, 0);
194   int out = cgen.addTensor({{1, 1, 1, output_depth}, circle::TensorType_UINT8}, 1, 0);
195   cgen.addOperatorDepthwiseConv2D({{in, ker, bias}, {out}}, circle::Padding::Padding_VALID, stride,
196                                   stride, depth_multiplier, circle::ActivationFunctionType_NONE);
197   cgen.setInputsAndOutputs({in}, {out});
198   return cgen.finish();
199 }
200
201 struct DepthwiseConv2DVariationParam
202 {
203   int stride = 1; // Used for both height and width
204   int input_depth = 1;
205   int depth_multiplier = 1;
206   std::vector<uint8_t> ref_output;
207 };
208
209 class DepthwiseConv2DVariation : public GenModelTest,
210                                  public ::testing::WithParamInterface<DepthwiseConv2DVariationParam>
211 {
212 };
213
214 TEST_P(DepthwiseConv2DVariation, Test)
215 {
216   // Same input is used for all tests but output differs
217   static const std::vector<uint8_t> input64{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
218                                             5, 4, 3, 2, 5, 4, 3, 2, 5, 4, 3, 2, 5, 4, 3, 2,
219                                             2, 4, 6, 8, 2, 4, 6, 8, 2, 4, 6, 8, 2, 4, 6, 8,
220                                             2, 3, 5, 8, 8, 5, 3, 2, 1, 2, 3, 4, 5, 4, 3, 2};
221
222   auto &param = GetParam();
223   _context = std::make_unique<GenModelTestContext>(genSimpleDepthwiseConv2DQuantizedModel(
224       param.stride, param.input_depth, param.depth_multiplier));
225   std::vector<uint8_t> ref_input(input64.begin(), input64.begin() + param.input_depth * 4);
226   _context->addTestCase(uniformTCD<uint8_t>({ref_input}, {param.ref_output}));
227   _context->setBackends({"acl_cl", "acl_neon", "cpu"});
228
229   SUCCEED();
230 }
231
232 // Test with different InputDepth and DepthMultiplier. The values are intended to test optimized CPU
233 // kernels.
234 INSTANTIATE_TEST_CASE_P(
235     GenModelTest, DepthwiseConv2DVariation,
236     ::testing::Values(
237         // Stride == 1
238         DepthwiseConv2DVariationParam{1, 8, 1, std::vector<uint8_t>{0, 3, 5, 8, 0, 3, 5, 8}},
239         DepthwiseConv2DVariationParam{1, 4, 2, std::vector<uint8_t>{0, 0, 2, 3, 0, 2, 6, 9}},
240         DepthwiseConv2DVariationParam{
241             1, 2, 8, std::vector<uint8_t>{0, 1, 2, 3, 0, 1, 2, 3, 0, 2, 4, 6, 0, 2, 4, 6}},
242         DepthwiseConv2DVariationParam{1, 2, 2, std::vector<uint8_t>{0, 1, 4, 6}},
243         DepthwiseConv2DVariationParam{1, 2, 1, std::vector<uint8_t>{2, 5}},
244         DepthwiseConv2DVariationParam{1, 1, 2, std::vector<uint8_t>{2, 4}},
245         DepthwiseConv2DVariationParam{1, 1, 4, std::vector<uint8_t>{0, 2, 3, 5}},
246         DepthwiseConv2DVariationParam{1, 4, 1, std::vector<uint8_t>{0, 1, 4, 9}},
247         DepthwiseConv2DVariationParam{
248             1, 4, 4, std::vector<uint8_t>{0, 0, 0, 0, 0, 1, 2, 3, 0, 2, 4, 6, 0, 3, 6, 9}},
249         DepthwiseConv2DVariationParam{1, 12, 1,
250                                       std::vector<uint8_t>{0, 3, 7, 12, 0, 4, 7, 12, 0, 4, 9, 16}},
251         // Stride == 2
252         DepthwiseConv2DVariationParam{2, 4, 1, std::vector<uint8_t>{0, 1, 4, 9}},
253         DepthwiseConv2DVariationParam{2, 2, 1, std::vector<uint8_t>{2, 5}},
254         DepthwiseConv2DVariationParam{2, 1, 8, std::vector<uint8_t>{0, 2, 3, 5, 0, 2, 3, 5}},
255         DepthwiseConv2DVariationParam{
256             2, 1, 32, std::vector<uint8_t>{0, 2, 3, 5, 0, 2, 3, 5, 0, 2, 3, 5, 0, 2, 3, 5,
257                                            0, 2, 3, 5, 0, 2, 3, 5, 0, 2, 3, 5, 0, 2, 3, 5}},
258         DepthwiseConv2DVariationParam{2, 1, 20, std::vector<uint8_t>{0, 2, 3, 5, 0, 2, 3, 5, 0, 2,
259                                                                      3, 5, 0, 2, 3, 5, 0, 2, 3, 5}},
260         DepthwiseConv2DVariationParam{
261             2, 1, 16, std::vector<uint8_t>{0, 2, 3, 5, 0, 2, 3, 5, 0, 2, 3, 5, 0, 2, 3, 5}},
262         DepthwiseConv2DVariationParam{2, 8, 1, std::vector<uint8_t>{0, 3, 5, 8, 0, 3, 5, 8}},
263         DepthwiseConv2DVariationParam{
264             2, 8, 2, std::vector<uint8_t>{0, 3, 5, 8, 0, 3, 5, 8, 0, 3, 5, 8, 0, 3, 5, 8}},
265         DepthwiseConv2DVariationParam{
266             2, 16, 1, std::vector<uint8_t>{0, 3, 8, 16, 0, 4, 7, 12, 0, 3, 7, 13, 0, 4, 7, 12}}));
267
268 TEST_F(GenModelTest, neg_OneOp_DepthwiseConv2D_InvalidPaddingType)
269 {
270   _context = std::make_unique<GenModelTestContext>(genNegTestDepthwiseConv2DModel(
271       static_cast<circle::Padding>(99), 1, 1, 1, circle::ActivationFunctionType_NONE));
272   _context->expectFailModelLoad();
273   _context->setBackends({"acl_cl", "acl_neon", "cpu"});
274
275   SUCCEED();
276 }
277
278 // TODO add other invalid operation tests like above