packages/modules/NeuralNetworks/runtime/test/fuzzing/operation_signatures/Elementwise.cpp

227 lines
13 KiB
C++

/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fuzzing/operation_signatures/OperationSignatureUtils.h"
namespace android {
namespace nn {
namespace fuzzing_test {
static void elementwiseOpConstructor(TestOperandType dataType, uint32_t rank, RandomOperation* op) {
sameShapeOpConstructor(dataType, rank, op);
switch (op->opType) {
case TestOperationType::RELU:
case TestOperationType::RELU6:
op->outputs[0]->valueProperties = RandomOperand::NON_NEGATIVE;
break;
case TestOperationType::LOGISTIC:
op->outputs[0]->valueProperties = RandomOperand::NON_ZERO | RandomOperand::NON_NEGATIVE;
break;
case TestOperationType::ABS:
op->outputs[0]->valueProperties = RandomOperand::NON_NEGATIVE;
break;
case TestOperationType::EXP:
op->outputs[0]->valueProperties = RandomOperand::NON_ZERO | RandomOperand::NON_NEGATIVE;
break;
case TestOperationType::LOG:
op->inputs[0]->valueProperties = RandomOperand::NON_ZERO | RandomOperand::NON_NEGATIVE;
break;
case TestOperationType::RSQRT:
op->inputs[0]->valueProperties = RandomOperand::NON_ZERO | RandomOperand::NON_NEGATIVE;
op->outputs[0]->valueProperties = RandomOperand::NON_ZERO | RandomOperand::NON_NEGATIVE;
break;
case TestOperationType::SQRT:
op->inputs[0]->valueProperties = RandomOperand::NON_NEGATIVE;
op->outputs[0]->valueProperties = RandomOperand::NON_NEGATIVE;
break;
default:
break;
}
}
#define DEFINE_ELEMENTWISE_SIGNATURE(op, ver, ...) \
DEFINE_OPERATION_SIGNATURE(op##_##ver){.opType = TestOperationType::op, \
.supportedDataTypes = {__VA_ARGS__}, \
.supportedRanks = {1, 2, 3, 4}, \
.version = TestHalVersion::ver, \
.inputs = {INPUT_DEFAULT}, \
.outputs = {OUTPUT_DEFAULT}, \
.constructor = elementwiseOpConstructor};
DEFINE_ELEMENTWISE_SIGNATURE(FLOOR, V1_0, TestOperandType::TENSOR_FLOAT32);
DEFINE_ELEMENTWISE_SIGNATURE(RELU, V1_0, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_QUANT8_ASYMM);
DEFINE_ELEMENTWISE_SIGNATURE(RELU1, V1_0, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_QUANT8_ASYMM);
DEFINE_ELEMENTWISE_SIGNATURE(RELU6, V1_0, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_QUANT8_ASYMM);
DEFINE_ELEMENTWISE_SIGNATURE(TANH, V1_0, TestOperandType::TENSOR_FLOAT32);
DEFINE_ELEMENTWISE_SIGNATURE(FLOOR, V1_2, TestOperandType::TENSOR_FLOAT16);
DEFINE_ELEMENTWISE_SIGNATURE(LOGISTIC, V1_2, TestOperandType::TENSOR_FLOAT16);
DEFINE_ELEMENTWISE_SIGNATURE(RELU, V1_2, TestOperandType::TENSOR_FLOAT16);
DEFINE_ELEMENTWISE_SIGNATURE(RELU1, V1_2, TestOperandType::TENSOR_FLOAT16);
DEFINE_ELEMENTWISE_SIGNATURE(RELU6, V1_2, TestOperandType::TENSOR_FLOAT16);
DEFINE_ELEMENTWISE_SIGNATURE(RELU, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
DEFINE_ELEMENTWISE_SIGNATURE(RELU1, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
DEFINE_ELEMENTWISE_SIGNATURE(RELU6, V1_3, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
DEFINE_ELEMENTWISE_SIGNATURE(HARD_SWISH, V1_3, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_QUANT8_ASYMM);
#define DEFINE_ELEMENTWISE_SIGNATURE_WITH_RANK5(op, ver, ...) \
DEFINE_OPERATION_SIGNATURE(op##_##ver){.opType = TestOperationType::op, \
.supportedDataTypes = {__VA_ARGS__}, \
.supportedRanks = {1, 2, 3, 4, 5}, \
.version = TestHalVersion::ver, \
.inputs = {INPUT_DEFAULT}, \
.outputs = {OUTPUT_DEFAULT}, \
.constructor = elementwiseOpConstructor};
DEFINE_ELEMENTWISE_SIGNATURE_WITH_RANK5(ABS, V1_2, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_FLOAT16);
DEFINE_ELEMENTWISE_SIGNATURE_WITH_RANK5(EXP, V1_2, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_FLOAT16);
DEFINE_ELEMENTWISE_SIGNATURE_WITH_RANK5(NEG, V1_2, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_FLOAT16,
TestOperandType::TENSOR_INT32);
DEFINE_ELEMENTWISE_SIGNATURE_WITH_RANK5(SIN, V1_2, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_FLOAT16);
DEFINE_ELEMENTWISE_SIGNATURE_WITH_RANK5(LOGICAL_NOT, V1_2, TestOperandType::TENSOR_BOOL8);
DEFINE_ELEMENTWISE_SIGNATURE_WITH_RANK5(ABS, V1_3, TestOperandType::TENSOR_INT32);
DEFINE_ELEMENTWISE_SIGNATURE_WITH_RANK5(LOG, V1_2, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_FLOAT16);
DEFINE_ELEMENTWISE_SIGNATURE_WITH_RANK5(RSQRT, V1_2, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_FLOAT16);
DEFINE_ELEMENTWISE_SIGNATURE_WITH_RANK5(SQRT, V1_2, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_FLOAT16);
// Quantized operations with special output quantization parameters.
#define DEFINE_ELEMENTWISE_WITH_QUANT_OUTPUT_SIGNATURE(op, ver, s, z, ...) \
DEFINE_OPERATION_SIGNATURE(op##_##ver){.opType = TestOperationType::op, \
.supportedDataTypes = {__VA_ARGS__}, \
.supportedRanks = {1, 2, 3, 4}, \
.version = TestHalVersion::ver, \
.inputs = {INPUT_DEFAULT}, \
.outputs = {OUTPUT_QUANT((s), (z))}, \
.constructor = sameDimensionOpConstructor};
DEFINE_ELEMENTWISE_WITH_QUANT_OUTPUT_SIGNATURE(LOGISTIC, V1_0, /*scale=*/1.f / 256, /*zeroPoint=*/0,
TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_QUANT8_ASYMM);
DEFINE_ELEMENTWISE_WITH_QUANT_OUTPUT_SIGNATURE(TANH, V1_2, /*scale=*/1.f / 128, /*zeroPoint=*/128,
TestOperandType::TENSOR_FLOAT16,
TestOperandType::TENSOR_QUANT8_ASYMM);
DEFINE_ELEMENTWISE_WITH_QUANT_OUTPUT_SIGNATURE(LOGISTIC, V1_3, /*scale=*/1.f / 256,
/*zeroPoint=*/-128,
TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
DEFINE_ELEMENTWISE_WITH_QUANT_OUTPUT_SIGNATURE(TANH, V1_3, /*scale=*/1.f / 128, /*zeroPoint=*/0,
TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
static void castingOpConstructor(TestOperandType dataType, uint32_t rank, RandomOperation* op) {
sameDimensionOpConstructor(dataType, rank, op);
// If it is casting to/from a FP16 data type, the source/destination should have a scale
// representable in FP16 to avoid precision loss.
if (op->inputs[0]->dataType == TestOperandType::TENSOR_FLOAT16) {
op->outputs[0]->scale = static_cast<_Float16>(op->outputs[0]->scale);
} else if (op->outputs[0]->dataType == TestOperandType::TENSOR_FLOAT16) {
op->inputs[0]->scale = static_cast<_Float16>(op->inputs[0]->scale);
}
}
// Operations with output data type different from input.
#define DEFINE_QUANTIZATION_OP_SIGNATURE(op, ver, outType, ...) \
DEFINE_OPERATION_SIGNATURE(op##_##outType##_##ver){ \
.opType = TestOperationType::op, \
.supportedDataTypes = {__VA_ARGS__}, \
.supportedRanks = {1, 2, 3, 4}, \
.version = TestHalVersion::ver, \
.inputs = {INPUT_DEFAULT}, \
.outputs = {OUTPUT_TYPED(TestOperandType::outType)}, \
.constructor = castingOpConstructor};
DEFINE_QUANTIZATION_OP_SIGNATURE(DEQUANTIZE, V1_0, /*outType=*/TENSOR_FLOAT32,
TestOperandType::TENSOR_QUANT8_ASYMM);
DEFINE_QUANTIZATION_OP_SIGNATURE(DEQUANTIZE, V1_2, /*outType=*/TENSOR_FLOAT32,
TestOperandType::TENSOR_QUANT8_SYMM);
DEFINE_QUANTIZATION_OP_SIGNATURE(DEQUANTIZE, V1_2, /*outType=*/TENSOR_FLOAT16,
TestOperandType::TENSOR_QUANT8_ASYMM,
TestOperandType::TENSOR_QUANT8_SYMM);
DEFINE_QUANTIZATION_OP_SIGNATURE(DEQUANTIZE, V1_3, /*outType=*/TENSOR_FLOAT32,
TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
DEFINE_QUANTIZATION_OP_SIGNATURE(DEQUANTIZE, V1_3, /*outType=*/TENSOR_FLOAT16,
TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
DEFINE_QUANTIZATION_OP_SIGNATURE(QUANTIZE, V1_2, /*outType=*/TENSOR_QUANT8_ASYMM,
TestOperandType::TENSOR_FLOAT32, TestOperandType::TENSOR_FLOAT16);
DEFINE_QUANTIZATION_OP_SIGNATURE(QUANTIZE, V1_3,
/*outType=*/TENSOR_QUANT8_ASYMM_SIGNED,
TestOperandType::TENSOR_FLOAT32, TestOperandType::TENSOR_FLOAT16);
#define DEFINE_CAST_SIGNATURE(ver, outType, ...) \
DEFINE_OPERATION_SIGNATURE(CAST_##outType##_##ver){ \
.opType = TestOperationType::CAST, \
.supportedDataTypes = {__VA_ARGS__}, \
.supportedRanks = {1, 2, 3, 4, 5}, \
.version = TestHalVersion::ver, \
.inputs = {INPUT_DEFAULT}, \
.outputs = {OUTPUT_TYPED(TestOperandType::outType)}, \
.constructor = castingOpConstructor};
DEFINE_CAST_SIGNATURE(V1_2, /*outType=*/TENSOR_FLOAT32, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_QUANT8_ASYMM,
TestOperandType::TENSOR_INT32);
DEFINE_CAST_SIGNATURE(V1_2, /*outType=*/TENSOR_FLOAT16, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_QUANT8_ASYMM,
TestOperandType::TENSOR_INT32);
DEFINE_CAST_SIGNATURE(V1_2, /*outType=*/TENSOR_QUANT8_ASYMM, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_QUANT8_ASYMM,
TestOperandType::TENSOR_INT32);
DEFINE_CAST_SIGNATURE(V1_2, /*outType=*/TENSOR_INT32, TestOperandType::TENSOR_FLOAT32,
TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_QUANT8_ASYMM,
TestOperandType::TENSOR_INT32);
DEFINE_CAST_SIGNATURE(V1_3, /*outType=*/TENSOR_BOOL8, TestOperandType::TENSOR_BOOL8);
DEFINE_CAST_SIGNATURE(V1_3, /*outType=*/TENSOR_INT32, TestOperandType::TENSOR_INT32);
DEFINE_CAST_SIGNATURE(V1_3, /*outType=*/TENSOR_QUANT16_ASYMM,
TestOperandType::TENSOR_QUANT16_ASYMM);
DEFINE_CAST_SIGNATURE(V1_3, /*outType=*/TENSOR_QUANT16_SYMM, TestOperandType::TENSOR_QUANT16_SYMM);
DEFINE_CAST_SIGNATURE(V1_3, /*outType=*/TENSOR_QUANT8_ASYMM_SIGNED,
TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED);
DEFINE_CAST_SIGNATURE(V1_3, /*outType=*/TENSOR_QUANT8_SYMM, TestOperandType::TENSOR_QUANT8_SYMM);
DEFINE_OPERATION_SIGNATURE(ELU_V1_3){
.opType = TestOperationType::ELU,
.supportedDataTypes = {TestOperandType::TENSOR_FLOAT32, TestOperandType::TENSOR_FLOAT16},
.supportedRanks = {1, 2, 3, 4, 5},
.version = TestHalVersion::V1_3,
.inputs = {INPUT_DEFAULT, PARAMETER_FLOAT_RANGE(0.0f, 10.0f)},
.outputs = {OUTPUT_DEFAULT},
.constructor = sameDimensionOpConstructor};
} // namespace fuzzing_test
} // namespace nn
} // namespace android