blob: 6bb3a91ab2db63a06baa410997317070ee249d62 [file] [log] [blame]
/*
* Copyright (C) 2018 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 "NeuralNetworksWrapper.h"
#include "NeuralNetworksOEM.h"
#include <gtest/gtest.h>
using namespace android::nn::wrapper;
namespace {
static const int32_t kAvailableOperandCodes[] = {
ANEURALNETWORKS_FLOAT32,
ANEURALNETWORKS_INT32,
ANEURALNETWORKS_UINT32,
ANEURALNETWORKS_TENSOR_FLOAT32,
ANEURALNETWORKS_TENSOR_INT32,
ANEURALNETWORKS_TENSOR_QUANT8_ASYMM,
ANEURALNETWORKS_TENSOR_OEM_BYTE
};
class OperationTestBase {
public:
OperationTestBase(ANeuralNetworksOperationType opCode,
std::vector<ANeuralNetworksOperandType> validInputs,
std::vector<ANeuralNetworksOperandType> validOutputs)
: mOpCode(opCode),
mValidInputs(std::move(validInputs)),
mValidOutputs(std::move(validOutputs)) {}
// Add each operand separately and add the operation using these operands.
// This function does not cover the cases that a operand used mutiple times.
int32_t addOperation(const std::vector<ANeuralNetworksOperandType>& inputs,
const std::vector<ANeuralNetworksOperandType>& outputs) {
ANeuralNetworksModel* model = nullptr;
ANeuralNetworksModel_create(&model);
uint32_t opIdx = 0;
std::vector<uint32_t> inputIds;
std::vector<uint32_t> outputIds;
for (uint32_t i = 0; i < inputs.size(); i++) {
ANeuralNetworksModel_addOperand(model, &inputs[i]);
inputIds.push_back(opIdx++);
}
for (uint32_t i = 0; i < outputs.size(); i++) {
ANeuralNetworksModel_addOperand(model, &outputs[i]);
outputIds.push_back(opIdx++);
}
int32_t result = ANeuralNetworksModel_addOperation(model, mOpCode,
static_cast<uint32_t>(inputIds.size()),
inputIds.data(),
static_cast<uint32_t>(outputIds.size()),
outputIds.data());
ANeuralNetworksModel_free(model);
return result;
}
bool testMutatingInputOperandCode() {
for (uint32_t i = 0; i < mValidInputs.size(); i++) {
ANeuralNetworksOperandType newType = mValidInputs[i];
int32_t originalOperandCode = mValidInputs[i].type;
for (int32_t newOperandCode : kAvailableOperandCodes) {
if (newOperandCode == originalOperandCode) {
continue;
}
newType.type = newOperandCode;
std::vector<ANeuralNetworksOperandType> inputs = mValidInputs;
inputs[i] = newType;
int32_t result = addOperation(inputs, mValidOutputs);
if (ANEURALNETWORKS_NO_ERROR == result) {
return false;
}
}
}
return true;
}
bool testMutatingOutputOperandCode() {
for (uint32_t i = 0; i < mValidOutputs.size(); i++) {
ANeuralNetworksOperandType newType = mValidOutputs[i];
int32_t originalOperandCode = mValidOutputs[i].type;
for (int32_t newOperandCode : kAvailableOperandCodes) {
if (newOperandCode == originalOperandCode) {
continue;
}
newType.type = newOperandCode;
std::vector<ANeuralNetworksOperandType> outputs = mValidOutputs;
outputs[i] = newType;
int32_t result = addOperation(mValidInputs, outputs);
if (ANEURALNETWORKS_NO_ERROR == result) {
return false;
}
}
}
return true;
}
bool testMutatingInputOperandCounts() {
std::vector<ANeuralNetworksOperandType> inputs = mValidInputs;
for (uint32_t i = 0; i < 5; i++) {
inputs.push_back(inputs[0]);
if (ANEURALNETWORKS_NO_ERROR == addOperation(inputs, mValidOutputs)) {
return false;
}
}
return true;
}
bool testMutatingOutputOperandCounts() {
std::vector<ANeuralNetworksOperandType> outputs = mValidOutputs;
for (int i = 0; i < 5; i++) {
outputs.push_back(outputs[0]);
if (ANEURALNETWORKS_NO_ERROR == addOperation(mValidInputs, outputs)) {
return false;
}
}
return true;
}
private:
ANeuralNetworksOperationType mOpCode;
// The dimensions in the ANeuralNetworksOperandType must outlive the test object.
std::vector<ANeuralNetworksOperandType> mValidInputs;
std::vector<ANeuralNetworksOperandType> mValidOutputs;
};
TEST(OperationValidationTest, DEQUANTIZE_float32) {
uint32_t inputDimensions[4] = {2, 2, 2, 2};
ANeuralNetworksOperandType input = {.type = ANEURALNETWORKS_TENSOR_QUANT8_ASYMM,
.dimensionCount = 4,
.dimensions = inputDimensions,
.scale = 1.0f,
.zeroPoint = 0};
ANeuralNetworksOperandType output = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
.dimensionCount = 4,
.dimensions = inputDimensions,
.scale = 0.0f,
.zeroPoint = 0};
OperationTestBase dequantizeTest(ANEURALNETWORKS_DEQUANTIZE, {input}, {output});
EXPECT_TRUE(dequantizeTest.testMutatingInputOperandCode());
EXPECT_TRUE(dequantizeTest.testMutatingInputOperandCounts());
EXPECT_TRUE(dequantizeTest.testMutatingOutputOperandCode());
EXPECT_TRUE(dequantizeTest.testMutatingOutputOperandCounts());
}
void simpleMathOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
uint32_t inputDimensions[4] = {2, 2, 2, 2};
ANeuralNetworksOperandType input1 = {.type = operandCode,
.dimensionCount = 4,
.dimensions = inputDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
input1.scale = 0.5f;
}
ANeuralNetworksOperandType input2 = input1;
ANeuralNetworksOperandType output = input1;
ANeuralNetworksOperandType activation = {.type = ANEURALNETWORKS_INT32,
.dimensionCount = 0,
.dimensions = nullptr,
.scale = 0.0f,
.zeroPoint = 0};
OperationTestBase simpleMathTest(operationCode, {input1, input2, activation}, {output});
EXPECT_TRUE(simpleMathTest.testMutatingInputOperandCode());
EXPECT_TRUE(simpleMathTest.testMutatingInputOperandCounts());
EXPECT_TRUE(simpleMathTest.testMutatingOutputOperandCode());
EXPECT_TRUE(simpleMathTest.testMutatingOutputOperandCounts());
}
TEST(OperationValidationTest, ADD_float32) {
simpleMathOpTest(ANEURALNETWORKS_ADD, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, MUL_float32) {
simpleMathOpTest(ANEURALNETWORKS_MUL, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, SUB_float32) {
simpleMathOpTest(ANEURALNETWORKS_SUB, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, DIV_float32) {
simpleMathOpTest(ANEURALNETWORKS_DIV, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, ADD_quant8) {
simpleMathOpTest(ANEURALNETWORKS_ADD, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
TEST(OperationValidationTest, MUL_quant8) {
simpleMathOpTest(ANEURALNETWORKS_MUL, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
void activationOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
uint32_t inputDimensions[4] = {2, 2, 2, 2};
ANeuralNetworksOperandType input = {.type = operandCode,
.dimensionCount = 4,
.dimensions = inputDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
input.scale = 1.f / 256;
}
ANeuralNetworksOperandType output = input;
OperationTestBase activationTest(operationCode, {input}, {output});
EXPECT_TRUE(activationTest.testMutatingInputOperandCode());
EXPECT_TRUE(activationTest.testMutatingInputOperandCounts());
EXPECT_TRUE(activationTest.testMutatingOutputOperandCode());
EXPECT_TRUE(activationTest.testMutatingOutputOperandCounts());
}
TEST(OperationValidationTest, L2_NORMALIZATION_float32) {
activationOpTest(ANEURALNETWORKS_L2_NORMALIZATION, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, FLOOR_float32) {
activationOpTest(ANEURALNETWORKS_FLOOR, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, TANH_float32) {
activationOpTest(ANEURALNETWORKS_TANH, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, RELU_float32) {
activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, RELU1_float32) {
activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, RELU6_float32) {
activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, LOGISTIC_float32) {
activationOpTest(ANEURALNETWORKS_LOGISTIC, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, RELU_quant8) {
activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
TEST(OperationValidationTest, RELU1_quant8) {
activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
TEST(OperationValidationTest, RELU6_quant8) {
activationOpTest(ANEURALNETWORKS_RELU, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
TEST(OperationValidationTest, LOGISTIC_quant8) {
activationOpTest(ANEURALNETWORKS_LOGISTIC, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
void softmaxOpTest(int32_t operandCode) {
uint32_t inputDimensions[4] = {2, 2, 2, 2};
ANeuralNetworksOperandType input = {.type = operandCode,
.dimensionCount = 4,
.dimensions = inputDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
input.scale = 1.f / 256;
}
ANeuralNetworksOperandType output = input;
ANeuralNetworksOperandType beta = {.type = ANEURALNETWORKS_FLOAT32,
.dimensionCount = 0,
.dimensions = nullptr,
.scale = 0.0f,
.zeroPoint = 0};
OperationTestBase softmaxTest(ANEURALNETWORKS_SOFTMAX, {input, beta}, {output});
EXPECT_TRUE(softmaxTest.testMutatingInputOperandCode());
EXPECT_TRUE(softmaxTest.testMutatingInputOperandCounts());
EXPECT_TRUE(softmaxTest.testMutatingOutputOperandCode());
EXPECT_TRUE(softmaxTest.testMutatingOutputOperandCounts());
}
TEST(OperationValidationTest, SOFTMAX_float32) {
softmaxOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, SOFTMAX_quant8) {
softmaxOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
void poolingOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
uint32_t inputDimensions[4] = {2, 4, 4, 2};
ANeuralNetworksOperandType input = {.type = operandCode,
.dimensionCount = 4,
.dimensions = inputDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
input.scale = 1.f / 256;
}
ANeuralNetworksOperandType output = input;
ANeuralNetworksOperandType scalar = {.type = ANEURALNETWORKS_INT32,
.dimensionCount = 0,
.dimensions = nullptr,
.scale = 0.0f,
.zeroPoint = 0};
ANeuralNetworksOperandType padLeft = scalar;
ANeuralNetworksOperandType padRight = scalar;
ANeuralNetworksOperandType padTop = scalar;
ANeuralNetworksOperandType padBottom = scalar;
ANeuralNetworksOperandType strideWidth = scalar;
ANeuralNetworksOperandType strideHeight = scalar;
ANeuralNetworksOperandType filterWidth = scalar;
ANeuralNetworksOperandType filterHeight = scalar;
ANeuralNetworksOperandType activation = scalar;
OperationTestBase explicitPoolingTest(operationCode,
{input,
padLeft, padRight, padTop, padBottom,
strideWidth, strideHeight,
filterWidth, filterHeight,
activation},
{output});
EXPECT_TRUE(explicitPoolingTest.testMutatingInputOperandCode());
EXPECT_TRUE(explicitPoolingTest.testMutatingInputOperandCounts());
EXPECT_TRUE(explicitPoolingTest.testMutatingOutputOperandCode());
EXPECT_TRUE(explicitPoolingTest.testMutatingOutputOperandCounts());
ANeuralNetworksOperandType padImplicit = scalar;
OperationTestBase implicitPoolingTest(operationCode,
{input,
padImplicit,
strideWidth, strideHeight,
filterWidth, filterHeight,
activation},
{output});
EXPECT_TRUE(implicitPoolingTest.testMutatingInputOperandCode());
EXPECT_TRUE(implicitPoolingTest.testMutatingInputOperandCounts());
EXPECT_TRUE(implicitPoolingTest.testMutatingOutputOperandCode());
EXPECT_TRUE(implicitPoolingTest.testMutatingOutputOperandCounts());
}
TEST(OperationValidationTest, AVERAGE_POOL_2D_float32) {
poolingOpTest(ANEURALNETWORKS_AVERAGE_POOL_2D, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, MAX_POOL_2D_float32) {
poolingOpTest(ANEURALNETWORKS_MAX_POOL_2D, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, L2_POOL_2D_float32) {
poolingOpTest(ANEURALNETWORKS_L2_POOL_2D, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, AVERAGE_POOL_2D_quant8) {
poolingOpTest(ANEURALNETWORKS_AVERAGE_POOL_2D, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
TEST(OperationValidationTest, MAX_POOL_2D_quant8) {
poolingOpTest(ANEURALNETWORKS_MAX_POOL_2D, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
void spaceDepthOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
uint32_t inputDimensions[4] = {2, 2, 2, 2};
ANeuralNetworksOperandType input = {.type = operandCode,
.dimensionCount = 4,
.dimensions = inputDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
input.scale = 1.f / 256;
}
ANeuralNetworksOperandType block_size = {.type = ANEURALNETWORKS_INT32,
.dimensionCount = 0,
.dimensions = nullptr,
.scale = 0.0f,
.zeroPoint = 0};
ANeuralNetworksOperandType output = input;
OperationTestBase spaceDepthTest(operationCode, {input, block_size}, {output});
EXPECT_TRUE(spaceDepthTest.testMutatingInputOperandCode());
EXPECT_TRUE(spaceDepthTest.testMutatingInputOperandCounts());
EXPECT_TRUE(spaceDepthTest.testMutatingOutputOperandCode());
EXPECT_TRUE(spaceDepthTest.testMutatingOutputOperandCounts());
}
TEST(OperationValidationTest, SPACE_TO_DEPTH_float32) {
spaceDepthOpTest(ANEURALNETWORKS_SPACE_TO_DEPTH, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, DEPTH_TO_SPACE_float32) {
spaceDepthOpTest(ANEURALNETWORKS_DEPTH_TO_SPACE, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, SPACE_TO_DEPTH_quant8) {
spaceDepthOpTest(ANEURALNETWORKS_SPACE_TO_DEPTH, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
TEST(OperationValidationTest, DEPTH_TO_SPACE_quant8) {
spaceDepthOpTest(ANEURALNETWORKS_DEPTH_TO_SPACE, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
void spaceBatchOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
uint32_t inputDimensions[4] = {2, 2, 2, 2};
ANeuralNetworksOperandType input = {.type = operandCode,
.dimensionCount = 4,
.dimensions = inputDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
input.scale = 1.f / 256;
}
uint32_t blockDimensions[1] = {2};
ANeuralNetworksOperandType blockShape = {.type = ANEURALNETWORKS_TENSOR_INT32,
.dimensionCount = 1,
.dimensions = blockDimensions,
.scale = 0.0f,
.zeroPoint = 0};
ANeuralNetworksOperandType padding = blockShape;
ANeuralNetworksOperandType output = input;
if (operationCode == ANEURALNETWORKS_SPACE_TO_BATCH_ND) {
OperationTestBase spaceBatchTest(operationCode, {input, blockShape, padding}, {output});
EXPECT_TRUE(spaceBatchTest.testMutatingInputOperandCode());
EXPECT_TRUE(spaceBatchTest.testMutatingInputOperandCounts());
EXPECT_TRUE(spaceBatchTest.testMutatingOutputOperandCode());
EXPECT_TRUE(spaceBatchTest.testMutatingOutputOperandCounts());
} else {
OperationTestBase spaceBatchTest(operationCode, {input, blockShape}, {output});
EXPECT_TRUE(spaceBatchTest.testMutatingInputOperandCode());
EXPECT_TRUE(spaceBatchTest.testMutatingInputOperandCounts());
EXPECT_TRUE(spaceBatchTest.testMutatingOutputOperandCode());
EXPECT_TRUE(spaceBatchTest.testMutatingOutputOperandCounts());
}
}
TEST(OperationValidationTest, SPACE_TO_BATCH_ND_float32) {
spaceBatchOpTest(ANEURALNETWORKS_SPACE_TO_BATCH_ND, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, BATCH_TO_SPACE_ND_float32) {
spaceBatchOpTest(ANEURALNETWORKS_BATCH_TO_SPACE_ND, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, SPACE_TO_BATCH_ND_quant8) {
spaceBatchOpTest(ANEURALNETWORKS_SPACE_TO_BATCH_ND, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
TEST(OperationValidationTest, BATCH_TO_SPACE_ND_quant8) {
spaceBatchOpTest(ANEURALNETWORKS_BATCH_TO_SPACE_ND, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
void transposeAndSqueezeOpTest(ANeuralNetworksOperationType operationCode, int32_t operandCode) {
uint32_t inputDimensions[4] = {2, 2, 2, 2};
ANeuralNetworksOperandType input = {.type = operandCode,
.dimensionCount = 4,
.dimensions = inputDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
input.scale = 1.f / 256;
}
uint32_t blockDimensions[1] = {4};
ANeuralNetworksOperandType dims = {.type = ANEURALNETWORKS_TENSOR_INT32,
.dimensionCount = 1,
.dimensions = blockDimensions,
.scale = 0.0f,
.zeroPoint = 0};
ANeuralNetworksOperandType output = input;
OperationTestBase transposeAndSqueezeTest(operationCode, {input, dims}, {output});
EXPECT_TRUE(transposeAndSqueezeTest.testMutatingInputOperandCode());
EXPECT_TRUE(transposeAndSqueezeTest.testMutatingInputOperandCounts());
EXPECT_TRUE(transposeAndSqueezeTest.testMutatingOutputOperandCode());
EXPECT_TRUE(transposeAndSqueezeTest.testMutatingOutputOperandCounts());
}
TEST(OperationValidationTest, TRANSPOSE_float32) {
transposeAndSqueezeOpTest(ANEURALNETWORKS_TRANSPOSE, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, SQUEEZE_float32) {
transposeAndSqueezeOpTest(ANEURALNETWORKS_SQUEEZE, ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, TRANSPOSE_quant8) {
transposeAndSqueezeOpTest(ANEURALNETWORKS_TRANSPOSE, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
TEST(OperationValidationTest, SQUEEZE_quant8) {
transposeAndSqueezeOpTest(ANEURALNETWORKS_SQUEEZE, ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
void convOpTest(int32_t operandCode) {
uint32_t inputDimensions[4] = {2, 4, 4, 2};
ANeuralNetworksOperandType input = {.type = operandCode,
.dimensionCount = 4,
.dimensions = inputDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
input.scale = 0.5f;
}
ANeuralNetworksOperandType filter = input;
ANeuralNetworksOperandType output = input;
uint32_t biasDimensions[1] = {2};
ANeuralNetworksOperandType bias = {.type = operandCode,
.dimensionCount = 1,
.dimensions = biasDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
bias.type = ANEURALNETWORKS_TENSOR_INT32;
bias.scale = 0.25f;
}
ANeuralNetworksOperandType scalar = {.type = ANEURALNETWORKS_INT32,
.dimensionCount = 0,
.dimensions = nullptr,
.scale = 0.0f,
.zeroPoint = 0};
ANeuralNetworksOperandType padLeft = scalar;
ANeuralNetworksOperandType padRight = scalar;
ANeuralNetworksOperandType padTop = scalar;
ANeuralNetworksOperandType padBottom = scalar;
ANeuralNetworksOperandType strideWidth = scalar;
ANeuralNetworksOperandType strideHeight = scalar;
ANeuralNetworksOperandType activation = scalar;
OperationTestBase explicitConvTest(ANEURALNETWORKS_CONV_2D,
{input, filter, bias,
padLeft, padRight, padTop, padBottom,
strideWidth, strideHeight,
activation},
{output});
EXPECT_TRUE(explicitConvTest.testMutatingInputOperandCode());
EXPECT_TRUE(explicitConvTest.testMutatingInputOperandCounts());
EXPECT_TRUE(explicitConvTest.testMutatingOutputOperandCode());
EXPECT_TRUE(explicitConvTest.testMutatingOutputOperandCounts());
ANeuralNetworksOperandType padImplicit = scalar;
OperationTestBase implicitConvTest(ANEURALNETWORKS_CONV_2D,
{input, filter, bias,
padImplicit,
strideWidth, strideHeight,
activation},
{output});
EXPECT_TRUE(implicitConvTest.testMutatingInputOperandCode());
EXPECT_TRUE(implicitConvTest.testMutatingInputOperandCounts());
EXPECT_TRUE(implicitConvTest.testMutatingOutputOperandCode());
EXPECT_TRUE(implicitConvTest.testMutatingOutputOperandCounts());
}
TEST(OperationValidationTest, CONV_2D_float32) {
convOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, CONV_2D_quant8) {
convOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
void depthwiseConvOpTest(int32_t operandCode) {
uint32_t inputDimensions[4] = {1, 2, 2, 2};
ANeuralNetworksOperandType input = {.type = operandCode,
.dimensionCount = 4,
.dimensions = inputDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
input.scale = 0.5f;
}
ANeuralNetworksOperandType filter = input;
ANeuralNetworksOperandType output = input;
uint32_t biasDimensions[1] = {2};
ANeuralNetworksOperandType bias = {.type = operandCode,
.dimensionCount = 1,
.dimensions = biasDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
bias.type = ANEURALNETWORKS_TENSOR_INT32;
bias.scale = 0.25f;
}
ANeuralNetworksOperandType scalar = {.type = ANEURALNETWORKS_INT32,
.dimensionCount = 0,
.dimensions = nullptr,
.scale = 0.0f,
.zeroPoint = 0};
ANeuralNetworksOperandType padLeft = scalar;
ANeuralNetworksOperandType padRight = scalar;
ANeuralNetworksOperandType padTop = scalar;
ANeuralNetworksOperandType padBottom = scalar;
ANeuralNetworksOperandType strideWidth = scalar;
ANeuralNetworksOperandType strideHeight = scalar;
ANeuralNetworksOperandType multiplier = scalar;
ANeuralNetworksOperandType activation = scalar;
OperationTestBase explicitDepthwiseConvTest(ANEURALNETWORKS_DEPTHWISE_CONV_2D,
{input, filter, bias,
padLeft, padRight, padTop, padBottom,
strideWidth, strideHeight,
multiplier, activation},
{output});
EXPECT_TRUE(explicitDepthwiseConvTest.testMutatingInputOperandCode());
EXPECT_TRUE(explicitDepthwiseConvTest.testMutatingInputOperandCounts());
EXPECT_TRUE(explicitDepthwiseConvTest.testMutatingOutputOperandCode());
EXPECT_TRUE(explicitDepthwiseConvTest.testMutatingOutputOperandCounts());
ANeuralNetworksOperandType padImplicit = scalar;
OperationTestBase implicitDepthwiseConvTest(ANEURALNETWORKS_DEPTHWISE_CONV_2D,
{input, filter, bias,
padImplicit,
strideWidth, strideHeight,
multiplier, activation},
{output});
EXPECT_TRUE(implicitDepthwiseConvTest.testMutatingInputOperandCode());
EXPECT_TRUE(implicitDepthwiseConvTest.testMutatingInputOperandCounts());
EXPECT_TRUE(implicitDepthwiseConvTest.testMutatingOutputOperandCode());
EXPECT_TRUE(implicitDepthwiseConvTest.testMutatingOutputOperandCounts());
}
TEST(OperationValidationTest, DEPTHWISE_CONV_2D_float32) {
depthwiseConvOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, DEPTHWISE_CONV_2D_quant8) {
depthwiseConvOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
void fullyConnectedOpTest(int32_t operandCode) {
uint32_t inputDimensions[2] = {5, 5};
ANeuralNetworksOperandType input = {.type = operandCode,
.dimensionCount = 2,
.dimensions = inputDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
input.scale = 0.5f;
}
ANeuralNetworksOperandType weights = input;
ANeuralNetworksOperandType output = input;
uint32_t biasDimensions[1] = {5};
ANeuralNetworksOperandType bias = {.type = operandCode,
.dimensionCount = 1,
.dimensions = biasDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
bias.type = ANEURALNETWORKS_TENSOR_INT32;
bias.scale = 0.25f;
}
ANeuralNetworksOperandType activation = {.type = ANEURALNETWORKS_INT32,
.dimensionCount = 0,
.dimensions = nullptr,
.scale = 0.0f,
.zeroPoint = 0};
OperationTestBase fullyConnectedTest(ANEURALNETWORKS_FULLY_CONNECTED,
{input, weights, bias, activation},
{output});
EXPECT_TRUE(fullyConnectedTest.testMutatingInputOperandCode());
EXPECT_TRUE(fullyConnectedTest.testMutatingInputOperandCounts());
EXPECT_TRUE(fullyConnectedTest.testMutatingOutputOperandCode());
EXPECT_TRUE(fullyConnectedTest.testMutatingOutputOperandCounts());
}
TEST(OperationValidationTest, FULLY_CONNECTED_float32) {
fullyConnectedOpTest(ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, FULLY_CONNECTED_quant8) {
fullyConnectedOpTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
void concatenationTest(int32_t operandCode) {
uint32_t inputDimensions[2] = {5, 5};
ANeuralNetworksOperandType input1 = {.type = operandCode,
.dimensionCount = 2,
.dimensions = inputDimensions,
.scale = 0.0f,
.zeroPoint = 0};
if (operandCode == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
input1.scale = 0.5f;
}
ANeuralNetworksOperandType input2 = input1;
ANeuralNetworksOperandType output = input1;
ANeuralNetworksOperandType activation = {.type = ANEURALNETWORKS_INT32,
.dimensionCount = 0,
.dimensions = nullptr,
.scale = 0.0f,
.zeroPoint = 0};
OperationTestBase concat2Test(ANEURALNETWORKS_CONCATENATION,
{input1, input2, activation}, {output});
EXPECT_TRUE(concat2Test.testMutatingInputOperandCode());
EXPECT_TRUE(concat2Test.testMutatingOutputOperandCode());
EXPECT_TRUE(concat2Test.testMutatingOutputOperandCounts());
OperationTestBase concat1Test(ANEURALNETWORKS_CONCATENATION,
{input1, activation}, {output});
EXPECT_TRUE(concat1Test.testMutatingInputOperandCode());
EXPECT_TRUE(concat1Test.testMutatingOutputOperandCode());
EXPECT_TRUE(concat1Test.testMutatingOutputOperandCounts());
}
TEST(OperationValidationTest, CONCATENATION_float32) {
concatenationTest(ANEURALNETWORKS_TENSOR_FLOAT32);
}
TEST(OperationValidationTest, CONCATENATION_quant8) {
concatenationTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
}
TEST(OperationValidationTest, RESIZE_BILINEAR_float32) {
uint32_t inputDimensions[4] = {2, 2, 2, 2};
ANeuralNetworksOperandType input = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
.dimensionCount = 4,
.dimensions = inputDimensions,
.scale = 0.0f,
.zeroPoint = 0};
ANeuralNetworksOperandType height = {.type = ANEURALNETWORKS_INT32,
.dimensionCount = 0,
.dimensions = nullptr,
.scale = 0.0f,
.zeroPoint = 0};
ANeuralNetworksOperandType width = height;
ANeuralNetworksOperandType output = input;
OperationTestBase resizeTest(ANEURALNETWORKS_RESIZE_BILINEAR,
{input, height, width}, {output});
EXPECT_TRUE(resizeTest.testMutatingInputOperandCode());
EXPECT_TRUE(resizeTest.testMutatingInputOperandCounts());
EXPECT_TRUE(resizeTest.testMutatingOutputOperandCode());
EXPECT_TRUE(resizeTest.testMutatingOutputOperandCounts());
}
} // end namespace