1/* 2 * Copyright (C) 2017 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 19//#include <android-base/logging.h> 20#include <gtest/gtest.h> 21 22using namespace android::nn::wrapper; 23 24namespace { 25 26typedef float Matrix3x4[3][4]; 27typedef float Matrix4[4]; 28 29class TrivialTest : public ::testing::Test { 30protected: 31 virtual void SetUp() {} 32 33 const Matrix3x4 matrix1 = {{1.f, 2.f, 3.f, 4.f}, {5.f, 6.f, 7.f, 8.f}, {9.f, 10.f, 11.f, 12.f}}; 34 const Matrix3x4 matrix2 = {{100.f, 200.f, 300.f, 400.f}, 35 {500.f, 600.f, 700.f, 800.f}, 36 {900.f, 1000.f, 1100.f, 1200.f}}; 37 const Matrix4 matrix2b = {100.f, 200.f, 300.f, 400.f}; 38 const Matrix3x4 matrix3 = {{20.f, 30.f, 40.f, 50.f}, 39 {21.f, 22.f, 23.f, 24.f}, 40 {31.f, 32.f, 33.f, 34.f}}; 41 const Matrix3x4 expected2 = {{101.f, 202.f, 303.f, 404.f}, 42 {505.f, 606.f, 707.f, 808.f}, 43 {909.f, 1010.f, 1111.f, 1212.f}}; 44 const Matrix3x4 expected2b = {{101.f, 202.f, 303.f, 404.f}, 45 {105.f, 206.f, 307.f, 408.f}, 46 {109.f, 210.f, 311.f, 412.f}}; 47 const Matrix3x4 expected2c = {{100.f, 400.f, 900.f, 1600.f}, 48 {500.f, 1200.f, 2100.f, 3200.f}, 49 {900.f, 2000.f, 3300.f, 4800.f}}; 50 51 const Matrix3x4 expected3 = {{121.f, 232.f, 343.f, 454.f}, 52 {526.f, 628.f, 730.f, 832.f}, 53 {940.f, 1042.f, 1144.f, 1246.f}}; 54 const Matrix3x4 expected3b = {{22.f, 34.f, 46.f, 58.f}, 55 {31.f, 34.f, 37.f, 40.f}, 56 {49.f, 52.f, 55.f, 58.f}}; 57}; 58 59// Create a model that can add two tensors using a one node graph. 60void CreateAddTwoTensorModel(Model* model) { 61 OperandType matrixType(Type::TENSOR_FLOAT32, {3, 4}); 62 OperandType scalarType(Type::INT32, {}); 63 int32_t activation(ANEURALNETWORKS_FUSED_NONE); 64 auto a = model->addOperand(&matrixType); 65 auto b = model->addOperand(&matrixType); 66 auto c = model->addOperand(&matrixType); 67 auto d = model->addOperand(&scalarType); 68 model->setOperandValue(d, &activation, sizeof(activation)); 69 model->addOperation(ANEURALNETWORKS_ADD, {a, b, d}, {c}); 70 model->identifyInputsAndOutputs({a, b}, {c}); 71 ASSERT_TRUE(model->isValid()); 72 model->finish(); 73} 74 75// Create a model that can add three tensors using a two node graph, 76// with one tensor set as part of the model. 77void CreateAddThreeTensorModel(Model* model, const Matrix3x4 bias) { 78 OperandType matrixType(Type::TENSOR_FLOAT32, {3, 4}); 79 OperandType scalarType(Type::INT32, {}); 80 int32_t activation(ANEURALNETWORKS_FUSED_NONE); 81 auto a = model->addOperand(&matrixType); 82 auto b = model->addOperand(&matrixType); 83 auto c = model->addOperand(&matrixType); 84 auto d = model->addOperand(&matrixType); 85 auto e = model->addOperand(&matrixType); 86 auto f = model->addOperand(&scalarType); 87 model->setOperandValue(e, bias, sizeof(Matrix3x4)); 88 model->setOperandValue(f, &activation, sizeof(activation)); 89 model->addOperation(ANEURALNETWORKS_ADD, {a, c, f}, {b}); 90 model->addOperation(ANEURALNETWORKS_ADD, {b, e, f}, {d}); 91 model->identifyInputsAndOutputs({c, a}, {d}); 92 ASSERT_TRUE(model->isValid()); 93 model->finish(); 94} 95 96// Check that the values are the same. This works only if dealing with integer 97// value, otherwise we should accept values that are similar if not exact. 98int CompareMatrices(const Matrix3x4& expected, const Matrix3x4& actual) { 99 int errors = 0; 100 for (int i = 0; i < 3; i++) { 101 for (int j = 0; j < 4; j++) { 102 if (expected[i][j] != actual[i][j]) { 103 printf("expected[%d][%d] != actual[%d][%d], %f != %f\n", i, j, i, j, 104 static_cast<double>(expected[i][j]), static_cast<double>(actual[i][j])); 105 errors++; 106 } 107 } 108 } 109 return errors; 110} 111 112TEST_F(TrivialTest, AddTwo) { 113 Model modelAdd2; 114 CreateAddTwoTensorModel(&modelAdd2); 115 116 // Test the one node model. 117 Matrix3x4 actual; 118 memset(&actual, 0, sizeof(actual)); 119 Compilation compilation(&modelAdd2); 120 compilation.finish(); 121 Execution execution(&compilation); 122 ASSERT_EQ(execution.setInput(0, matrix1, sizeof(Matrix3x4)), Result::NO_ERROR); 123 ASSERT_EQ(execution.setInput(1, matrix2, sizeof(Matrix3x4)), Result::NO_ERROR); 124 ASSERT_EQ(execution.setOutput(0, actual, sizeof(Matrix3x4)), Result::NO_ERROR); 125 ASSERT_EQ(execution.compute(), Result::NO_ERROR); 126 ASSERT_EQ(CompareMatrices(expected2, actual), 0); 127} 128 129TEST_F(TrivialTest, AddThree) { 130 Model modelAdd3; 131 CreateAddThreeTensorModel(&modelAdd3, matrix3); 132 133 // Test the three node model. 134 Matrix3x4 actual; 135 memset(&actual, 0, sizeof(actual)); 136 Compilation compilation2(&modelAdd3); 137 compilation2.finish(); 138 Execution execution2(&compilation2); 139 ASSERT_EQ(execution2.setInput(0, matrix1, sizeof(Matrix3x4)), Result::NO_ERROR); 140 ASSERT_EQ(execution2.setInput(1, matrix2, sizeof(Matrix3x4)), Result::NO_ERROR); 141 ASSERT_EQ(execution2.setOutput(0, actual, sizeof(Matrix3x4)), Result::NO_ERROR); 142 ASSERT_EQ(execution2.compute(), Result::NO_ERROR); 143 ASSERT_EQ(CompareMatrices(expected3, actual), 0); 144 145 // Test it a second time to make sure the model is reusable. 146 memset(&actual, 0, sizeof(actual)); 147 Compilation compilation3(&modelAdd3); 148 compilation3.finish(); 149 Execution execution3(&compilation3); 150 ASSERT_EQ(execution3.setInput(0, matrix1, sizeof(Matrix3x4)), Result::NO_ERROR); 151 ASSERT_EQ(execution3.setInput(1, matrix1, sizeof(Matrix3x4)), Result::NO_ERROR); 152 ASSERT_EQ(execution3.setOutput(0, actual, sizeof(Matrix3x4)), Result::NO_ERROR); 153 ASSERT_EQ(execution3.compute(), Result::NO_ERROR); 154 ASSERT_EQ(CompareMatrices(expected3b, actual), 0); 155} 156 157TEST_F(TrivialTest, BroadcastAddTwo) { 158 Model modelBroadcastAdd2; 159 // activation: NONE. 160 int32_t activation_init[] = {ANEURALNETWORKS_FUSED_NONE}; 161 OperandType scalarType(Type::INT32, {1}); 162 auto activation = modelBroadcastAdd2.addOperand(&scalarType); 163 modelBroadcastAdd2.setOperandValue(activation, activation_init, sizeof(int32_t) * 1); 164 165 OperandType matrixType(Type::TENSOR_FLOAT32, {1, 1, 3, 4}); 166 OperandType matrixType2(Type::TENSOR_FLOAT32, {4}); 167 168 auto a = modelBroadcastAdd2.addOperand(&matrixType); 169 auto b = modelBroadcastAdd2.addOperand(&matrixType2); 170 auto c = modelBroadcastAdd2.addOperand(&matrixType); 171 modelBroadcastAdd2.addOperation(ANEURALNETWORKS_ADD, {a, b, activation}, {c}); 172 modelBroadcastAdd2.identifyInputsAndOutputs({a, b}, {c}); 173 ASSERT_TRUE(modelBroadcastAdd2.isValid()); 174 modelBroadcastAdd2.finish(); 175 176 // Test the one node model. 177 Matrix3x4 actual; 178 memset(&actual, 0, sizeof(actual)); 179 Compilation compilation(&modelBroadcastAdd2); 180 compilation.finish(); 181 Execution execution(&compilation); 182 ASSERT_EQ(execution.setInput(0, matrix1, sizeof(Matrix3x4)), Result::NO_ERROR); 183 ASSERT_EQ(execution.setInput(1, matrix2b, sizeof(Matrix4)), Result::NO_ERROR); 184 ASSERT_EQ(execution.setOutput(0, actual, sizeof(Matrix3x4)), Result::NO_ERROR); 185 ASSERT_EQ(execution.compute(), Result::NO_ERROR); 186 ASSERT_EQ(CompareMatrices(expected2b, actual), 0); 187} 188 189TEST_F(TrivialTest, BroadcastMulTwo) { 190 Model modelBroadcastMul2; 191 // activation: NONE. 192 int32_t activation_init[] = {ANEURALNETWORKS_FUSED_NONE}; 193 OperandType scalarType(Type::INT32, {1}); 194 auto activation = modelBroadcastMul2.addOperand(&scalarType); 195 modelBroadcastMul2.setOperandValue(activation, activation_init, sizeof(int32_t) * 1); 196 197 OperandType matrixType(Type::TENSOR_FLOAT32, {1, 1, 3, 4}); 198 OperandType matrixType2(Type::TENSOR_FLOAT32, {4}); 199 200 auto a = modelBroadcastMul2.addOperand(&matrixType); 201 auto b = modelBroadcastMul2.addOperand(&matrixType2); 202 auto c = modelBroadcastMul2.addOperand(&matrixType); 203 modelBroadcastMul2.addOperation(ANEURALNETWORKS_MUL, {a, b, activation}, {c}); 204 modelBroadcastMul2.identifyInputsAndOutputs({a, b}, {c}); 205 ASSERT_TRUE(modelBroadcastMul2.isValid()); 206 modelBroadcastMul2.finish(); 207 208 // Test the one node model. 209 Matrix3x4 actual; 210 memset(&actual, 0, sizeof(actual)); 211 Compilation compilation(&modelBroadcastMul2); 212 compilation.finish(); 213 Execution execution(&compilation); 214 ASSERT_EQ(execution.setInput(0, matrix1, sizeof(Matrix3x4)), Result::NO_ERROR); 215 ASSERT_EQ(execution.setInput(1, matrix2b, sizeof(Matrix4)), Result::NO_ERROR); 216 ASSERT_EQ(execution.setOutput(0, actual, sizeof(Matrix3x4)), Result::NO_ERROR); 217 ASSERT_EQ(execution.compute(), Result::NO_ERROR); 218 ASSERT_EQ(CompareMatrices(expected2c, actual), 0); 219} 220 221} // end namespace 222