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 <algorithm>
18
19 #include "fuzzing/operation_signatures/OperationSignatureUtils.h"
20
21 namespace android {
22 namespace nn {
23 namespace fuzzing_test {
24
broadcastOpConstructor(TestOperandType dataType,uint32_t rank,RandomOperation * op)25 static void broadcastOpConstructor(TestOperandType dataType, uint32_t rank, RandomOperation* op) {
26 const uint32_t rank2 = getUniform(1u, rank), rankDiff = rank - rank2;
27 op->inputs[0]->dimensions.resize(rank);
28 op->inputs[1]->dimensions.resize(rank2);
29 op->outputs[0]->dimensions.resize(rank);
30 for (uint32_t i = 0; i < rank; i++) {
31 op->outputs[0]->dimensions[i] = RandomVariableType::FREE;
32 if (i < rankDiff) {
33 op->inputs[0]->dimensions[i] = op->outputs[0]->dimensions[i];
34 } else {
35 if (getBernoulli(0.5f)) {
36 // No broadcast on this dimension.
37 op->inputs[0]->dimensions[i] = op->outputs[0]->dimensions[i];
38 op->inputs[1]->dimensions[i - rankDiff] = op->outputs[0]->dimensions[i];
39 } else if (getBernoulli(0.5f)) {
40 // input0 broadcast on this dimension.
41 op->inputs[0]->dimensions[i] = 1;
42 op->inputs[1]->dimensions[i - rankDiff] = op->outputs[0]->dimensions[i];
43 } else {
44 // input1 broadcast on this dimension.
45 op->inputs[0]->dimensions[i] = op->outputs[0]->dimensions[i];
46 op->inputs[1]->dimensions[i - rankDiff] = 1;
47 }
48 }
49 }
50 if (getBernoulli(0.5f)) {
51 // Swap the dimensions to test the case that inpuy 1 has a larger rank than input0.
52 op->inputs[0]->dimensions.swap(op->inputs[1]->dimensions);
53 }
54
55 // MUL requires output.scale > input0.scale * input1.scale.
56 if (isQuantizedType(dataType) && op->opType == TestOperationType::MUL) {
57 float minScale = op->inputs[0]->scale * op->inputs[1]->scale;
58 op->outputs[0]->scale = getUniform(minScale, minScale * 5);
59 }
60
61 // DIV and POW may produce Inf output values. We should not connect this output tensor to the
62 // input of another operation.
63 if (op->opType == TestOperationType::DIV || op->opType == TestOperationType::POW) {
64 op->outputs[0]->doNotConnect = true;
65 }
66
67 // For ADD/MUL/SUB/DIV with TENSOR_INT32 tensors, the activation must be "NONE".
68 if ((op->opType == TestOperationType::ADD || op->opType == TestOperationType::MUL ||
69 op->opType == TestOperationType::SUB || op->opType == TestOperationType::DIV) &&
70 dataType == TestOperandType::TENSOR_INT32) {
71 op->inputs[2]->setScalarValue(0);
72 }
73
74 if (op->opType == TestOperationType::DIV) {
75 op->inputs[1]->valueProperties = RandomOperand::NON_ZERO;
76 }
77
78 if (op->opType == TestOperationType::POW) {
79 op->inputs[0]->valueProperties = RandomOperand::NON_NEGATIVE;
80 }
81 }
82
83 // For broadcast operations with fused activation.
84 #define DEFINE_BROADCAST_WITH_ACT_SIGNATURE(op, ver, ...) \
85 DEFINE_OPERATION_SIGNATURE(op##_##ver){ \
86 .opType = TestOperationType::op, \
87 .supportedDataTypes = {__VA_ARGS__}, \
88 .supportedRanks = {1, 2, 3, 4}, \
89 .version = TestHalVersion::ver, \
90 .inputs = {INPUT_DEFAULT, INPUT_DEFAULT, \
91 PARAMETER_CHOICE(TestOperandType::INT32, 0, 1, 2, 3)}, \
92 .outputs = {OUTPUT_DEFAULT}, \
93 .constructor = broadcastOpConstructor};
94
95 // Arithmetic with activation.
96 DEFINE_BROADCAST_WITH_ACT_SIGNATURE(ADD, V1_0, TestOperandType::TENSOR_FLOAT32,
97 TestOperandType::TENSOR_QUANT8_ASYMM);
98 DEFINE_BROADCAST_WITH_ACT_SIGNATURE(MUL, V1_0, TestOperandType::TENSOR_FLOAT32,
99 TestOperandType::TENSOR_QUANT8_ASYMM);
100 DEFINE_BROADCAST_WITH_ACT_SIGNATURE(SUB, V1_1, TestOperandType::TENSOR_FLOAT32);
101 DEFINE_BROADCAST_WITH_ACT_SIGNATURE(DIV, V1_1, TestOperandType::TENSOR_FLOAT32);
102 DEFINE_BROADCAST_WITH_ACT_SIGNATURE(ADD, V1_2, TestOperandType::TENSOR_FLOAT16);
103 DEFINE_BROADCAST_WITH_ACT_SIGNATURE(MUL, V1_2, TestOperandType::TENSOR_FLOAT16);
104 DEFINE_BROADCAST_WITH_ACT_SIGNATURE(SUB, V1_2, TestOperandType::TENSOR_FLOAT16,
105 TestOperandType::TENSOR_QUANT8_ASYMM);
106 DEFINE_BROADCAST_WITH_ACT_SIGNATURE(DIV, V1_2, TestOperandType::TENSOR_FLOAT16);
107 DEFINE_BROADCAST_WITH_ACT_SIGNATURE(ADD, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED,
108 TestOperandType::TENSOR_INT32);
109 DEFINE_BROADCAST_WITH_ACT_SIGNATURE(MUL, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED,
110 TestOperandType::TENSOR_INT32);
111 DEFINE_BROADCAST_WITH_ACT_SIGNATURE(SUB, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED,
112 TestOperandType::TENSOR_INT32);
113 DEFINE_BROADCAST_WITH_ACT_SIGNATURE(DIV, V1_3, TestOperandType::TENSOR_INT32);
114
115 // For broadcast ops with output of the same data type as inputs.
116 #define DEFINE_BROADCAST_SIGNATURE(op, ver, ...) \
117 DEFINE_OPERATION_SIGNATURE(op##_##ver){.opType = TestOperationType::op, \
118 .supportedDataTypes = {__VA_ARGS__}, \
119 .supportedRanks = {1, 2, 3, 4, 5}, \
120 .version = TestHalVersion::ver, \
121 .inputs = {INPUT_DEFAULT, INPUT_DEFAULT}, \
122 .outputs = {OUTPUT_DEFAULT}, \
123 .constructor = broadcastOpConstructor};
124
125 // Arithmetic without activation.
126 DEFINE_BROADCAST_SIGNATURE(POW, V1_2, TestOperandType::TENSOR_FLOAT32,
127 TestOperandType::TENSOR_FLOAT16);
128 DEFINE_BROADCAST_SIGNATURE(PRELU, V1_2, TestOperandType::TENSOR_FLOAT32,
129 TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_QUANT8_ASYMM);
130 DEFINE_BROADCAST_SIGNATURE(MAXIMUM, V1_2, TestOperandType::TENSOR_FLOAT32,
131 TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_QUANT8_ASYMM,
132 TestOperandType::TENSOR_INT32);
133 DEFINE_BROADCAST_SIGNATURE(MINIMUM, V1_2, TestOperandType::TENSOR_FLOAT32,
134 TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_QUANT8_ASYMM,
135 TestOperandType::TENSOR_INT32);
136 DEFINE_BROADCAST_SIGNATURE(PRELU, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
137 DEFINE_BROADCAST_SIGNATURE(MAXIMUM, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
138 DEFINE_BROADCAST_SIGNATURE(MINIMUM, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
139
140 // Logical
141 DEFINE_BROADCAST_SIGNATURE(LOGICAL_AND, V1_2, TestOperandType::TENSOR_BOOL8);
142 DEFINE_BROADCAST_SIGNATURE(LOGICAL_OR, V1_2, TestOperandType::TENSOR_BOOL8);
143
144 // Comparisons
145 #define DEFINE_COMPARISON_SIGNATURE(op, ver, ...) \
146 DEFINE_OPERATION_SIGNATURE(op##_##ver){ \
147 .opType = TestOperationType::op, \
148 .supportedDataTypes = {__VA_ARGS__}, \
149 .supportedRanks = {1, 2, 3, 4}, \
150 .version = TestHalVersion::ver, \
151 .inputs = {INPUT_DEFAULT, INPUT_DEFAULT}, \
152 .outputs = {OUTPUT_TYPED(TestOperandType::TENSOR_BOOL8)}, \
153 .constructor = broadcastOpConstructor};
154
155 DEFINE_COMPARISON_SIGNATURE(EQUAL, V1_2, TestOperandType::TENSOR_FLOAT32,
156 TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_INT32,
157 TestOperandType::TENSOR_QUANT8_ASYMM, TestOperandType::TENSOR_BOOL8);
158 DEFINE_COMPARISON_SIGNATURE(GREATER, V1_2, TestOperandType::TENSOR_FLOAT32,
159 TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_INT32,
160 TestOperandType::TENSOR_QUANT8_ASYMM);
161 DEFINE_COMPARISON_SIGNATURE(GREATER_EQUAL, V1_2, TestOperandType::TENSOR_FLOAT32,
162 TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_INT32,
163 TestOperandType::TENSOR_QUANT8_ASYMM);
164 DEFINE_COMPARISON_SIGNATURE(LESS, V1_2, TestOperandType::TENSOR_FLOAT32,
165 TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_INT32,
166 TestOperandType::TENSOR_QUANT8_ASYMM);
167 DEFINE_COMPARISON_SIGNATURE(LESS_EQUAL, V1_2, TestOperandType::TENSOR_FLOAT32,
168 TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_INT32,
169 TestOperandType::TENSOR_QUANT8_ASYMM);
170 DEFINE_COMPARISON_SIGNATURE(NOT_EQUAL, V1_2, TestOperandType::TENSOR_FLOAT32,
171 TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_INT32,
172 TestOperandType::TENSOR_QUANT8_ASYMM, TestOperandType::TENSOR_BOOL8);
173 DEFINE_COMPARISON_SIGNATURE(EQUAL, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
174 DEFINE_COMPARISON_SIGNATURE(GREATER, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
175 DEFINE_COMPARISON_SIGNATURE(GREATER_EQUAL, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
176 DEFINE_COMPARISON_SIGNATURE(LESS, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
177 DEFINE_COMPARISON_SIGNATURE(LESS_EQUAL, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
178 DEFINE_COMPARISON_SIGNATURE(NOT_EQUAL, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
179
180 } // namespace fuzzing_test
181 } // namespace nn
182 } // namespace android
183