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