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 "NeuralNetworksWrapper.h"
18 #include "NeuralNetworksOEM.h"
19
20 #include <gtest/gtest.h>
21
22 using namespace android::nn::wrapper;
23
24 namespace {
25
26 static const int32_t kAvailableOperandCodes[] = {
27 ANEURALNETWORKS_FLOAT32,
28 ANEURALNETWORKS_INT32,
29 ANEURALNETWORKS_UINT32,
30 ANEURALNETWORKS_TENSOR_FLOAT32,
31 ANEURALNETWORKS_TENSOR_INT32,
32 ANEURALNETWORKS_TENSOR_QUANT8_ASYMM,
33 ANEURALNETWORKS_TENSOR_OEM_BYTE
34 };
35
36 class OperationTestBase {
37 public:
OperationTestBase(ANeuralNetworksOperationType opCode,std::vector<ANeuralNetworksOperandType> validInputs,std::vector<ANeuralNetworksOperandType> validOutputs)38 OperationTestBase(ANeuralNetworksOperationType opCode,
39 std::vector<ANeuralNetworksOperandType> validInputs,
40 std::vector<ANeuralNetworksOperandType> validOutputs)
41 : mOpCode(opCode),
42 mValidInputs(std::move(validInputs)),
43 mValidOutputs(std::move(validOutputs)) {}
44
45 // Add each operand separately and add the operation using these operands.
46 // This function does not cover the cases that a operand used mutiple times.
addOperation(const std::vector<ANeuralNetworksOperandType> & inputs,const std::vector<ANeuralNetworksOperandType> & outputs)47 int32_t addOperation(const std::vector<ANeuralNetworksOperandType>& inputs,
48 const std::vector<ANeuralNetworksOperandType>& outputs) {
49 ANeuralNetworksModel* model = nullptr;
50 ANeuralNetworksModel_create(&model);
51
52 uint32_t opIdx = 0;
53 std::vector<uint32_t> inputIds;
54 std::vector<uint32_t> outputIds;
55 for (uint32_t i = 0; i < inputs.size(); i++) {
56 ANeuralNetworksModel_addOperand(model, &inputs[i]);
57 inputIds.push_back(opIdx++);
58 }
59 for (uint32_t i = 0; i < outputs.size(); i++) {
60 ANeuralNetworksModel_addOperand(model, &outputs[i]);
61 outputIds.push_back(opIdx++);
62 }
63
64 int32_t result = ANeuralNetworksModel_addOperation(model, mOpCode,
65 static_cast<uint32_t>(inputIds.size()),
66 inputIds.data(),
67 static_cast<uint32_t>(outputIds.size()),
68 outputIds.data());
69 ANeuralNetworksModel_free(model);
70 return result;
71 }
72
testMutatingInputOperandCode()73 bool testMutatingInputOperandCode() {
74 for (uint32_t i = 0; i < mValidInputs.size(); i++) {
75 // LSH_PROJECTION's second argument is allowed to have any type.
76 // This is the only operation that currently has a type that can be
77 // anything independent from any other type. Changing the operand
78 // type to any other type will result in a valid model for
79 // LSH_PROJECTION. If this is the case, skip the test.
80 if (mOpCode == ANEURALNETWORKS_LSH_PROJECTION && i == 1) {
81 continue;
82 }
83 ANeuralNetworksOperandType newType = mValidInputs[i];
84 int32_t originalOperandCode = mValidInputs[i].type;
85 for (int32_t newOperandCode : kAvailableOperandCodes) {
86 if (newOperandCode == originalOperandCode) {
87 continue;
88 }
89 newType.type = newOperandCode;
90 std::vector<ANeuralNetworksOperandType> inputs = mValidInputs;
91 inputs[i] = newType;
92 int32_t result = addOperation(inputs, mValidOutputs);
93 if (ANEURALNETWORKS_NO_ERROR == result) {
94 return false;
95 }
96 }
97 }
98 return true;
99 }
100
testMutatingOutputOperandCode()101 bool testMutatingOutputOperandCode() {
102 for (uint32_t i = 0; i < mValidOutputs.size(); i++) {
103 // LSH_PROJECTION's second argument is allowed to have any type.
104 // This is the only operation that currently has a type that can be
105 // anything independent from any other type. Changing the operand
106 // type to any other type will result in a valid model for
107 // LSH_PROJECTION. If this is the case, skip the test.
108 if (mOpCode == ANEURALNETWORKS_LSH_PROJECTION && i == 1) {
109 continue;
110 }
111 ANeuralNetworksOperandType newType = mValidOutputs[i];
112 int32_t originalOperandCode = mValidOutputs[i].type;
113 for (int32_t newOperandCode : kAvailableOperandCodes) {
114 if (newOperandCode == originalOperandCode) {
115 continue;
116 }
117 newType.type = newOperandCode;
118 std::vector<ANeuralNetworksOperandType> outputs = mValidOutputs;
119 outputs[i] = newType;
120 int32_t result = addOperation(mValidInputs, outputs);
121 if (ANEURALNETWORKS_NO_ERROR == result) {
122 return false;
123 }
124 }
125 }
126 return true;
127 }
128
testMutatingInputOperandCounts()129 bool testMutatingInputOperandCounts() {
130 std::vector<ANeuralNetworksOperandType> inputs = mValidInputs;
131 for (uint32_t i = 0; i < 5; i++) {
132 inputs.push_back(inputs[0]);
133 if (ANEURALNETWORKS_NO_ERROR == addOperation(inputs, mValidOutputs)) {
134 return false;
135 }
136 }
137 return true;
138 }
139
testMutatingOutputOperandCounts()140 bool testMutatingOutputOperandCounts() {
141 std::vector<ANeuralNetworksOperandType> outputs = mValidOutputs;
142 for (int i = 0; i < 5; i++) {
143 outputs.push_back(outputs[0]);
144 if (ANEURALNETWORKS_NO_ERROR == addOperation(mValidInputs, outputs)) {
145 return false;
146 }
147 }
148 return true;
149 }
150
151 private:
152 ANeuralNetworksOperationType mOpCode;
153 // The dimensions in the ANeuralNetworksOperandType must outlive the test object.
154 std::vector<ANeuralNetworksOperandType> mValidInputs;
155 std::vector<ANeuralNetworksOperandType> mValidOutputs;
156 };
157
TEST(OperationValidationTest,DEQUANTIZE_float32)158 TEST(OperationValidationTest, DEQUANTIZE_float32) {
159 uint32_t inputDimensions[4] = {2, 2, 2, 2};
160 ANeuralNetworksOperandType input = {.type = ANEURALNETWORKS_TENSOR_QUANT8_ASYMM,
161 .dimensionCount = 4,
162 .dimensions = inputDimensions,
163 .scale = 1.0f,
164 .zeroPoint = 0};
165 ANeuralNetworksOperandType output = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
166 .dimensionCount = 4,
167 .dimensions = inputDimensions,
168 .scale = 0.0f,
169 .zeroPoint = 0};
170 OperationTestBase dequantizeTest(ANEURALNETWORKS_DEQUANTIZE, {input}, {output});
171
172 EXPECT_TRUE(dequantizeTest.testMutatingInputOperandCode());
173 EXPECT_TRUE(dequantizeTest.testMutatingInputOperandCounts());
174 EXPECT_TRUE(dequantizeTest.testMutatingOutputOperandCode());
175 EXPECT_TRUE(dequantizeTest.testMutatingOutputOperandCounts());
176 }
177
simpleMathOpTest(ANeuralNetworksOperationType operationCode,int32_t operandCode)178 void simpleMathOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
179 uint32_t inputDimensions[4] = {2, 2, 2, 2};
180 ANeuralNetworksOperandType input1 = {.type = operandCode,
181 .dimensionCount = 4,
182 .dimensions = inputDimensions,
183 .scale = 0.0f,
184 .zeroPoint = 0};
185 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
186 input1.scale = 0.5f;
187 }
188
189 ANeuralNetworksOperandType input2 = input1;
190 ANeuralNetworksOperandType output = input1;
191 ANeuralNetworksOperandType activation = {.type = ANEURALNETWORKS_INT32,
192 .dimensionCount = 0,
193 .dimensions = nullptr,
194 .scale = 0.0f,
195 .zeroPoint = 0};
196
197 OperationTestBase simpleMathTest(operationCode, {input1, input2, activation}, {output});
198
199 EXPECT_TRUE(simpleMathTest.testMutatingInputOperandCode());
200 EXPECT_TRUE(simpleMathTest.testMutatingInputOperandCounts());
201 EXPECT_TRUE(simpleMathTest.testMutatingOutputOperandCode());
202 EXPECT_TRUE(simpleMathTest.testMutatingOutputOperandCounts());
203 }
204
TEST(OperationValidationTest,ADD_float32)205 TEST(OperationValidationTest, ADD_float32) {
206 simpleMathOpTest(ANEURALNETWORKS_ADD, ANEURALNETWORKS_TENSOR_FLOAT32);
207 }
208
TEST(OperationValidationTest,MUL_float32)209 TEST(OperationValidationTest, MUL_float32) {
210 simpleMathOpTest(ANEURALNETWORKS_MUL, ANEURALNETWORKS_TENSOR_FLOAT32);
211 }
212
TEST(OperationValidationTest,SUB_float32)213 TEST(OperationValidationTest, SUB_float32) {
214 simpleMathOpTest(ANEURALNETWORKS_SUB, ANEURALNETWORKS_TENSOR_FLOAT32);
215 }
216
TEST(OperationValidationTest,DIV_float32)217 TEST(OperationValidationTest, DIV_float32) {
218 simpleMathOpTest(ANEURALNETWORKS_DIV, ANEURALNETWORKS_TENSOR_FLOAT32);
219 }
220
TEST(OperationValidationTest,ADD_quant8)221 TEST(OperationValidationTest, ADD_quant8) {
222 simpleMathOpTest(ANEURALNETWORKS_ADD, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
223 }
224
TEST(OperationValidationTest,MUL_quant8)225 TEST(OperationValidationTest, MUL_quant8) {
226 simpleMathOpTest(ANEURALNETWORKS_MUL, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
227 }
228
activationOpTest(ANeuralNetworksOperationType operationCode,int32_t operandCode)229 void activationOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
230 uint32_t inputDimensions[4] = {2, 2, 2, 2};
231 ANeuralNetworksOperandType input = {.type = operandCode,
232 .dimensionCount = 4,
233 .dimensions = inputDimensions,
234 .scale = 0.0f,
235 .zeroPoint = 0};
236 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
237 input.scale = 1.f / 256;
238 }
239
240 ANeuralNetworksOperandType output = input;
241 OperationTestBase activationTest(operationCode, {input}, {output});
242
243 EXPECT_TRUE(activationTest.testMutatingInputOperandCode());
244 EXPECT_TRUE(activationTest.testMutatingInputOperandCounts());
245 EXPECT_TRUE(activationTest.testMutatingOutputOperandCode());
246 EXPECT_TRUE(activationTest.testMutatingOutputOperandCounts());
247 }
248
TEST(OperationValidationTest,L2_NORMALIZATION_float32)249 TEST(OperationValidationTest, L2_NORMALIZATION_float32) {
250 activationOpTest(ANEURALNETWORKS_L2_NORMALIZATION, ANEURALNETWORKS_TENSOR_FLOAT32);
251 }
252
TEST(OperationValidationTest,FLOOR_float32)253 TEST(OperationValidationTest, FLOOR_float32) {
254 activationOpTest(ANEURALNETWORKS_FLOOR, ANEURALNETWORKS_TENSOR_FLOAT32);
255 }
256
TEST(OperationValidationTest,TANH_float32)257 TEST(OperationValidationTest, TANH_float32) {
258 activationOpTest(ANEURALNETWORKS_TANH, ANEURALNETWORKS_TENSOR_FLOAT32);
259 }
260
TEST(OperationValidationTest,RELU_float32)261 TEST(OperationValidationTest, RELU_float32) {
262 activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_FLOAT32);
263 }
264
TEST(OperationValidationTest,RELU1_float32)265 TEST(OperationValidationTest, RELU1_float32) {
266 activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_FLOAT32);
267 }
268
TEST(OperationValidationTest,RELU6_float32)269 TEST(OperationValidationTest, RELU6_float32) {
270 activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_FLOAT32);
271 }
272
TEST(OperationValidationTest,LOGISTIC_float32)273 TEST(OperationValidationTest, LOGISTIC_float32) {
274 activationOpTest(ANEURALNETWORKS_LOGISTIC, ANEURALNETWORKS_TENSOR_FLOAT32);
275 }
276
TEST(OperationValidationTest,RELU_quant8)277 TEST(OperationValidationTest, RELU_quant8) {
278 activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
279 }
280
TEST(OperationValidationTest,RELU1_quant8)281 TEST(OperationValidationTest, RELU1_quant8) {
282 activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
283 }
284
TEST(OperationValidationTest,RELU6_quant8)285 TEST(OperationValidationTest, RELU6_quant8) {
286 activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
287 }
288
TEST(OperationValidationTest,LOGISTIC_quant8)289 TEST(OperationValidationTest, LOGISTIC_quant8) {
290 activationOpTest(ANEURALNETWORKS_LOGISTIC, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
291 }
292
softmaxOpTest(int32_t operandCode)293 void softmaxOpTest(int32_t operandCode) {
294 uint32_t inputDimensions[4] = {2, 2, 2, 2};
295 ANeuralNetworksOperandType input = {.type = operandCode,
296 .dimensionCount = 4,
297 .dimensions = inputDimensions,
298 .scale = 0.0f,
299 .zeroPoint = 0};
300 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
301 input.scale = 1.f / 256;
302 }
303
304 ANeuralNetworksOperandType output = input;
305 ANeuralNetworksOperandType beta = {.type = ANEURALNETWORKS_FLOAT32,
306 .dimensionCount = 0,
307 .dimensions = nullptr,
308 .scale = 0.0f,
309 .zeroPoint = 0};
310
311 OperationTestBase softmaxTest(ANEURALNETWORKS_SOFTMAX, {input, beta}, {output});
312
313 EXPECT_TRUE(softmaxTest.testMutatingInputOperandCode());
314 EXPECT_TRUE(softmaxTest.testMutatingInputOperandCounts());
315 EXPECT_TRUE(softmaxTest.testMutatingOutputOperandCode());
316 EXPECT_TRUE(softmaxTest.testMutatingOutputOperandCounts());
317 }
318
TEST(OperationValidationTest,SOFTMAX_float32)319 TEST(OperationValidationTest, SOFTMAX_float32) {
320 softmaxOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
321 }
322
TEST(OperationValidationTest,SOFTMAX_quant8)323 TEST(OperationValidationTest, SOFTMAX_quant8) {
324 softmaxOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
325 }
326
poolingOpTest(ANeuralNetworksOperationType operationCode,int32_t operandCode)327 void poolingOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
328 uint32_t inputDimensions[4] = {2, 4, 4, 2};
329 ANeuralNetworksOperandType input = {.type = operandCode,
330 .dimensionCount = 4,
331 .dimensions = inputDimensions,
332 .scale = 0.0f,
333 .zeroPoint = 0};
334 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
335 input.scale = 1.f / 256;
336 }
337 ANeuralNetworksOperandType output = input;
338
339 ANeuralNetworksOperandType scalar = {.type = ANEURALNETWORKS_INT32,
340 .dimensionCount = 0,
341 .dimensions = nullptr,
342 .scale = 0.0f,
343 .zeroPoint = 0};
344 ANeuralNetworksOperandType padLeft = scalar;
345 ANeuralNetworksOperandType padRight = scalar;
346 ANeuralNetworksOperandType padTop = scalar;
347 ANeuralNetworksOperandType padBottom = scalar;
348 ANeuralNetworksOperandType strideWidth = scalar;
349 ANeuralNetworksOperandType strideHeight = scalar;
350 ANeuralNetworksOperandType filterWidth = scalar;
351 ANeuralNetworksOperandType filterHeight = scalar;
352 ANeuralNetworksOperandType activation = scalar;
353
354 OperationTestBase explicitPoolingTest(operationCode,
355 {input,
356 padLeft, padRight, padTop, padBottom,
357 strideWidth, strideHeight,
358 filterWidth, filterHeight,
359 activation},
360 {output});
361
362 EXPECT_TRUE(explicitPoolingTest.testMutatingInputOperandCode());
363 EXPECT_TRUE(explicitPoolingTest.testMutatingInputOperandCounts());
364 EXPECT_TRUE(explicitPoolingTest.testMutatingOutputOperandCode());
365 EXPECT_TRUE(explicitPoolingTest.testMutatingOutputOperandCounts());
366
367 ANeuralNetworksOperandType padImplicit = scalar;
368 OperationTestBase implicitPoolingTest(operationCode,
369 {input,
370 padImplicit,
371 strideWidth, strideHeight,
372 filterWidth, filterHeight,
373 activation},
374 {output});
375
376 EXPECT_TRUE(implicitPoolingTest.testMutatingInputOperandCode());
377 EXPECT_TRUE(implicitPoolingTest.testMutatingInputOperandCounts());
378 EXPECT_TRUE(implicitPoolingTest.testMutatingOutputOperandCode());
379 EXPECT_TRUE(implicitPoolingTest.testMutatingOutputOperandCounts());
380 }
381
TEST(OperationValidationTest,AVERAGE_POOL_2D_float32)382 TEST(OperationValidationTest, AVERAGE_POOL_2D_float32) {
383 poolingOpTest(ANEURALNETWORKS_AVERAGE_POOL_2D, ANEURALNETWORKS_TENSOR_FLOAT32);
384 }
385
TEST(OperationValidationTest,MAX_POOL_2D_float32)386 TEST(OperationValidationTest, MAX_POOL_2D_float32) {
387 poolingOpTest(ANEURALNETWORKS_MAX_POOL_2D, ANEURALNETWORKS_TENSOR_FLOAT32);
388 }
389
TEST(OperationValidationTest,L2_POOL_2D_float32)390 TEST(OperationValidationTest, L2_POOL_2D_float32) {
391 poolingOpTest(ANEURALNETWORKS_L2_POOL_2D, ANEURALNETWORKS_TENSOR_FLOAT32);
392 }
393
TEST(OperationValidationTest,AVERAGE_POOL_2D_quant8)394 TEST(OperationValidationTest, AVERAGE_POOL_2D_quant8) {
395 poolingOpTest(ANEURALNETWORKS_AVERAGE_POOL_2D, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
396 }
397
TEST(OperationValidationTest,MAX_POOL_2D_quant8)398 TEST(OperationValidationTest, MAX_POOL_2D_quant8) {
399 poolingOpTest(ANEURALNETWORKS_MAX_POOL_2D, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
400 }
401
spaceDepthOpTest(ANeuralNetworksOperationType operationCode,int32_t operandCode)402 void spaceDepthOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
403 uint32_t inputDimensions[4] = {2, 2, 2, 2};
404 ANeuralNetworksOperandType input = {.type = operandCode,
405 .dimensionCount = 4,
406 .dimensions = inputDimensions,
407 .scale = 0.0f,
408 .zeroPoint = 0};
409 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
410 input.scale = 1.f / 256;
411 }
412
413 ANeuralNetworksOperandType block_size = {.type = ANEURALNETWORKS_INT32,
414 .dimensionCount = 0,
415 .dimensions = nullptr,
416 .scale = 0.0f,
417 .zeroPoint = 0};
418
419 ANeuralNetworksOperandType output = input;
420 OperationTestBase spaceDepthTest(operationCode, {input, block_size}, {output});
421
422 EXPECT_TRUE(spaceDepthTest.testMutatingInputOperandCode());
423 EXPECT_TRUE(spaceDepthTest.testMutatingInputOperandCounts());
424 EXPECT_TRUE(spaceDepthTest.testMutatingOutputOperandCode());
425 EXPECT_TRUE(spaceDepthTest.testMutatingOutputOperandCounts());
426 }
427
TEST(OperationValidationTest,SPACE_TO_DEPTH_float32)428 TEST(OperationValidationTest, SPACE_TO_DEPTH_float32) {
429 spaceDepthOpTest(ANEURALNETWORKS_SPACE_TO_DEPTH, ANEURALNETWORKS_TENSOR_FLOAT32);
430 }
431
TEST(OperationValidationTest,DEPTH_TO_SPACE_float32)432 TEST(OperationValidationTest, DEPTH_TO_SPACE_float32) {
433 spaceDepthOpTest(ANEURALNETWORKS_DEPTH_TO_SPACE, ANEURALNETWORKS_TENSOR_FLOAT32);
434 }
435
TEST(OperationValidationTest,SPACE_TO_DEPTH_quant8)436 TEST(OperationValidationTest, SPACE_TO_DEPTH_quant8) {
437 spaceDepthOpTest(ANEURALNETWORKS_SPACE_TO_DEPTH, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
438 }
439
TEST(OperationValidationTest,DEPTH_TO_SPACE_quant8)440 TEST(OperationValidationTest, DEPTH_TO_SPACE_quant8) {
441 spaceDepthOpTest(ANEURALNETWORKS_DEPTH_TO_SPACE, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
442 }
443
spaceBatchOpTest(ANeuralNetworksOperationType operationCode,int32_t operandCode)444 void spaceBatchOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
445 uint32_t inputDimensions[4] = {2, 2, 2, 2};
446 ANeuralNetworksOperandType input = {.type = operandCode,
447 .dimensionCount = 4,
448 .dimensions = inputDimensions,
449 .scale = 0.0f,
450 .zeroPoint = 0};
451 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
452 input.scale = 1.f / 256;
453 }
454
455 uint32_t blockDimensions[1] = {2};
456 ANeuralNetworksOperandType blockShape = {.type = ANEURALNETWORKS_TENSOR_INT32,
457 .dimensionCount = 1,
458 .dimensions = blockDimensions,
459 .scale = 0.0f,
460 .zeroPoint = 0};
461
462 ANeuralNetworksOperandType padding = blockShape;
463 ANeuralNetworksOperandType output = input;
464 if (operationCode == ANEURALNETWORKS_SPACE_TO_BATCH_ND) {
465 OperationTestBase spaceBatchTest(operationCode, {input, blockShape, padding}, {output});
466
467 EXPECT_TRUE(spaceBatchTest.testMutatingInputOperandCode());
468 EXPECT_TRUE(spaceBatchTest.testMutatingInputOperandCounts());
469 EXPECT_TRUE(spaceBatchTest.testMutatingOutputOperandCode());
470 EXPECT_TRUE(spaceBatchTest.testMutatingOutputOperandCounts());
471 } else {
472 OperationTestBase spaceBatchTest(operationCode, {input, blockShape}, {output});
473
474 EXPECT_TRUE(spaceBatchTest.testMutatingInputOperandCode());
475 EXPECT_TRUE(spaceBatchTest.testMutatingInputOperandCounts());
476 EXPECT_TRUE(spaceBatchTest.testMutatingOutputOperandCode());
477 EXPECT_TRUE(spaceBatchTest.testMutatingOutputOperandCounts());
478 }
479 }
480
TEST(OperationValidationTest,SPACE_TO_BATCH_ND_float32)481 TEST(OperationValidationTest, SPACE_TO_BATCH_ND_float32) {
482 spaceBatchOpTest(ANEURALNETWORKS_SPACE_TO_BATCH_ND, ANEURALNETWORKS_TENSOR_FLOAT32);
483 }
484
TEST(OperationValidationTest,BATCH_TO_SPACE_ND_float32)485 TEST(OperationValidationTest, BATCH_TO_SPACE_ND_float32) {
486 spaceBatchOpTest(ANEURALNETWORKS_BATCH_TO_SPACE_ND, ANEURALNETWORKS_TENSOR_FLOAT32);
487 }
488
TEST(OperationValidationTest,SPACE_TO_BATCH_ND_quant8)489 TEST(OperationValidationTest, SPACE_TO_BATCH_ND_quant8) {
490 spaceBatchOpTest(ANEURALNETWORKS_SPACE_TO_BATCH_ND, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
491 }
492
TEST(OperationValidationTest,BATCH_TO_SPACE_ND_quant8)493 TEST(OperationValidationTest, BATCH_TO_SPACE_ND_quant8) {
494 spaceBatchOpTest(ANEURALNETWORKS_BATCH_TO_SPACE_ND, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
495 }
496
transposeAndSqueezeOpTest(ANeuralNetworksOperationType operationCode,int32_t operandCode)497 void transposeAndSqueezeOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
498 uint32_t inputDimensions[4] = {2, 2, 2, 2};
499 ANeuralNetworksOperandType input = {.type = operandCode,
500 .dimensionCount = 4,
501 .dimensions = inputDimensions,
502 .scale = 0.0f,
503 .zeroPoint = 0};
504 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
505 input.scale = 1.f / 256;
506 }
507
508 uint32_t blockDimensions[1] = {4};
509 ANeuralNetworksOperandType dims = {.type = ANEURALNETWORKS_TENSOR_INT32,
510 .dimensionCount = 1,
511 .dimensions = blockDimensions,
512 .scale = 0.0f,
513 .zeroPoint = 0};
514
515 ANeuralNetworksOperandType output = input;
516 OperationTestBase transposeAndSqueezeTest(operationCode, {input, dims}, {output});
517
518 EXPECT_TRUE(transposeAndSqueezeTest.testMutatingInputOperandCode());
519 EXPECT_TRUE(transposeAndSqueezeTest.testMutatingInputOperandCounts());
520 EXPECT_TRUE(transposeAndSqueezeTest.testMutatingOutputOperandCode());
521 EXPECT_TRUE(transposeAndSqueezeTest.testMutatingOutputOperandCounts());
522 }
523
TEST(OperationValidationTest,TRANSPOSE_float32)524 TEST(OperationValidationTest, TRANSPOSE_float32) {
525 transposeAndSqueezeOpTest(ANEURALNETWORKS_TRANSPOSE, ANEURALNETWORKS_TENSOR_FLOAT32);
526 }
527
TEST(OperationValidationTest,SQUEEZE_float32)528 TEST(OperationValidationTest, SQUEEZE_float32) {
529 transposeAndSqueezeOpTest(ANEURALNETWORKS_SQUEEZE, ANEURALNETWORKS_TENSOR_FLOAT32);
530 }
531
TEST(OperationValidationTest,TRANSPOSE_quant8)532 TEST(OperationValidationTest, TRANSPOSE_quant8) {
533 transposeAndSqueezeOpTest(ANEURALNETWORKS_TRANSPOSE, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
534 }
535
TEST(OperationValidationTest,SQUEEZE_quant8)536 TEST(OperationValidationTest, SQUEEZE_quant8) {
537 transposeAndSqueezeOpTest(ANEURALNETWORKS_SQUEEZE, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
538 }
539
convOpTest(int32_t operandCode)540 void convOpTest(int32_t operandCode) {
541 uint32_t inputDimensions[4] = {2, 4, 4, 2};
542 ANeuralNetworksOperandType input = {.type = operandCode,
543 .dimensionCount = 4,
544 .dimensions = inputDimensions,
545 .scale = 0.0f,
546 .zeroPoint = 0};
547 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
548 input.scale = 0.5f;
549 }
550
551 ANeuralNetworksOperandType filter = input;
552 ANeuralNetworksOperandType output = input;
553
554 uint32_t biasDimensions[1] = {2};
555 ANeuralNetworksOperandType bias = {.type = operandCode,
556 .dimensionCount = 1,
557 .dimensions = biasDimensions,
558 .scale = 0.0f,
559 .zeroPoint = 0};
560 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
561 bias.type = ANEURALNETWORKS_TENSOR_INT32;
562 bias.scale = 0.25f;
563 }
564
565 ANeuralNetworksOperandType scalar = {.type = ANEURALNETWORKS_INT32,
566 .dimensionCount = 0,
567 .dimensions = nullptr,
568 .scale = 0.0f,
569 .zeroPoint = 0};
570 ANeuralNetworksOperandType padLeft = scalar;
571 ANeuralNetworksOperandType padRight = scalar;
572 ANeuralNetworksOperandType padTop = scalar;
573 ANeuralNetworksOperandType padBottom = scalar;
574 ANeuralNetworksOperandType strideWidth = scalar;
575 ANeuralNetworksOperandType strideHeight = scalar;
576 ANeuralNetworksOperandType activation = scalar;
577
578 OperationTestBase explicitConvTest(ANEURALNETWORKS_CONV_2D,
579 {input, filter, bias,
580 padLeft, padRight, padTop, padBottom,
581 strideWidth, strideHeight,
582 activation},
583 {output});
584
585 EXPECT_TRUE(explicitConvTest.testMutatingInputOperandCode());
586 EXPECT_TRUE(explicitConvTest.testMutatingInputOperandCounts());
587 EXPECT_TRUE(explicitConvTest.testMutatingOutputOperandCode());
588 EXPECT_TRUE(explicitConvTest.testMutatingOutputOperandCounts());
589
590 ANeuralNetworksOperandType padImplicit = scalar;
591 OperationTestBase implicitConvTest(ANEURALNETWORKS_CONV_2D,
592 {input, filter, bias,
593 padImplicit,
594 strideWidth, strideHeight,
595 activation},
596 {output});
597
598 EXPECT_TRUE(implicitConvTest.testMutatingInputOperandCode());
599 EXPECT_TRUE(implicitConvTest.testMutatingInputOperandCounts());
600 EXPECT_TRUE(implicitConvTest.testMutatingOutputOperandCode());
601 EXPECT_TRUE(implicitConvTest.testMutatingOutputOperandCounts());
602 }
603
TEST(OperationValidationTest,CONV_2D_float32)604 TEST(OperationValidationTest, CONV_2D_float32) {
605 convOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
606 }
607
TEST(OperationValidationTest,CONV_2D_quant8)608 TEST(OperationValidationTest, CONV_2D_quant8) {
609 convOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
610 }
611
depthwiseConvOpTest(int32_t operandCode)612 void depthwiseConvOpTest(int32_t operandCode) {
613 uint32_t inputDimensions[4] = {1, 2, 2, 2};
614 ANeuralNetworksOperandType input = {.type = operandCode,
615 .dimensionCount = 4,
616 .dimensions = inputDimensions,
617 .scale = 0.0f,
618 .zeroPoint = 0};
619 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
620 input.scale = 0.5f;
621 }
622
623 ANeuralNetworksOperandType filter = input;
624 ANeuralNetworksOperandType output = input;
625
626 uint32_t biasDimensions[1] = {2};
627 ANeuralNetworksOperandType bias = {.type = operandCode,
628 .dimensionCount = 1,
629 .dimensions = biasDimensions,
630 .scale = 0.0f,
631 .zeroPoint = 0};
632 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
633 bias.type = ANEURALNETWORKS_TENSOR_INT32;
634 bias.scale = 0.25f;
635 }
636
637 ANeuralNetworksOperandType scalar = {.type = ANEURALNETWORKS_INT32,
638 .dimensionCount = 0,
639 .dimensions = nullptr,
640 .scale = 0.0f,
641 .zeroPoint = 0};
642 ANeuralNetworksOperandType padLeft = scalar;
643 ANeuralNetworksOperandType padRight = scalar;
644 ANeuralNetworksOperandType padTop = scalar;
645 ANeuralNetworksOperandType padBottom = scalar;
646 ANeuralNetworksOperandType strideWidth = scalar;
647 ANeuralNetworksOperandType strideHeight = scalar;
648 ANeuralNetworksOperandType multiplier = scalar;
649 ANeuralNetworksOperandType activation = scalar;
650
651 OperationTestBase explicitDepthwiseConvTest(ANEURALNETWORKS_DEPTHWISE_CONV_2D,
652 {input, filter, bias,
653 padLeft, padRight, padTop, padBottom,
654 strideWidth, strideHeight,
655 multiplier, activation},
656 {output});
657
658 EXPECT_TRUE(explicitDepthwiseConvTest.testMutatingInputOperandCode());
659 EXPECT_TRUE(explicitDepthwiseConvTest.testMutatingInputOperandCounts());
660 EXPECT_TRUE(explicitDepthwiseConvTest.testMutatingOutputOperandCode());
661 EXPECT_TRUE(explicitDepthwiseConvTest.testMutatingOutputOperandCounts());
662
663 ANeuralNetworksOperandType padImplicit = scalar;
664 OperationTestBase implicitDepthwiseConvTest(ANEURALNETWORKS_DEPTHWISE_CONV_2D,
665 {input, filter, bias,
666 padImplicit,
667 strideWidth, strideHeight,
668 multiplier, activation},
669 {output});
670
671 EXPECT_TRUE(implicitDepthwiseConvTest.testMutatingInputOperandCode());
672 EXPECT_TRUE(implicitDepthwiseConvTest.testMutatingInputOperandCounts());
673 EXPECT_TRUE(implicitDepthwiseConvTest.testMutatingOutputOperandCode());
674 EXPECT_TRUE(implicitDepthwiseConvTest.testMutatingOutputOperandCounts());
675 }
676
TEST(OperationValidationTest,DEPTHWISE_CONV_2D_float32)677 TEST(OperationValidationTest, DEPTHWISE_CONV_2D_float32) {
678 depthwiseConvOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
679 }
680
TEST(OperationValidationTest,DEPTHWISE_CONV_2D_quant8)681 TEST(OperationValidationTest, DEPTHWISE_CONV_2D_quant8) {
682 depthwiseConvOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
683 }
684
fullyConnectedOpTest(int32_t operandCode)685 void fullyConnectedOpTest(int32_t operandCode) {
686 uint32_t inputDimensions[2] = {5, 5};
687 ANeuralNetworksOperandType input = {.type = operandCode,
688 .dimensionCount = 2,
689 .dimensions = inputDimensions,
690 .scale = 0.0f,
691 .zeroPoint = 0};
692 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
693 input.scale = 0.5f;
694 }
695
696 ANeuralNetworksOperandType weights = input;
697 ANeuralNetworksOperandType output = input;
698
699 uint32_t biasDimensions[1] = {5};
700 ANeuralNetworksOperandType bias = {.type = operandCode,
701 .dimensionCount = 1,
702 .dimensions = biasDimensions,
703 .scale = 0.0f,
704 .zeroPoint = 0};
705 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
706 bias.type = ANEURALNETWORKS_TENSOR_INT32;
707 bias.scale = 0.25f;
708 }
709
710 ANeuralNetworksOperandType activation = {.type = ANEURALNETWORKS_INT32,
711 .dimensionCount = 0,
712 .dimensions = nullptr,
713 .scale = 0.0f,
714 .zeroPoint = 0};
715
716 OperationTestBase fullyConnectedTest(ANEURALNETWORKS_FULLY_CONNECTED,
717 {input, weights, bias, activation},
718 {output});
719
720 EXPECT_TRUE(fullyConnectedTest.testMutatingInputOperandCode());
721 EXPECT_TRUE(fullyConnectedTest.testMutatingInputOperandCounts());
722 EXPECT_TRUE(fullyConnectedTest.testMutatingOutputOperandCode());
723 EXPECT_TRUE(fullyConnectedTest.testMutatingOutputOperandCounts());
724 }
725
TEST(OperationValidationTest,FULLY_CONNECTED_float32)726 TEST(OperationValidationTest, FULLY_CONNECTED_float32) {
727 fullyConnectedOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
728 }
729
TEST(OperationValidationTest,FULLY_CONNECTED_quant8)730 TEST(OperationValidationTest, FULLY_CONNECTED_quant8) {
731 fullyConnectedOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
732 }
733
concatenationTest(int32_t operandCode)734 void concatenationTest(int32_t operandCode) {
735 uint32_t inputDimensions[2] = {5, 5};
736 ANeuralNetworksOperandType input1 = {.type = operandCode,
737 .dimensionCount = 2,
738 .dimensions = inputDimensions,
739 .scale = 0.0f,
740 .zeroPoint = 0};
741 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
742 input1.scale = 0.5f;
743 }
744 ANeuralNetworksOperandType input2 = input1;
745 ANeuralNetworksOperandType output = input1;
746
747 ANeuralNetworksOperandType activation = {.type = ANEURALNETWORKS_INT32,
748 .dimensionCount = 0,
749 .dimensions = nullptr,
750 .scale = 0.0f,
751 .zeroPoint = 0};
752
753 OperationTestBase concat2Test(ANEURALNETWORKS_CONCATENATION,
754 {input1, input2, activation}, {output});
755
756 EXPECT_TRUE(concat2Test.testMutatingInputOperandCode());
757 EXPECT_TRUE(concat2Test.testMutatingOutputOperandCode());
758 EXPECT_TRUE(concat2Test.testMutatingOutputOperandCounts());
759
760 OperationTestBase concat1Test(ANEURALNETWORKS_CONCATENATION,
761 {input1, activation}, {output});
762
763 EXPECT_TRUE(concat1Test.testMutatingInputOperandCode());
764 EXPECT_TRUE(concat1Test.testMutatingOutputOperandCode());
765 EXPECT_TRUE(concat1Test.testMutatingOutputOperandCounts());
766 }
767
TEST(OperationValidationTest,CONCATENATION_float32)768 TEST(OperationValidationTest, CONCATENATION_float32) {
769 concatenationTest(ANEURALNETWORKS_TENSOR_FLOAT32);
770 }
771
TEST(OperationValidationTest,CONCATENATION_quant8)772 TEST(OperationValidationTest, CONCATENATION_quant8) {
773 concatenationTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
774 }
775
TEST(OperationValidationTest,RESIZE_BILINEAR_float32)776 TEST(OperationValidationTest, RESIZE_BILINEAR_float32) {
777 uint32_t inputDimensions[4] = {2, 2, 2, 2};
778 ANeuralNetworksOperandType input = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
779 .dimensionCount = 4,
780 .dimensions = inputDimensions,
781 .scale = 0.0f,
782 .zeroPoint = 0};
783 ANeuralNetworksOperandType height = {.type = ANEURALNETWORKS_INT32,
784 .dimensionCount = 0,
785 .dimensions = nullptr,
786 .scale = 0.0f,
787 .zeroPoint = 0};
788 ANeuralNetworksOperandType width = height;
789 ANeuralNetworksOperandType output = input;
790 OperationTestBase resizeTest(ANEURALNETWORKS_RESIZE_BILINEAR,
791 {input, height, width}, {output});
792
793 EXPECT_TRUE(resizeTest.testMutatingInputOperandCode());
794 EXPECT_TRUE(resizeTest.testMutatingInputOperandCounts());
795 EXPECT_TRUE(resizeTest.testMutatingOutputOperandCode());
796 EXPECT_TRUE(resizeTest.testMutatingOutputOperandCounts());
797 }
798
embeddingLookupTest(int32_t operandCode)799 void embeddingLookupTest(int32_t operandCode) {
800 uint32_t lookupDimensions[1] = {5};
801 ANeuralNetworksOperandType lookup = {.type = ANEURALNETWORKS_TENSOR_INT32,
802 .dimensionCount = 1,
803 .dimensions = lookupDimensions,
804 .scale = 0.0f,
805 .zeroPoint = 0};
806
807 uint32_t inputDimensions[2] = {5, 5};
808 ANeuralNetworksOperandType input = {.type = operandCode,
809 .dimensionCount = 2,
810 .dimensions = inputDimensions,
811 .scale = 0.0f,
812 .zeroPoint = 0};
813 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
814 input.scale = 0.5f;
815 }
816 ANeuralNetworksOperandType output = input;
817
818 OperationTestBase embedLookupTest(ANEURALNETWORKS_EMBEDDING_LOOKUP,
819 {lookup, input}, {output});
820
821 EXPECT_TRUE(embedLookupTest.testMutatingInputOperandCode());
822 EXPECT_TRUE(embedLookupTest.testMutatingInputOperandCounts());
823 EXPECT_TRUE(embedLookupTest.testMutatingOutputOperandCode());
824 EXPECT_TRUE(embedLookupTest.testMutatingOutputOperandCounts());
825 }
826
TEST(OperationValidationTest,EMBEDDING_LOOKUP_float32)827 TEST(OperationValidationTest, EMBEDDING_LOOKUP_float32) {
828 embeddingLookupTest(ANEURALNETWORKS_TENSOR_FLOAT32);
829 }
830
TEST(OperationValidationTest,EMBEDDING_LOOKUP_quant8)831 TEST(OperationValidationTest, EMBEDDING_LOOKUP_quant8) {
832 embeddingLookupTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
833 }
834
hashtableLookupTest(int32_t operandCode)835 void hashtableLookupTest(int32_t operandCode) {
836 uint32_t lookupDimensions[1] = {5};
837 ANeuralNetworksOperandType lookup = {.type = ANEURALNETWORKS_TENSOR_INT32,
838 .dimensionCount = 1,
839 .dimensions = lookupDimensions,
840 .scale = 0.0f,
841 .zeroPoint = 0};
842 ANeuralNetworksOperandType keys = lookup;
843
844 uint32_t valuesDimensions[2] = {5, 5};
845 ANeuralNetworksOperandType values = {.type = operandCode,
846 .dimensionCount = 2,
847 .dimensions = valuesDimensions,
848 .scale = 0.0f,
849 .zeroPoint = 0};
850 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
851 values.scale = 0.5f;
852 }
853 ANeuralNetworksOperandType output = values;
854
855 ANeuralNetworksOperandType hits = lookup;
856 hits.type = ANEURALNETWORKS_TENSOR_QUANT8_ASYMM;
857 hits.scale = 1.0f;
858
859 OperationTestBase hashLookupTest(ANEURALNETWORKS_HASHTABLE_LOOKUP,
860 {lookup, keys, values}, {output, hits});
861
862 EXPECT_TRUE(hashLookupTest.testMutatingInputOperandCode());
863 EXPECT_TRUE(hashLookupTest.testMutatingInputOperandCounts());
864 EXPECT_TRUE(hashLookupTest.testMutatingOutputOperandCode());
865 EXPECT_TRUE(hashLookupTest.testMutatingOutputOperandCounts());
866 }
867
TEST(OperationValidationTest,HASHTABLE_LOOKUP_float32)868 TEST(OperationValidationTest, HASHTABLE_LOOKUP_float32) {
869 hashtableLookupTest(ANEURALNETWORKS_TENSOR_FLOAT32);
870 }
871
TEST(OperationValidationTest,HASHTABLE_LOOKUP_quant8)872 TEST(OperationValidationTest, HASHTABLE_LOOKUP_quant8) {
873 hashtableLookupTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
874 }
875
lshProjectionTest(int32_t operandCode)876 void lshProjectionTest(int32_t operandCode) {
877 uint32_t inputDimensions[2] = {5, 5};
878 ANeuralNetworksOperandType hash = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
879 .dimensionCount = 2,
880 .dimensions = inputDimensions,
881 .scale = 0.0f,
882 .zeroPoint = 0};
883
884 ANeuralNetworksOperandType input = hash;
885 input.type = operandCode;
886 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
887 input.scale = 0.5f;
888 }
889
890 uint32_t weightDimensions[1] = {5};
891 ANeuralNetworksOperandType weight = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
892 .dimensionCount = 1,
893 .dimensions = weightDimensions,
894 .scale = 0.0f,
895 .zeroPoint = 0};
896
897 ANeuralNetworksOperandType type = {.type = ANEURALNETWORKS_INT32,
898 .dimensionCount = 0,
899 .dimensions = nullptr,
900 .scale = 0.0f,
901 .zeroPoint = 0};
902
903 ANeuralNetworksOperandType output = weight;
904 output.type = ANEURALNETWORKS_TENSOR_INT32;
905
906 OperationTestBase lshProjTest(ANEURALNETWORKS_LSH_PROJECTION,
907 {hash, input, weight, type}, {output});
908
909 EXPECT_TRUE(lshProjTest.testMutatingInputOperandCode());
910 EXPECT_TRUE(lshProjTest.testMutatingInputOperandCounts());
911 EXPECT_TRUE(lshProjTest.testMutatingOutputOperandCode());
912 EXPECT_TRUE(lshProjTest.testMutatingOutputOperandCounts());
913 }
914
TEST(OperationValidationTest,LSH_PROJECTION_float32)915 TEST(OperationValidationTest, LSH_PROJECTION_float32) {
916 lshProjectionTest(ANEURALNETWORKS_TENSOR_FLOAT32);
917 }
918
TEST(OperationValidationTest,LSH_PROJECTION_quant8)919 TEST(OperationValidationTest, LSH_PROJECTION_quant8) {
920 lshProjectionTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
921 }
922
TEST(OperationValidationTest,LSTM_float32)923 TEST(OperationValidationTest, LSTM_float32) {
924 uint32_t oneDimensional[1] = {5};
925 uint32_t twoDimensional[2] = {5, 5};
926 ANeuralNetworksOperandType floatTensor1D = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
927 .dimensionCount = 1,
928 .dimensions = oneDimensional,
929 .scale = 0.0f,
930 .zeroPoint = 0};
931 ANeuralNetworksOperandType floatTensor2D = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
932 .dimensionCount = 2,
933 .dimensions = twoDimensional,
934 .scale = 0.0f,
935 .zeroPoint = 0};
936 ANeuralNetworksOperandType intScalar = {.type = ANEURALNETWORKS_INT32,
937 .dimensionCount = 0,
938 .dimensions = nullptr,
939 .scale = 0.0f,
940 .zeroPoint = 0};
941 ANeuralNetworksOperandType floatScalar = {.type = ANEURALNETWORKS_FLOAT32,
942 .dimensionCount = 0,
943 .dimensions = nullptr,
944 .scale = 0.0f,
945 .zeroPoint = 0};
946
947 ANeuralNetworksOperandType input = floatTensor2D;
948 ANeuralNetworksOperandType inputToInput = floatTensor2D;
949 ANeuralNetworksOperandType inputToForget = floatTensor2D;
950 ANeuralNetworksOperandType inputToCell = floatTensor2D;
951 ANeuralNetworksOperandType inputToOutput = floatTensor2D;
952 ANeuralNetworksOperandType recurrentToInput = floatTensor2D;
953 ANeuralNetworksOperandType recurrentToForget = floatTensor2D;
954 ANeuralNetworksOperandType recurrentToCell = floatTensor2D;
955 ANeuralNetworksOperandType recurrentToOutput = floatTensor2D;
956 ANeuralNetworksOperandType cellToInput = floatTensor1D;
957 ANeuralNetworksOperandType cellToForget = floatTensor1D;
958 ANeuralNetworksOperandType cellToOutput = floatTensor1D;
959 ANeuralNetworksOperandType inputGateBias = floatTensor1D;
960 ANeuralNetworksOperandType forgetGateBias = floatTensor1D;
961 ANeuralNetworksOperandType cellBias = floatTensor1D;
962 ANeuralNetworksOperandType outputGateBias = floatTensor1D;
963 ANeuralNetworksOperandType projWeights = floatTensor2D;
964 ANeuralNetworksOperandType projBias = floatTensor1D;
965 ANeuralNetworksOperandType outputStateIn = floatTensor2D;
966 ANeuralNetworksOperandType cellStateIn = floatTensor2D;
967 ANeuralNetworksOperandType activation = intScalar;
968 ANeuralNetworksOperandType clipCellState = floatScalar;
969 ANeuralNetworksOperandType clipProjLayer = floatScalar;
970
971 ANeuralNetworksOperandType scratch = floatTensor2D;
972 ANeuralNetworksOperandType outputStateOut = floatTensor2D;
973 ANeuralNetworksOperandType cellStateOut = floatTensor2D;
974 ANeuralNetworksOperandType output = floatTensor2D;
975
976 OperationTestBase lstmTest(ANEURALNETWORKS_LSTM,
977 {input, inputToInput, inputToForget, inputToCell, inputToOutput, recurrentToInput,
978 recurrentToForget, recurrentToCell, recurrentToOutput, cellToInput, cellToForget,
979 cellToOutput, inputGateBias, forgetGateBias, cellBias, outputGateBias, projWeights,
980 projBias, outputStateIn, cellStateIn, activation, clipCellState, clipProjLayer},
981 {scratch, outputStateOut, cellStateOut, output});
982
983 EXPECT_TRUE(lstmTest.testMutatingInputOperandCode());
984 EXPECT_TRUE(lstmTest.testMutatingInputOperandCounts());
985 EXPECT_TRUE(lstmTest.testMutatingOutputOperandCode());
986 EXPECT_TRUE(lstmTest.testMutatingOutputOperandCounts());
987 }
988
TEST(OperationValidationTest,RNN_float32)989 TEST(OperationValidationTest, RNN_float32) {
990 uint32_t oneDimensional[1] = {5};
991 uint32_t twoDimensional[2] = {5, 5};
992 ANeuralNetworksOperandType floatTensor1D = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
993 .dimensionCount = 1,
994 .dimensions = oneDimensional,
995 .scale = 0.0f,
996 .zeroPoint = 0};
997 ANeuralNetworksOperandType floatTensor2D = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
998 .dimensionCount = 2,
999 .dimensions = twoDimensional,
1000 .scale = 0.0f,
1001 .zeroPoint = 0};
1002 ANeuralNetworksOperandType intScalar = {.type = ANEURALNETWORKS_INT32,
1003 .dimensionCount = 0,
1004 .dimensions = nullptr,
1005 .scale = 0.0f,
1006 .zeroPoint = 0};
1007
1008 ANeuralNetworksOperandType input = floatTensor2D;
1009 ANeuralNetworksOperandType weights = floatTensor2D;
1010 ANeuralNetworksOperandType recurrentWeights = floatTensor2D;
1011 ANeuralNetworksOperandType bias = floatTensor1D;
1012 ANeuralNetworksOperandType hiddenStateIn = floatTensor2D;
1013 ANeuralNetworksOperandType activation = intScalar;
1014
1015 ANeuralNetworksOperandType hiddenStateOut = floatTensor2D;
1016 ANeuralNetworksOperandType output = floatTensor2D;
1017
1018 OperationTestBase rnnTest(ANEURALNETWORKS_RNN,
1019 {input, weights, recurrentWeights, bias, hiddenStateIn, activation},
1020 {hiddenStateOut, output});
1021
1022 EXPECT_TRUE(rnnTest.testMutatingInputOperandCode());
1023 EXPECT_TRUE(rnnTest.testMutatingInputOperandCounts());
1024 EXPECT_TRUE(rnnTest.testMutatingOutputOperandCode());
1025 EXPECT_TRUE(rnnTest.testMutatingOutputOperandCounts());
1026 }
1027
TEST(OperationValidationTest,SVDF_float32)1028 TEST(OperationValidationTest, SVDF_float32) {
1029 uint32_t oneDimensional[1] = {5};
1030 uint32_t twoDimensional[2] = {5, 5};
1031 ANeuralNetworksOperandType floatTensor1D = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
1032 .dimensionCount = 1,
1033 .dimensions = oneDimensional,
1034 .scale = 0.0f,
1035 .zeroPoint = 0};
1036 ANeuralNetworksOperandType floatTensor2D = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
1037 .dimensionCount = 2,
1038 .dimensions = twoDimensional,
1039 .scale = 0.0f,
1040 .zeroPoint = 0};
1041 ANeuralNetworksOperandType intScalar = {.type = ANEURALNETWORKS_INT32,
1042 .dimensionCount = 0,
1043 .dimensions = nullptr,
1044 .scale = 0.0f,
1045 .zeroPoint = 0};
1046
1047 ANeuralNetworksOperandType input = floatTensor2D;
1048 ANeuralNetworksOperandType weightsFeature = floatTensor2D;
1049 ANeuralNetworksOperandType weightsTime = floatTensor2D;
1050 ANeuralNetworksOperandType bias = floatTensor1D;
1051 ANeuralNetworksOperandType stateIn = floatTensor2D;
1052 ANeuralNetworksOperandType rank = intScalar;
1053 ANeuralNetworksOperandType activation = intScalar;
1054
1055 ANeuralNetworksOperandType stateOut = floatTensor2D;
1056 ANeuralNetworksOperandType output = floatTensor2D;
1057
1058 OperationTestBase svdfTest(ANEURALNETWORKS_SVDF,
1059 {input, weightsFeature, weightsTime, bias, stateIn, rank, activation},
1060 {stateOut, output});
1061
1062 EXPECT_TRUE(svdfTest.testMutatingInputOperandCode());
1063 EXPECT_TRUE(svdfTest.testMutatingInputOperandCounts());
1064 EXPECT_TRUE(svdfTest.testMutatingOutputOperandCode());
1065 EXPECT_TRUE(svdfTest.testMutatingOutputOperandCounts());
1066 }
1067
stridedSliceOpTest(int32_t operandCode)1068 void stridedSliceOpTest(int32_t operandCode) {
1069 uint32_t inputDimensions[2] = {5, 5};
1070 ANeuralNetworksOperandType input = {.type = operandCode,
1071 .dimensionCount = 2,
1072 .dimensions = inputDimensions,
1073 .scale = 0.0f,
1074 .zeroPoint = 0};
1075 if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
1076 input.scale = 0.5f;
1077 }
1078 ANeuralNetworksOperandType output = input;
1079
1080 uint32_t beginsDimensions[1] = {2};
1081 ANeuralNetworksOperandType begins = {.type = ANEURALNETWORKS_TENSOR_INT32,
1082 .dimensionCount = 1,
1083 .dimensions = beginsDimensions,
1084 .scale = 0.0f,
1085 .zeroPoint = 0};
1086
1087 ANeuralNetworksOperandType ends = begins;
1088 ANeuralNetworksOperandType strides = begins;
1089
1090 ANeuralNetworksOperandType beginMask = {.type = ANEURALNETWORKS_INT32,
1091 .dimensionCount = 0,
1092 .dimensions = nullptr,
1093 .scale = 0.0f,
1094 .zeroPoint = 0};
1095 ANeuralNetworksOperandType endMask = beginMask;
1096 ANeuralNetworksOperandType shrinkAxisMask = beginMask;
1097
1098 OperationTestBase stridedSliceTest(ANEURALNETWORKS_STRIDED_SLICE,
1099 {input, begins, ends, strides,
1100 beginMask, endMask, shrinkAxisMask},
1101 {output});
1102
1103 EXPECT_TRUE(stridedSliceTest.testMutatingInputOperandCode());
1104 EXPECT_TRUE(stridedSliceTest.testMutatingInputOperandCounts());
1105 EXPECT_TRUE(stridedSliceTest.testMutatingOutputOperandCode());
1106 EXPECT_TRUE(stridedSliceTest.testMutatingOutputOperandCounts());
1107 }
1108
TEST(OperationValidationTest,STRIDED_SLICE_float32)1109 TEST(OperationValidationTest, STRIDED_SLICE_float32) {
1110 stridedSliceOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
1111 }
1112
TEST(OperationValidationTest,STRIDED_SLICE_quant8)1113 TEST(OperationValidationTest, STRIDED_SLICE_quant8) {
1114 stridedSliceOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
1115 }
1116
1117 } // end namespace
1118