diff options
author | Slava Shklyaev <slavash@google.com> | 2018-10-30 12:17:23 +0000 |
---|---|---|
committer | Xusong Wang <xusongw@google.com> | 2018-11-09 20:47:32 -0800 |
commit | af66ded6c7c0238369073e148e011ee33c0d07f6 (patch) | |
tree | f615bf02b198e89613a4fc072ad73f944e9e5aa6 | |
parent | 18767480d9325582d12dbf37e5705b974be4b39c (diff) | |
download | ml-af66ded6c7c0238369073e148e011ee33c0d07f6.tar.gz |
Extract IndexedShapeWrapper into a separate file
I am going to use IndexedShapeWrapper in my implementation of MAXIMUM.
Bug: 113560501
Test: mma
Change-Id: I8a740167f128819ca3005c19da5b607537ad07eb
Merged-In: I8a740167f128819ca3005c19da5b607537ad07eb
(cherry picked from commit 8b165e64bce2eed15d34a2a7d319916ccebbf88a)
-rw-r--r-- | nn/common/Android.bp | 1 | ||||
-rw-r--r-- | nn/common/IndexedShapeWrapper.cpp | 102 | ||||
-rw-r--r-- | nn/common/include/IndexedShapeWrapper.h | 65 | ||||
-rw-r--r-- | nn/common/operations/Pow.cpp | 107 |
4 files changed, 170 insertions, 105 deletions
diff --git a/nn/common/Android.bp b/nn/common/Android.bp index 517ac73b2..877a2ebb2 100644 --- a/nn/common/Android.bp +++ b/nn/common/Android.bp @@ -55,6 +55,7 @@ cc_library_static { srcs: [ "CpuExecutor.cpp", "GraphDump.cpp", + "IndexedShapeWrapper.cpp", "OperationsUtils.cpp", "Utils.cpp", "ValidateHal.cpp", diff --git a/nn/common/IndexedShapeWrapper.cpp b/nn/common/IndexedShapeWrapper.cpp new file mode 100644 index 000000000..e90665986 --- /dev/null +++ b/nn/common/IndexedShapeWrapper.cpp @@ -0,0 +1,102 @@ +/* + * 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. + */ + +#define LOG_TAG "IndexedShapeWrapper" + +#include "IndexedShapeWrapper.h" + +namespace android { +namespace nn { + +IndexedShapeWrapper::IndexedShapeWrapper(const Shape& wrapped_shape) : shape(&wrapped_shape) { + strides.resize(shape->dimensions.size()); + strides.back() = 1; + for (int i = strides.size() - 2; i >= 0; --i) { + strides[i] = shape->dimensions[i + 1] * strides[i + 1]; + } +} + +bool IndexedShapeWrapper::nextIndexInplace(std::vector<uint32_t>* index, bool* lastIndex) const { + NN_CHECK(isValid(*index)); + + bool anyIndicesLeft = false; + for (int i = 0; i < index->size(); ++i) { + if (index->at(i) < shape->dimensions[i] - 1) { + anyIndicesLeft = true; + break; + } + } + if (!anyIndicesLeft) { + *lastIndex = true; + return true; + } + for (int i = index->size() - 1; i >= 0; --i) { + ++index->at(i); + if (index->at(i) == shape->dimensions[i]) { + index->at(i) = 0; + } else { + break; + } + } + return true; +} + +bool IndexedShapeWrapper::indexToFlatIndex(const std::vector<uint32_t>& index, + uint32_t* flatIndex) const { + NN_CHECK(isValid(index)); + + *flatIndex = 0; + for (int i = 0; i < index.size(); ++i) { + *flatIndex += strides[i] * index[i]; + } + return true; +} + +bool IndexedShapeWrapper::broadcastedIndexToFlatIndex(const std::vector<uint32_t>& index, + uint32_t* flatIndex) const { + NN_CHECK(index.size() >= strides.size()); + + *flatIndex = 0; + for (int i = 1; i <= strides.size(); ++i) { + uint32_t currentIndex = index[index.size() - i]; + uint32_t currentDimSize = shape->dimensions[shape->dimensions.size() - i]; + NN_CHECK(currentIndex < currentDimSize || currentDimSize == 1); + if (currentDimSize != 1) { + *flatIndex += strides[strides.size() - i] * index[index.size() - i]; + } + } + return true; +} + +bool IndexedShapeWrapper::isValid(const std::vector<uint32_t>& index) const { + if (index.size() != shape->dimensions.size()) { + LOG(ERROR) << "Index: " << toString(index) + << " has a different number of dimensions from shape: " + << toString(shape->dimensions); + return false; + } + for (int i = 0; i < index.size(); ++i) { + if (index[i] >= shape->dimensions[i]) { + LOG(ERROR) << "Invalid index: " << toString(index) + << " is out of range for shape: " << toString(shape->dimensions); + return false; + } + } + return true; +} + +} // namespace nn +} // namespace android diff --git a/nn/common/include/IndexedShapeWrapper.h b/nn/common/include/IndexedShapeWrapper.h new file mode 100644 index 000000000..8ae53ccbf --- /dev/null +++ b/nn/common/include/IndexedShapeWrapper.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef FRAMEWORKS_ML_NN_INDEXED_SHAPE_WRAPPER_H +#define FRAMEWORKS_ML_NN_INDEXED_SHAPE_WRAPPER_H + +#include "OperationsUtils.h" + +namespace android { +namespace nn { + +// A wrapper over a Shape class implementing some indexing logic for a wrapped +// shape. +// To get an offset for an element in a tensor from vector index, one needs to +// calculate strides first. This class removes the need to recalculate strides +// for every indexing and also provides some utility functions. +class IndexedShapeWrapper { + public: + IndexedShapeWrapper(const Shape& wrapped_shape); + + // Calculates the next index in a lexicograpical order for a wrapped shape + // inplace. Only accepts valid index for a given shape as an input. + // Sets lastIndex to true if the received index was the last in a + // lexicographical order for a given shape. In this case, index stays the + // same. + bool nextIndexInplace(std::vector<uint32_t>* index, bool* lastIndex) const; + + // Given an index as a vector with per-dimension indices, calculates an + // offset of the element in a flattened tensor. + bool indexToFlatIndex(const std::vector<uint32_t>& index, uint32_t* flatIndex) const; + + // Same as indexToFlatIndex, only ignores first dimensions of an index if + // they are not present in the shape. Also ignores dimensions of a shape of + // size 1. + // For example: + // for shape: [3, 1, 2] + // and index: [4, 2, 5, 1] + // the function will ignore dimensions with indices 4 and 5 and set + // flatIndex to 5 as a result. + bool broadcastedIndexToFlatIndex(const std::vector<uint32_t>& index, uint32_t* flatIndex) const; + + private: + const Shape* const shape; + std::vector<uint32_t> strides; + + bool isValid(const std::vector<uint32_t>& index) const; +}; + +} // namespace nn +} // namespace android + +#endif // FRAMEWORKS_ML_NN_INDEXED_SHAPE_WRAPPER_H diff --git a/nn/common/operations/Pow.cpp b/nn/common/operations/Pow.cpp index db59d94df..f944b9881 100644 --- a/nn/common/operations/Pow.cpp +++ b/nn/common/operations/Pow.cpp @@ -17,120 +17,17 @@ #define LOG_TAG "Operations" #include "Pow.h" +#include "IndexedShapeWrapper.h" +#include "OperationsUtils.h" #include <cmath> -#include "OperationsUtils.h" - namespace android { namespace nn { namespace pow { namespace { -// A wrapper over a Shape class implementing some indexing logic for a wrapped -// shape. -// To get an offset for an element in a tensor from vector index, one needs to -// calculate strides first. This class removes the need to recalculate strides -// for every indexing and also provides some utility functions. -class IndexedShapeWrapper { - public: - IndexedShapeWrapper(const Shape& wrapped_shape) : shape(&wrapped_shape) { - strides.resize(shape->dimensions.size()); - strides.back() = 1; - for (int i = strides.size() - 2; i >= 0; --i) { - strides[i] = shape->dimensions[i + 1] * strides[i + 1]; - } - } - - // Calculates the next index in a lexicograpical order for a wrapped shape - // inplace. Only accepts valid index for a given shape as an input. - // Sets lastIndex to true if the received index was the last in a - // lexicographical order for a given shape. In this case, index stays the - // same. - bool nextIndexInplace(std::vector<uint32_t>* index, bool* lastIndex) const { - NN_CHECK(isValid(*index)); - - bool anyIndicesLeft = false; - for (int i = 0; i < index->size(); ++i) { - if (index->at(i) < shape->dimensions[i] - 1) { - anyIndicesLeft = true; - break; - } - } - if (!anyIndicesLeft) { - *lastIndex = true; - return true; - } - for (int i = index->size() - 1; i >= 0; --i) { - ++index->at(i); - if (index->at(i) == shape->dimensions[i]) { - index->at(i) = 0; - } else { - break; - } - } - return true; - } - - // Given an index as a vector with per-dimension indices, calculates an - // offset of the element in a flattened tensor. - bool indexToFlatIndex(const std::vector<uint32_t>& index, uint32_t* flatIndex) const { - NN_CHECK(isValid(index)); - - *flatIndex = 0; - for (int i = 0; i < index.size(); ++i) { - *flatIndex += strides[i] * index[i]; - } - return true; - } - - // Same as indexToFlatIndex, only ignores first dimensions of an index if - // they are not present in the shape. Also ignores dimensions of a shape of - // size 1. - // For example: - // for shape: [3, 1, 2] - // and index: [4, 2, 5, 1] - // the function will ignore dimensions with indices 4 and 5 and set - // flatIndex to 5 as a result. - bool broadcastedIndexToFlatIndex(const std::vector<uint32_t>& index, - uint32_t* flatIndex) const { - NN_CHECK(index.size() >= strides.size()); - - *flatIndex = 0; - for (int i = 1; i <= strides.size(); ++i) { - uint32_t currentIndex = index[index.size() - i]; - uint32_t currentDimSize = shape->dimensions[shape->dimensions.size() - i]; - NN_CHECK(currentIndex < currentDimSize || currentDimSize == 1); - if (currentDimSize != 1) { - *flatIndex += strides[strides.size() - i] * index[index.size() - i]; - } - } - return true; - } - - private: - const Shape* const shape; - std::vector<uint32_t> strides; - - bool isValid(const std::vector<uint32_t>& index) const { - if (index.size() != shape->dimensions.size()) { - LOG(ERROR) << "Index: " << toString(index) - << " has a different number of dimensions from shape: " - << toString(shape->dimensions); - return false; - } - for (int i = 0; i < index.size(); ++i) { - if (index[i] >= shape->dimensions[i]) { - LOG(ERROR) << "Invalid index: " << toString(index) - << " is out of range for shape: " << toString(shape->dimensions); - return false; - } - } - return true; - } -}; - template <typename T> bool evalGeneric(const T* baseData, const Shape& baseShape, const T* exponentData, const Shape& exponentShape, T* outputData, const Shape& outputShape) { |