123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- /*
- * Copyright (C) 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 "LSHProjection.h"
- #include "NeuralNetworksWrapper.h"
- #include "gmock/gmock-generated-matchers.h"
- #include "gmock/gmock-matchers.h"
- #include "gtest/gtest.h"
- using ::testing::FloatNear;
- using ::testing::Matcher;
- namespace android {
- namespace nn {
- namespace wrapper {
- using ::testing::ElementsAre;
- #define FOR_ALL_INPUT_AND_WEIGHT_TENSORS(ACTION) \
- ACTION(Hash, float) \
- ACTION(Input, int) \
- ACTION(Weight, float)
- // For all output and intermediate states
- #define FOR_ALL_OUTPUT_TENSORS(ACTION) ACTION(Output, int)
- class LSHProjectionOpModel {
- public:
- LSHProjectionOpModel(LSHProjectionType type, std::initializer_list<uint32_t> hash_shape,
- std::initializer_list<uint32_t> input_shape,
- std::initializer_list<uint32_t> weight_shape)
- : type_(type) {
- std::vector<uint32_t> inputs;
- OperandType HashTy(Type::TENSOR_FLOAT32, hash_shape);
- inputs.push_back(model_.addOperand(&HashTy));
- OperandType InputTy(Type::TENSOR_INT32, input_shape);
- inputs.push_back(model_.addOperand(&InputTy));
- OperandType WeightTy(Type::TENSOR_FLOAT32, weight_shape);
- inputs.push_back(model_.addOperand(&WeightTy));
- OperandType TypeParamTy(Type::INT32, {});
- inputs.push_back(model_.addOperand(&TypeParamTy));
- std::vector<uint32_t> outputs;
- auto multiAll = [](const std::vector<uint32_t>& dims) -> uint32_t {
- uint32_t sz = 1;
- for (uint32_t d : dims) {
- sz *= d;
- }
- return sz;
- };
- uint32_t outShapeDimension = 0;
- if (type == LSHProjectionType_SPARSE || type == LSHProjectionType_SPARSE_DEPRECATED) {
- auto it = hash_shape.begin();
- Output_.insert(Output_.end(), *it, 0.f);
- outShapeDimension = *it;
- } else {
- Output_.insert(Output_.end(), multiAll(hash_shape), 0.f);
- outShapeDimension = multiAll(hash_shape);
- }
- OperandType OutputTy(Type::TENSOR_INT32, {outShapeDimension});
- outputs.push_back(model_.addOperand(&OutputTy));
- model_.addOperation(ANEURALNETWORKS_LSH_PROJECTION, inputs, outputs);
- model_.identifyInputsAndOutputs(inputs, outputs);
- model_.finish();
- }
- #define DefineSetter(X, T) \
- void Set##X(const std::vector<T>& f) { X##_.insert(X##_.end(), f.begin(), f.end()); }
- FOR_ALL_INPUT_AND_WEIGHT_TENSORS(DefineSetter);
- #undef DefineSetter
- const std::vector<int>& GetOutput() const { return Output_; }
- void Invoke() {
- ASSERT_TRUE(model_.isValid());
- Compilation compilation(&model_);
- compilation.finish();
- Execution execution(&compilation);
- #define SetInputOrWeight(X, T) \
- ASSERT_EQ( \
- execution.setInput(LSHProjection::k##X##Tensor, X##_.data(), sizeof(T) * X##_.size()), \
- Result::NO_ERROR);
- FOR_ALL_INPUT_AND_WEIGHT_TENSORS(SetInputOrWeight);
- #undef SetInputOrWeight
- #define SetOutput(X, T) \
- ASSERT_EQ(execution.setOutput(LSHProjection::k##X##Tensor, X##_.data(), \
- sizeof(T) * X##_.size()), \
- Result::NO_ERROR);
- FOR_ALL_OUTPUT_TENSORS(SetOutput);
- #undef SetOutput
- ASSERT_EQ(execution.setInput(LSHProjection::kTypeParam, &type_, sizeof(type_)),
- Result::NO_ERROR);
- ASSERT_EQ(execution.compute(), Result::NO_ERROR);
- }
- private:
- Model model_;
- LSHProjectionType type_;
- std::vector<float> Hash_;
- std::vector<int> Input_;
- std::vector<float> Weight_;
- std::vector<int> Output_;
- }; // namespace wrapper
- TEST(LSHProjectionOpTest2, DenseWithThreeInputs) {
- LSHProjectionOpModel m(LSHProjectionType_DENSE, {4, 2}, {3, 2}, {3});
- m.SetInput({12345, 54321, 67890, 9876, -12345678, -87654321});
- m.SetHash({0.123, 0.456, -0.321, -0.654, 1.234, 5.678, -4.321, -8.765});
- m.SetWeight({0.12, 0.34, 0.56});
- m.Invoke();
- EXPECT_THAT(m.GetOutput(), ElementsAre(1, 1, 1, 0, 1, 1, 1, 0));
- }
- TEST(LSHProjectionOpTest2, SparseDeprecatedWithTwoInputs) {
- LSHProjectionOpModel m(LSHProjectionType_SPARSE_DEPRECATED, {4, 2}, {3, 2}, {0});
- m.SetInput({12345, 54321, 67890, 9876, -12345678, -87654321});
- m.SetHash({0.123, 0.456, -0.321, -0.654, 1.234, 5.678, -4.321, -8.765});
- m.Invoke();
- EXPECT_THAT(m.GetOutput(), ElementsAre(1, 2, 2, 0));
- }
- TEST(LSHProjectionOpTest2, SparseWithTwoInputs) {
- LSHProjectionOpModel m(LSHProjectionType_SPARSE, {4, 2}, {3, 2}, {0});
- m.SetInput({12345, 54321, 67890, 9876, -12345678, -87654321});
- m.SetHash({0.123, 0.456, -0.321, -0.654, 1.234, 5.678, -4.321, -8.765});
- m.Invoke();
- EXPECT_THAT(m.GetOutput(), ElementsAre(1, 6, 10, 12));
- }
- } // namespace wrapper
- } // namespace nn
- } // namespace android
|