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 // Contains the implementation of the operations. 18 19 #define LOG_TAG "Operations" 20 21 #include "CpuOperationUtils.h" 22 #include "Operations.h" 23 24 #include "tensorflow/lite/kernels/internal/optimized/legacy_optimized_ops.h" 25 #include "tensorflow/lite/kernels/internal/reference/reference_ops.h" 26 27 #include "Tracing.h" 28 29 namespace android { 30 namespace nn { 31 32 bool copyData(const void* inputData, const Shape& inputShape, void* outputData, 33 const Shape& outputShape) { 34 NNTRACE_COMP("copyData"); 35 size_t count = nonExtensionOperandSizeOfData(inputShape.type, inputShape.dimensions); 36 memcpy(outputData, inputData, count); 37 return true; 38 } 39 40 template <typename T> 41 bool depthToSpaceGeneric(const T* inputData, const Shape& inputShape, int32_t blockSize, 42 T* outputData, const Shape& outputShape) { 43 NNTRACE_COMP("optimized_ops::DepthToSpace"); 44 tflite::optimized_ops::DepthToSpace(inputData, convertShapeToDims(inputShape), blockSize, 45 outputData, convertShapeToDims(outputShape)); 46 return true; 47 } 48 template bool depthToSpaceGeneric<float>(const float* inputData, const Shape& inputShape, 49 int32_t blockSize, float* outputData, 50 const Shape& outputShape); 51 template bool depthToSpaceGeneric<_Float16>(const _Float16* inputData, const Shape& inputShape, 52 int32_t blockSize, _Float16* outputData, 53 const Shape& outputShape); 54 template bool depthToSpaceGeneric<uint8_t>(const uint8_t* inputData, const Shape& inputShape, 55 int32_t blockSize, uint8_t* outputData, 56 const Shape& outputShape); 57 58 template <typename T> 59 bool spaceToDepthGeneric(const T* inputData, const Shape& inputShape, int32_t blockSize, 60 T* outputData, const Shape& outputShape) { 61 NNTRACE_COMP("optimized_ops::SpaceToDepth"); 62 tflite::optimized_ops::SpaceToDepth(inputData, convertShapeToDims(inputShape), blockSize, 63 outputData, convertShapeToDims(outputShape)); 64 return true; 65 } 66 template bool spaceToDepthGeneric<float>(const float* inputData, const Shape& inputShape, 67 int32_t blockSize, float* outputData, 68 const Shape& outputShape); 69 template bool spaceToDepthGeneric<_Float16>(const _Float16* inputData, const Shape& inputShape, 70 int32_t blockSize, _Float16* outputData, 71 const Shape& outputShape); 72 template bool spaceToDepthGeneric<uint8_t>(const uint8_t* inputData, const Shape& inputShape, 73 int32_t blockSize, uint8_t* outputData, 74 const Shape& outputShape); 75 76 template <typename T> 77 bool padGeneric(const T* inputData, const Shape& inputShape, const int32_t* paddings, T padValue, 78 T* outputData, const Shape& outputShape) { 79 NNTRACE_TRANS("padGeneric"); 80 81 // Based on 82 // http://google3/third_party/tensorflow/contrib/lite/kernels/internal/optimized/optimized_ops.h?l=6194&rcl=213557260 83 84 // TFLite runtime calls are currently fixed at 4 dimensions. Copy inputs so 85 // we can pad them to 4 dims (yes, we are "padding the padding"). 86 int32_t numInputDims = static_cast<int32_t>(getNumberOfDimensions(inputShape)); 87 NN_OPS_CHECK(numInputDims <= 4); 88 std::vector<int> leftPaddings(4 - numInputDims, 0); 89 std::vector<int> rightPaddings(4 - numInputDims, 0); 90 for (int32_t i = 0; i < numInputDims; ++i) { 91 leftPaddings.push_back(paddings[i * 2]); 92 rightPaddings.push_back(paddings[i * 2 + 1]); 93 } 94 const int leftBPadding = leftPaddings[0]; 95 const int leftHPadding = leftPaddings[1]; 96 const int leftWPadding = leftPaddings[2]; 97 const int leftDPadding = leftPaddings[3]; 98 const int rightBPadding = rightPaddings[0]; 99 const int rightHPadding = rightPaddings[1]; 100 const int rightWPadding = rightPaddings[2]; 101 const int rightDPadding = rightPaddings[3]; 102 103 const auto extInputShape = 104 tflite::RuntimeShape::ExtendedShape(4, convertShapeToTflshape(inputShape)); 105 const auto extOutputShape = 106 tflite::RuntimeShape::ExtendedShape(4, convertShapeToTflshape(outputShape)); 107 108 const int outputBatch = extOutputShape.Dims(0); 109 const int outputHeight = extOutputShape.Dims(1); 110 const int outputWidth = extOutputShape.Dims(2); 111 const int outputDepth = extOutputShape.Dims(3); 112 113 const int inputDepth = extInputShape.Dims(3); 114 115 NNTRACE_COMP_SWITCH("padGeneric"); 116 117 if (leftBPadding != 0) { 118 tflite::optimized_ops::TypedMemset<T>( 119 outputData, padValue, leftBPadding * outputHeight * outputWidth * outputDepth); 120 } 121 for (int outB = leftBPadding; outB < outputBatch - rightBPadding; ++outB) { 122 if (leftHPadding != 0) { 123 tflite::optimized_ops::TypedMemset<T>( 124 outputData + tflite::Offset(extOutputShape, outB, 0, 0, 0), padValue, 125 leftHPadding * outputWidth * outputDepth); 126 } 127 for (int outH = leftHPadding; outH < outputHeight - rightHPadding; ++outH) { 128 if (leftWPadding != 0) { 129 tflite::optimized_ops::TypedMemset<T>( 130 outputData + tflite::Offset(extOutputShape, outB, outH, 0, 0), padValue, 131 leftWPadding * outputDepth); 132 } 133 for (int outW = leftWPadding; outW < outputWidth - rightWPadding; ++outW) { 134 if (leftDPadding != 0) { 135 tflite::optimized_ops::TypedMemset<T>( 136 outputData + tflite::Offset(extOutputShape, outB, outH, outW, 0), 137 padValue, leftDPadding); 138 } 139 140 T* out = 141 outputData + tflite::Offset(extOutputShape, outB, outH, outW, leftDPadding); 142 const T* in = 143 inputData + tflite::Offset(extInputShape, outB - leftBPadding, 144 outH - leftHPadding, outW - leftWPadding, 0); 145 memcpy(out, in, inputDepth * sizeof(T)); 146 147 if (rightDPadding != 0) { 148 tflite::optimized_ops::TypedMemset<T>( 149 outputData + tflite::Offset(extOutputShape, outB, outH, outW, 150 outputDepth - rightDPadding), 151 padValue, rightDPadding); 152 } 153 } 154 if (rightWPadding != 0) { 155 tflite::optimized_ops::TypedMemset<T>( 156 outputData + tflite::Offset(extOutputShape, outB, outH, 157 outputWidth - rightWPadding, 0), 158 padValue, rightWPadding * outputDepth); 159 } 160 } 161 if (rightHPadding != 0) { 162 tflite::optimized_ops::TypedMemset<T>( 163 outputData + tflite::Offset(extOutputShape, outB, outputHeight - rightHPadding, 164 0, 0), 165 padValue, rightHPadding * outputWidth * outputDepth); 166 } 167 } 168 if (rightBPadding != 0) { 169 tflite::optimized_ops::TypedMemset<T>( 170 outputData + tflite::Offset(extOutputShape, outputBatch - rightBPadding, 0, 0, 0), 171 padValue, rightBPadding * outputHeight * outputWidth * outputDepth); 172 } 173 174 return true; 175 } 176 template bool padGeneric<float>(const float* inputData, const Shape& inputShape, 177 const int32_t* paddings, float padValue, float* outputData, 178 const Shape& outputShape); 179 template bool padGeneric<_Float16>(const _Float16* inputData, const Shape& inputShape, 180 const int32_t* paddings, _Float16 padValue, _Float16* outputData, 181 const Shape& outputShape); 182 template bool padGeneric<uint8_t>(const uint8_t* inputData, const Shape& inputShape, 183 const int32_t* paddings, uint8_t padValue, uint8_t* outputData, 184 const Shape& outputShape); 185 186 template <typename T> 187 bool batchToSpaceGeneric(const T* inputData, const Shape& inputShape, const int32_t* blockSize, 188 T* outputData, const Shape& outputShape) { 189 // Needed by low level implementation, but not really used. 190 tflite::Dims<4> blockSizeDim, cropsDim; 191 const int32 crops[4] = {0, 0, 0, 0}; 192 NNTRACE_COMP("optimized_ops::BatchToSpaceND"); 193 tflite::optimized_ops::BatchToSpaceND(inputData, convertShapeToDims(inputShape), blockSize, 194 blockSizeDim, crops, cropsDim, outputData, 195 convertShapeToDims(outputShape)); 196 return true; 197 } 198 template bool batchToSpaceGeneric<float>(const float* inputData, const Shape& inputShape, 199 const int32_t* blockSize, float* outputData, 200 const Shape& outputShape); 201 template bool batchToSpaceGeneric<_Float16>(const _Float16* inputData, const Shape& inputShape, 202 const int32_t* blockSize, _Float16* outputData, 203 const Shape& outputShape); 204 template bool batchToSpaceGeneric<uint8_t>(const uint8_t* inputData, const Shape& inputShape, 205 const int32_t* blockSize, uint8_t* outputData, 206 const Shape& outputShape); 207 208 template <typename T> 209 bool spaceToBatchGeneric(const T* inputData, const Shape& inputShape, const int32_t* blockSize, 210 const int32_t* padding, const Shape& paddingShape, T* outputData, 211 const Shape& outputShape) { 212 // Needed by low level implementation, but not really used. 213 tflite::RuntimeShape blockSizeDim; 214 NNTRACE_COMP("optimized_ops::SpaceToBatchND"); 215 tflite::optimized_ops::SpaceToBatchND( 216 {.output_offset = outputShape.offset}, convertShapeToTflshape(inputShape), inputData, 217 blockSizeDim, blockSize, convertShapeToTflshape(paddingShape), padding, 218 convertShapeToTflshape(outputShape), outputData); 219 return true; 220 } 221 template bool spaceToBatchGeneric<float>(const float* inputData, const Shape& inputShape, 222 const int32_t* blockSize, const int32_t* padding, 223 const Shape& paddingShape, float* outputData, 224 const Shape& outputShape); 225 template bool spaceToBatchGeneric<_Float16>(const _Float16* inputData, const Shape& inputShape, 226 const int32_t* blockSize, const int32_t* padding, 227 const Shape& paddingShape, _Float16* outputData, 228 const Shape& outputShape); 229 template bool spaceToBatchGeneric<uint8_t>(const uint8_t* inputData, const Shape& inputShape, 230 const int32_t* blockSize, const int32_t* padding, 231 const Shape& paddingShape, uint8_t* outputData, 232 const Shape& outputShape); 233 234 } // namespace nn 235 } // namespace android 236