• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     constexpr size_t kLowScaleCount = 3;
194     constexpr size_t kHighScaleCount = 10;
195     static float scales[kHighScaleCount] = {1.0, 2.0, 3.0, 4.0};
196     ANeuralNetworksSymmPerChannelQuantParams lowScaleCountExt = {
197             .channelDim = 3,
198             .scaleCount = kLowScaleCount,
199             .scales = scales,
200     };
201     ANeuralNetworksSymmPerChannelQuantParams highScaleCountExt = {
202             .channelDim = 3,
203             .scaleCount = kHighScaleCount,
204             .scales = scales,
205     };
206 
207     for (uint32_t dataType : kOperandCodeChannelQuant) {
208         testAddingWithSymmPerChannelQuantParams(dataType, lowScaleCountExt,
209                                                 /*expectExtraParamsSuccess=*/false);
210         testAddingWithSymmPerChannelQuantParams(dataType, highScaleCountExt,
211                                                 /*expectExtraParamsSuccess=*/false);
212     }
213 }
214 
TEST_F(OperandExtraParamsTest,TestChannelQuantValuesBadScalesNegative)215 TEST_F(OperandExtraParamsTest, TestChannelQuantValuesBadScalesNegative) {
216     // Bad .scales value
217     static float scales[4] = {1.0, 2.0, -3.0, 4.0};
218     ANeuralNetworksSymmPerChannelQuantParams ext = {
219             .channelDim = 3,
220             .scaleCount = 4,
221             .scales = scales,
222     };
223     for (uint32_t dataType : kOperandCodeChannelQuant) {
224         testAddingWithSymmPerChannelQuantParams(dataType, ext, /*expectExtraParamsSuccess=*/false);
225     }
226 }
227 
TEST_F(OperandExtraParamsTest,TestChannelQuantValuesNullScales)228 TEST_F(OperandExtraParamsTest, TestChannelQuantValuesNullScales) {
229     // .scales == nullptr value
230     ANeuralNetworksSymmPerChannelQuantParams ext = {
231             .channelDim = 3,
232             .scaleCount = 4,
233             .scales = nullptr,
234     };
235     for (uint32_t dataType : kOperandCodeChannelQuant) {
236         testAddingWithSymmPerChannelQuantParams(dataType, ext, /*expectExtraParamsSuccess=*/false);
237     }
238 }
239 
TEST_F(OperandExtraParamsTest,TestChannelQuantValuesOperandScale)240 TEST_F(OperandExtraParamsTest, TestChannelQuantValuesOperandScale) {
241     for (uint32_t dataType : kOperandCodeChannelQuant) {
242         ANeuralNetworksOperandType operandType = createOperand(dataType);
243         operandType.scale = 1.0f;
244         EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &operandType), ANEURALNETWORKS_BAD_DATA);
245     }
246 }
247 
TEST_F(OperandExtraParamsTest,TestChannelQuantValuesOperandZeroPoint)248 TEST_F(OperandExtraParamsTest, TestChannelQuantValuesOperandZeroPoint) {
249     for (uint32_t dataType : kOperandCodeChannelQuant) {
250         ANeuralNetworksOperandType operandType = createOperand(dataType);
251         operandType.zeroPoint = 1;
252         EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &operandType), ANEURALNETWORKS_BAD_DATA);
253     }
254 }
255 
256 }  // namespace
257