/* * Copyright 2017 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 "gmock/gmock-matchers.h" #include "gtest/gtest.h" #include "tensor_utils.h" namespace android { namespace nn { namespace tensor_utils { namespace { using ::testing::FloatNear; using ::testing::Matcher; std::vector> ArrayFloatNear(const std::vector& values, float max_abs_error=1.e-6) { std::vector> matchers; matchers.reserve(values.size()); for (const float& v : values) { matchers.emplace_back(FloatNear(v, max_abs_error)); } return matchers; } } // anonymous namespace TEST(uKernels, ClipTest) { constexpr int kVectorSize = 10; constexpr float kAbsLimit = 2.0; static float input[kVectorSize] = {0.0, -0.5, 1.0, -1.5, 2.0, -2.5, 3.0, -3.5, 4.0, -4.5}; std::vector output(kVectorSize); ClipVector(input, kVectorSize, kAbsLimit, output.data()); EXPECT_THAT(output, ElementsAreArray(ArrayFloatNear( {0.0, -0.5, 1.0, -1.5, 2.0, -2.0, 2.0, -2.0, 2.0, -2.0}))); } TEST(uKernels, MatrixBatchVectorMultiplyAccumulateTest) { constexpr int kRow = 3; constexpr int kCol = 4; constexpr int kBatch = 2; static float matrix[kRow * kCol] = {1.0, 2.0, 3.0, 4.0, // -1.0, -2.0, -3.0, -4.0, // 1.0, -2.0, 3.0, -4.0}; static float vector[kCol * kBatch] = {1.0, -1.0, 1.0, -1.0, // 2.0, -2.0, 2.0, -2.0}; std::vector output(kRow * kBatch); std::fill(output.begin(), output.end(), 3.0); MatrixBatchVectorMultiplyAccumulate(matrix, kRow, kCol, vector, kBatch, output.data(), /*result_stride=*/1); EXPECT_THAT(output, ElementsAreArray(ArrayFloatNear({1., 5., 13., // -1., 7., 23.}))); } TEST(uKernels, VectorVectorCwiseProductTest) { constexpr int kVectorSize = 10; static float input1[kVectorSize] = {0.0, -0.5, 1.0, -1.5, 2.0, -2.5, 3.0, -3.5, 4.0, -4.5}; static float input2[kVectorSize] = {0.1, -0.1, 0.1, -0.1, 0.1, -0.1, 0.1, -0.1, 0.1, -0.1}; std::vector output(kVectorSize); VectorVectorCwiseProduct(input1, input2, kVectorSize, output.data()); EXPECT_THAT(output, ElementsAreArray(ArrayFloatNear( {0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45}))); } TEST(uKernels, VectorVectorCwiseProductAccumulateTest) { constexpr int kVectorSize = 10; static float input1[kVectorSize] = {0.0, -0.5, 1.0, -1.5, 2.0, -2.5, 3.0, -3.5, 4.0, -4.5}; static float input2[kVectorSize] = {0.1, -0.1, 0.1, -0.1, 0.1, -0.1, 0.1, -0.1, 0.1, -0.1}; std::vector output(kVectorSize); std::fill(output.begin(), output.end(), 1.0); VectorVectorCwiseProductAccumulate(input1, input2, kVectorSize, output.data()); EXPECT_THAT(output, ElementsAreArray(ArrayFloatNear( {1.0, 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45}))); } TEST(uKernels, VectorBatchVectorAssignTest) { constexpr int kVectorSize = 5; constexpr int kBatchSize = 3; static float input[kVectorSize] = {0.0, -0.5, 1.0, -1.5, 2.0}; std::vector output(kVectorSize * kBatchSize); VectorBatchVectorAssign(input, kVectorSize, kBatchSize, output.data()); EXPECT_THAT(output, ElementsAreArray(ArrayFloatNear( {0.0, -0.5, 1.0, -1.5, 2.0, 0.0, -0.5, 1.0, -1.5, 2.0, 0.0, -0.5, 1.0, -1.5, 2.0}))); } TEST(uKernels, ApplySigmoidToVectorTest) { constexpr int kVectorSize = 5; static float input[kVectorSize] = {0.0, -0.5, 1.0, -1.5, 2.0}; std::vector output(kVectorSize); ApplySigmoidToVector(input, kVectorSize, output.data()); EXPECT_THAT(output, ElementsAreArray(ArrayFloatNear( {0.5, 0.377541, 0.731059, 0.182426, 0.880797}))); } TEST(uKernels, ApplyActivationToVectorTest) { constexpr int kVectorSize = 5; static float input[kVectorSize] = {0.0, -0.5, 1.0, -1.5, 2.0}; std::vector output(kVectorSize); ApplyActivationToVector(input, kVectorSize, kActivationRelu, output.data()); EXPECT_THAT(output, ElementsAreArray(ArrayFloatNear({0.0, 0.0, 1.0, 0.0, 2.0}))); ApplyActivationToVector(input, kVectorSize, kActivationTanh, output.data()); EXPECT_THAT(output, ElementsAreArray(ArrayFloatNear( {0.0, -0.462117, 0.761594, -0.905148, 0.964028}))); } TEST(uKernels, CopyVectorTest) { constexpr int kVectorSize = 5; static float input[kVectorSize] = {0.0, -0.5, 1.0, -1.5, 2.0}; std::vector output(kVectorSize); CopyVector(input, kVectorSize, output.data()); EXPECT_THAT(output, ElementsAreArray(ArrayFloatNear({0.0, -0.5, 1.0, -1.5, 2.0}))); } TEST(uKernels, Sub1VectorTest) { constexpr int kVectorSize = 5; static float input[kVectorSize] = {0.0, -0.5, 1.0, -1.5, 2.0}; std::vector output(kVectorSize); Sub1Vector(input, kVectorSize, output.data()); EXPECT_THAT(output, ElementsAreArray(ArrayFloatNear({1.0, 1.5, 0.0, 2.5, -1.0}))); } TEST(uKernels, ZeroVectorTest) { constexpr int kVectorSize = 5; std::vector output(kVectorSize); ZeroVector(output.data(), kVectorSize); EXPECT_THAT(output, ElementsAreArray(ArrayFloatNear({0.0, 0.0, 0.0, 0.0, 0.0}))); } TEST(uKernels, BatchVectorBatchVectorDotProductTest) { constexpr int kVectorSize = 5; constexpr int kBatch = 2; static float input1[kVectorSize * kBatch] = {0.0, -0.5, 1.0, -1.5, 2.0, -2.5, 3.0, -3.5, 4.0, -4.5}; static float input2[kVectorSize * kBatch] = {0.1, -0.1, 0.1, -0.1, 0.1, -0.1, 0.1, -0.1, 0.1, -0.1}; std::vector output(kBatch); BatchVectorBatchVectorDotProduct(input1, input2, kVectorSize, kBatch, output.data(), /*result_stride=*/1); EXPECT_THAT(output, ElementsAreArray(ArrayFloatNear({0.5, 1.75}))); } TEST(uKernels, VectorShiftLeftTest) { constexpr int kVectorSize = 5; static float input[kVectorSize] = {0.0, -0.5, 1.0, -1.5, 2.0}; std::vector result(kVectorSize); VectorShiftLeft(input, kVectorSize, 3.0); result.assign(input, input + kVectorSize); EXPECT_THAT(result, ElementsAreArray(ArrayFloatNear({-0.5, 1.0, -1.5, 2.0, 3.0}))); } TEST(uKernels, ReductionSumVectorTest) { constexpr int kInputVectorSize = 10; constexpr int kOutputVectorSize = 5; constexpr int kReductionSize = 2; static float input[kInputVectorSize] = {0.0, -0.5, 1.0, -1.5, 2.0, 0.0, -0.5, 1.0, 1.0, 2.0}; std::vector result(kOutputVectorSize); ReductionSumVector(input, /*input_stride=*/1, result.data(), kOutputVectorSize, kReductionSize); EXPECT_THAT(result, ElementsAreArray(ArrayFloatNear({-0.5, -0.5, 2.0, 0.5, 3.0}))); } } // namespace tensor_utils } // namespace nn } // namespace android