1 /*
2  * Copyright (C) 2019 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 "fuzzing/operation_signatures/OperationSignatureUtils.h"
18 
19 namespace android {
20 namespace nn {
21 namespace fuzzing_test {
22 
reduceOpConstructor(TestOperandType,uint32_t rank,RandomOperation * op)23 static void reduceOpConstructor(TestOperandType, uint32_t rank, RandomOperation* op) {
24     setFreeDimensions(op->inputs[0], rank);
25 
26     // A boolean array indicating whether each dimension is selected to be reduced.
27     bool reduce[4] = {false, false, false, false};
28 
29     // Generate values for the "axis" tensor.
30     uint32_t numAxis = getUniform<int32_t>(1, 10);
31     op->inputs[1]->dimensions = {numAxis};
32     op->inputs[1]->resizeBuffer<int32_t>(numAxis);
33     for (uint32_t i = 0; i < numAxis; i++) {
34         int32_t dim = getRandomAxis(rank);
35         op->inputs[1]->value<int32_t>(i) = dim;
36         reduce[toPositiveAxis(dim, rank)] = true;
37     }
38 
39     // This scalar may have two types: in MEAN it is INT32, in REDUCE_* it is BOOL
40     bool keepDims;
41     if (op->inputs[2]->dataType == TestOperandType::BOOL) {
42         keepDims = op->inputs[2]->value<bool8>();
43     } else {
44         keepDims = op->inputs[2]->value<int32_t>() > 0;
45     }
46 
47     for (uint32_t i = 0; i < rank; i++) {
48         if (!reduce[i]) {
49             op->outputs[0]->dimensions.emplace_back(op->inputs[0]->dimensions[i]);
50         } else if (keepDims) {
51             op->outputs[0]->dimensions.emplace_back(1);
52         }
53     }
54     setSameQuantization(op->outputs[0], op->inputs[0]);
55 
56     // REDUCE_PROD may produce Inf output values. We should not connect the output tensor to the
57     // input of another operation.
58     if (op->opType == TestOperationType::REDUCE_PROD) {
59         op->outputs[0]->doNotConnect = true;
60     }
61 }
62 
63 #define DEFINE_MEAN_SIGNATURE(ver, ...)                                              \
64     DEFINE_OPERATION_SIGNATURE(MEAN_##ver){                                          \
65             .opType = TestOperationType::MEAN,                                       \
66             .supportedDataTypes = {__VA_ARGS__},                                     \
67             .supportedRanks = {1, 2, 3, 4},                                          \
68             .version = TestHalVersion::ver,                                          \
69             .inputs = {INPUT_DEFAULT, PARAMETER_NONE(TestOperandType::TENSOR_INT32), \
70                        PARAMETER_CHOICE(TestOperandType::INT32, -100, 100)},         \
71             .outputs = {OUTPUT_DEFAULT},                                             \
72             .constructor = reduceOpConstructor};
73 
74 DEFINE_MEAN_SIGNATURE(V1_1, TestOperandType::TENSOR_FLOAT32, TestOperandType::TENSOR_QUANT8_ASYMM);
75 DEFINE_MEAN_SIGNATURE(V1_2, TestOperandType::TENSOR_FLOAT16);
76 DEFINE_MEAN_SIGNATURE(V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
77 
78 #define DEFINE_REDUCE_SIGNATURE(op, ver, ...)                                        \
79     DEFINE_OPERATION_SIGNATURE(op##_##ver){                                          \
80             .opType = TestOperationType::op,                                         \
81             .supportedDataTypes = {__VA_ARGS__},                                     \
82             .supportedRanks = {1, 2, 3, 4},                                          \
83             .version = TestHalVersion::ver,                                          \
84             .inputs = {INPUT_DEFAULT, PARAMETER_NONE(TestOperandType::TENSOR_INT32), \
85                        PARAMETER_CHOICE(TestOperandType::BOOL, true, false)},        \
86             .outputs = {OUTPUT_DEFAULT},                                             \
87             .constructor = reduceOpConstructor};
88 
89 DEFINE_REDUCE_SIGNATURE(REDUCE_ALL, V1_2, TestOperandType::TENSOR_BOOL8);
90 DEFINE_REDUCE_SIGNATURE(REDUCE_ANY, V1_2, TestOperandType::TENSOR_BOOL8);
91 DEFINE_REDUCE_SIGNATURE(REDUCE_PROD, V1_2, TestOperandType::TENSOR_FLOAT32,
92                         TestOperandType::TENSOR_FLOAT16);
93 DEFINE_REDUCE_SIGNATURE(REDUCE_SUM, V1_2, TestOperandType::TENSOR_FLOAT32,
94                         TestOperandType::TENSOR_FLOAT16);
95 DEFINE_REDUCE_SIGNATURE(REDUCE_MAX, V1_2, TestOperandType::TENSOR_FLOAT32,
96                         TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_QUANT8_ASYMM);
97 DEFINE_REDUCE_SIGNATURE(REDUCE_MIN, V1_2, TestOperandType::TENSOR_FLOAT32,
98                         TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_QUANT8_ASYMM);
99 DEFINE_REDUCE_SIGNATURE(REDUCE_MAX, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
100 DEFINE_REDUCE_SIGNATURE(REDUCE_MIN, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
101 
singleAxisReduceOpConstructor(TestOperandType,uint32_t rank,RandomOperation * op)102 static void singleAxisReduceOpConstructor(TestOperandType, uint32_t rank, RandomOperation* op) {
103     setFreeDimensions(op->inputs[0], rank);
104     // "axis" must be in the range [-rank, rank).
105     // Negative "axis" is used to specify axis from the end.
106     int32_t axis = getRandomAxis(rank);
107     op->inputs[1]->setScalarValue<int32_t>(axis);
108     for (uint32_t i = 0; i < rank; i++) {
109         if (i != static_cast<uint32_t>(toPositiveAxis(axis, rank))) {
110             op->outputs[0]->dimensions.emplace_back(op->inputs[0]->dimensions[i]);
111         }
112     }
113 }
114 
115 #define DEFINE_ARGMIN_MAX_SIGNATURE(op, ver, ...)                              \
116     DEFINE_OPERATION_SIGNATURE(op##_##ver){                                    \
117             .opType = TestOperationType::op,                                   \
118             .supportedDataTypes = {__VA_ARGS__},                               \
119             .supportedRanks = {1, 2, 3, 4, 5},                                 \
120             .version = TestHalVersion::ver,                                    \
121             .inputs = {INPUT_DEFAULT, PARAMETER_NONE(TestOperandType::INT32)}, \
122             .outputs = {OUTPUT_TYPED(TestOperandType::TENSOR_INT32)},          \
123             .constructor = singleAxisReduceOpConstructor};
124 
125 DEFINE_ARGMIN_MAX_SIGNATURE(ARGMAX, V1_2, TestOperandType::TENSOR_FLOAT32,
126                             TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_INT32,
127                             TestOperandType::TENSOR_QUANT8_ASYMM);
128 DEFINE_ARGMIN_MAX_SIGNATURE(ARGMIN, V1_2, TestOperandType::TENSOR_FLOAT32,
129                             TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_INT32,
130                             TestOperandType::TENSOR_QUANT8_ASYMM);
131 DEFINE_ARGMIN_MAX_SIGNATURE(ARGMAX, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
132 DEFINE_ARGMIN_MAX_SIGNATURE(ARGMIN, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
133 
134 }  // namespace fuzzing_test
135 }  // namespace nn
136 }  // namespace android
137