1 /*
2  * Copyright (C) 2018 The Android Open Source Project
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 <gtest/gtest.h>
18 
19 #include "NeuralNetworks.h"
20 #include "NeuralNetworksOEM.h"
21 #include "NeuralNetworksWrapper.h"
22 
23 #ifndef NNTEST_ONLY_PUBLIC_API
24 #include <Utils.h>
25 #endif
26 
27 namespace {
28 
29 using namespace android::nn::wrapper;
30 
31 class OperandExtraParamsTest : public ::testing::Test {
32    protected:
SetUp()33     virtual void SetUp() {
34         ::testing::Test::SetUp();
35         ASSERT_EQ(ANeuralNetworksModel_create(&mModel), ANEURALNETWORKS_NO_ERROR);
36         nextOperandIndex = 0;
37     }
TearDown()38     virtual void TearDown() {
39         ANeuralNetworksModel_free(mModel);
40         ::testing::Test::TearDown();
41     }
42 
43     static const uint32_t CHANNEL_DIM_SIZE = 4;
44 
createOperand(int32_t dataType)45     ANeuralNetworksOperandType createOperand(int32_t dataType) {
46         static uint32_t dims[4] = {1, 2, 3, CHANNEL_DIM_SIZE};
47         switch (dataType) {
48             case ANEURALNETWORKS_FLOAT32:
49             case ANEURALNETWORKS_FLOAT16:
50             case ANEURALNETWORKS_INT32:
51             case ANEURALNETWORKS_UINT32:
52             case ANEURALNETWORKS_BOOL:
53             case ANEURALNETWORKS_MODEL:
54             case ANEURALNETWORKS_OEM_SCALAR:
55                 return {.type = dataType,
56                         .dimensionCount = 0,
57                         .dimensions = nullptr,
58                         .scale = 0.0f,
59                         .zeroPoint = 0};
60             case ANEURALNETWORKS_TENSOR_OEM_BYTE:
61             case ANEURALNETWORKS_TENSOR_FLOAT32:
62             case ANEURALNETWORKS_TENSOR_FLOAT16:
63             case ANEURALNETWORKS_TENSOR_INT32:
64             case ANEURALNETWORKS_TENSOR_BOOL8:
65             case ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL:
66                 return {.type = dataType,
67                         .dimensionCount = 4,
68                         .dimensions = dims,
69                         .scale = 0.0f,
70                         .zeroPoint = 0};
71             case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
72                 return {.type = dataType,
73                         .dimensionCount = 4,
74                         .dimensions = dims,
75                         .scale = 1.0,
76                         .zeroPoint = 128};
77             case ANEURALNETWORKS_TENSOR_QUANT8_SYMM:
78                 return {.type = dataType,
79                         .dimensionCount = 4,
80                         .dimensions = dims,
81                         .scale = 1.0,
82                         .zeroPoint = 0};
83             case ANEURALNETWORKS_TENSOR_QUANT16_SYMM:
84                 return {.type = dataType,
85                         .dimensionCount = 4,
86                         .dimensions = dims,
87                         .scale = 1.0,
88                         .zeroPoint = 0};
89             case ANEURALNETWORKS_TENSOR_QUANT16_ASYMM:
90                 return {.type = dataType,
91                         .dimensionCount = 4,
92                         .dimensions = dims,
93                         .scale = 1.0,
94                         .zeroPoint = 32768};
95             case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED:
96                 return {.type = dataType,
97                         .dimensionCount = 4,
98                         .dimensions = dims,
99                         .scale = 1.0,
100                         .zeroPoint = 1};
101             default:
102                 ADD_FAILURE();
103                 return {};
104         }
105     }
106 
createSymmPerChannelQuantParams()107     ANeuralNetworksSymmPerChannelQuantParams createSymmPerChannelQuantParams() {
108         static float scales[CHANNEL_DIM_SIZE] = {1.0, 2.0, 3.0, 4.0};
109         return {
110                 .channelDim = 3,
111                 .scaleCount = CHANNEL_DIM_SIZE,
112                 .scales = scales,
113         };
114     }
115 
testAddingWithSymmPerChannelQuantParams(int32_t dataType,ANeuralNetworksSymmPerChannelQuantParams params,bool expectExtraParamsSuccess)116     void testAddingWithSymmPerChannelQuantParams(int32_t dataType,
117                                                  ANeuralNetworksSymmPerChannelQuantParams params,
118                                                  bool expectExtraParamsSuccess) {
119         ANeuralNetworksOperandType operandType = createOperand(dataType);
120         EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &operandType), ANEURALNETWORKS_NO_ERROR);
121         int operandIndex = nextOperandIndex++;
122         EXPECT_EQ(ANeuralNetworksModel_setOperandSymmPerChannelQuantParams(mModel, operandIndex,
123                                                                            &params),
124                   expectExtraParamsSuccess ? ANEURALNETWORKS_NO_ERROR : ANEURALNETWORKS_BAD_DATA);
125     }
126 
127     ANeuralNetworksModel* mModel = nullptr;
128     int nextOperandIndex = 0;
129 };
130 
131 const uint32_t kOperandCodeNoExtraParams[]{
132         ANEURALNETWORKS_FLOAT32,
133         ANEURALNETWORKS_FLOAT16,
134         ANEURALNETWORKS_INT32,
135         ANEURALNETWORKS_UINT32,
136         ANEURALNETWORKS_BOOL,
137         ANEURALNETWORKS_OEM_SCALAR,
138         ANEURALNETWORKS_TENSOR_OEM_BYTE,
139         ANEURALNETWORKS_TENSOR_FLOAT32,
140         ANEURALNETWORKS_TENSOR_INT32,
141         ANEURALNETWORKS_TENSOR_QUANT8_ASYMM,
142         ANEURALNETWORKS_TENSOR_QUANT16_ASYMM,
143         ANEURALNETWORKS_TENSOR_QUANT16_SYMM,
144         ANEURALNETWORKS_TENSOR_FLOAT16,
145         ANEURALNETWORKS_TENSOR_BOOL8,
146         ANEURALNETWORKS_TENSOR_QUANT8_SYMM,
147         ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED,
148         ANEURALNETWORKS_MODEL,
149 };
150 
151 #ifndef NNTEST_ONLY_PUBLIC_API
152 // android::nn::k* consts are defined in private headers
153 static_assert(sizeof(kOperandCodeNoExtraParams) / sizeof(kOperandCodeNoExtraParams[0]) ==
154                       android::nn::kNumberOfDataTypes + android::nn::kNumberOfDataTypesOEM - 1,
155               "New type added, OperandExtraParamsTest needs an update");
156 #endif
157 
158 const uint32_t kOperandCodeChannelQuant[]{
159         ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL,
160 };
161 
TEST_F(OperandExtraParamsTest,TestNoExtraParams)162 TEST_F(OperandExtraParamsTest, TestNoExtraParams) {
163     // Test for operands that are expected to not have additonal parameters
164     for (uint32_t dataType : kOperandCodeNoExtraParams) {
165         testAddingWithSymmPerChannelQuantParams(dataType, createSymmPerChannelQuantParams(),
166                                                 /*expectExtraParamsSuccess=*/false);
167     }
168 }
169 
TEST_F(OperandExtraParamsTest,TestChannelQuant)170 TEST_F(OperandExtraParamsTest, TestChannelQuant) {
171     // Test for operands that are expected to have SymmPerChannelQuantParams value associated
172     for (uint32_t dataType : kOperandCodeChannelQuant) {
173         testAddingWithSymmPerChannelQuantParams(dataType, createSymmPerChannelQuantParams(),
174                                                 /*expectExtraParamsSuccess=*/true);
175     }
176 }
177 
TEST_F(OperandExtraParamsTest,TestChannelQuantValuesBadDim)178 TEST_F(OperandExtraParamsTest, TestChannelQuantValuesBadDim) {
179     // Bad .channelDim value
180     static float scales[4] = {1.0, 2.0, 3.0, 4.0};
181     ANeuralNetworksSymmPerChannelQuantParams ext = {
182             .channelDim = 7,
183             .scaleCount = 4,
184             .scales = scales,
185     };
186     for (uint32_t dataType : kOperandCodeChannelQuant) {
187         testAddingWithSymmPerChannelQuantParams(dataType, ext, /*expectExtraParamsSuccess=*/false);
188     }
189 }
190 
TEST_F(OperandExtraParamsTest,TestChannelQuantValuesBadScalesCount)191 TEST_F(OperandExtraParamsTest, TestChannelQuantValuesBadScalesCount) {
192     // Bad .scaleCount value
193     static float scales[4] = {1.0, 2.0, 3.0, 4.0};
194     ANeuralNetworksSymmPerChannelQuantParams lowScaleCountExt = {
195             .channelDim = 3,
196             .scaleCount = 3,
197             .scales = scales,
198     };
199     ANeuralNetworksSymmPerChannelQuantParams highScaleCountExt = {
200             .channelDim = 3,
201             .scaleCount = 10,
202             .scales = scales,
203     };
204 
205     for (uint32_t dataType : kOperandCodeChannelQuant) {
206         testAddingWithSymmPerChannelQuantParams(dataType, lowScaleCountExt,
207                                                 /*expectExtraParamsSuccess=*/false);
208         testAddingWithSymmPerChannelQuantParams(dataType, highScaleCountExt,
209                                                 /*expectExtraParamsSuccess=*/false);
210     }
211 }
212 
TEST_F(OperandExtraParamsTest,TestChannelQuantValuesBadScalesNegative)213 TEST_F(OperandExtraParamsTest, TestChannelQuantValuesBadScalesNegative) {
214     // Bad .scales value
215     static float scales[4] = {1.0, 2.0, -3.0, 4.0};
216     ANeuralNetworksSymmPerChannelQuantParams ext = {
217             .channelDim = 3,
218             .scaleCount = 4,
219             .scales = scales,
220     };
221     for (uint32_t dataType : kOperandCodeChannelQuant) {
222         testAddingWithSymmPerChannelQuantParams(dataType, ext, /*expectExtraParamsSuccess=*/false);
223     }
224 }
225 
TEST_F(OperandExtraParamsTest,TestChannelQuantValuesNullScales)226 TEST_F(OperandExtraParamsTest, TestChannelQuantValuesNullScales) {
227     // .scales == nullptr value
228     ANeuralNetworksSymmPerChannelQuantParams ext = {
229             .channelDim = 3,
230             .scaleCount = 4,
231             .scales = nullptr,
232     };
233     for (uint32_t dataType : kOperandCodeChannelQuant) {
234         testAddingWithSymmPerChannelQuantParams(dataType, ext, /*expectExtraParamsSuccess=*/false);
235     }
236 }
237 
TEST_F(OperandExtraParamsTest,TestChannelQuantValuesOperandScale)238 TEST_F(OperandExtraParamsTest, TestChannelQuantValuesOperandScale) {
239     for (uint32_t dataType : kOperandCodeChannelQuant) {
240         ANeuralNetworksOperandType operandType = createOperand(dataType);
241         operandType.scale = 1.0f;
242         EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &operandType), ANEURALNETWORKS_BAD_DATA);
243     }
244 }
245 
TEST_F(OperandExtraParamsTest,TestChannelQuantValuesOperandZeroPoint)246 TEST_F(OperandExtraParamsTest, TestChannelQuantValuesOperandZeroPoint) {
247     for (uint32_t dataType : kOperandCodeChannelQuant) {
248         ANeuralNetworksOperandType operandType = createOperand(dataType);
249         operandType.zeroPoint = 1;
250         EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &operandType), ANEURALNETWORKS_BAD_DATA);
251     }
252 }
253 
254 }  // namespace
255