1 /* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #include "tensorflow/lite/delegates/gpu/common/selectors/simple_selectors.h"
17
18 #include <memory>
19 #include <set>
20
21 #include "absl/memory/memory.h"
22 #include "tensorflow/lite/delegates/gpu/common/status.h"
23 #include "tensorflow/lite/delegates/gpu/common/tasks/add.h"
24 #include "tensorflow/lite/delegates/gpu/common/tasks/concat_xy.h"
25 #include "tensorflow/lite/delegates/gpu/common/tasks/concat_z.h"
26 #include "tensorflow/lite/delegates/gpu/common/tasks/depthwise_conv.h"
27 #include "tensorflow/lite/delegates/gpu/common/tasks/lstm.h"
28 #include "tensorflow/lite/delegates/gpu/common/tasks/max_unpooling.h"
29 #include "tensorflow/lite/delegates/gpu/common/tasks/padding.h"
30 #include "tensorflow/lite/delegates/gpu/common/tasks/pooling.h"
31 #include "tensorflow/lite/delegates/gpu/common/tasks/prelu.h"
32 #include "tensorflow/lite/delegates/gpu/common/tasks/quantize_and_dequantize.h"
33 #include "tensorflow/lite/delegates/gpu/common/tasks/reduce.h"
34 #include "tensorflow/lite/delegates/gpu/common/tasks/relu.h"
35 #include "tensorflow/lite/delegates/gpu/common/tasks/reshape.h"
36 #include "tensorflow/lite/delegates/gpu/common/tasks/reshapex4.h"
37 #include "tensorflow/lite/delegates/gpu/common/tasks/resize.h"
38 #include "tensorflow/lite/delegates/gpu/common/tasks/softmax.h"
39 #include "tensorflow/lite/delegates/gpu/common/tasks/softmax1x1.h"
40 #include "tensorflow/lite/delegates/gpu/common/tasks/space_to_depth.h"
41 #include "tensorflow/lite/delegates/gpu/common/tasks/split.h"
42 #include "tensorflow/lite/delegates/gpu/common/tasks/strided_slice.h"
43 #include "tensorflow/lite/delegates/gpu/common/tasks/transpose.h"
44 #include "tensorflow/lite/delegates/gpu/common/tasks/winograd.h"
45
46 namespace tflite {
47 namespace gpu {
48
SelectLSTM(const OperationDef & op_def,const GpuInfo & gpu_info)49 std::unique_ptr<GPUOperation> SelectLSTM(const OperationDef& op_def,
50 const GpuInfo& gpu_info) {
51 return absl::make_unique<GPUOperation>(CreateLSTM(op_def, gpu_info));
52 }
53
SelectReLU(const ReLUAttributes & attr,const OperationDef & op_def)54 std::unique_ptr<GPUOperation> SelectReLU(const ReLUAttributes& attr,
55 const OperationDef& op_def) {
56 return absl::make_unique<GPUOperation>(CreateReLU(op_def, attr));
57 }
58
SelectPReLU(const PReLUAttributes & attr,const GpuInfo & gpu_info,const OperationDef & op_def)59 std::unique_ptr<GPUOperation> SelectPReLU(const PReLUAttributes& attr,
60 const GpuInfo& gpu_info,
61 const OperationDef& op_def) {
62 return absl::make_unique<GPUOperation>(CreatePReLU(gpu_info, op_def, attr));
63 }
64
SelectPooling(const Pooling2DAttributes & attr,const OperationDef & op_def)65 std::unique_ptr<GPUOperation> SelectPooling(const Pooling2DAttributes& attr,
66 const OperationDef& op_def) {
67 return absl::make_unique<GPUOperation>(CreatePooling(op_def, attr));
68 }
69
SelectMaxUnpooling(const MaxUnpooling2DAttributes & attr,const OperationDef & op_def)70 std::unique_ptr<GPUOperation> SelectMaxUnpooling(
71 const MaxUnpooling2DAttributes& attr, const OperationDef& op_def) {
72 return absl::make_unique<GPUOperation>(CreateMaxUnpooling(op_def, attr));
73 }
74
SelectAdd(const OperationDef & op_def,const std::vector<int> & channels,int dst_channels,std::unique_ptr<GPUOperation> * ptr)75 void SelectAdd(const OperationDef& op_def, const std::vector<int>& channels,
76 int dst_channels, std::unique_ptr<GPUOperation>* ptr) {
77 GPUOperation operation = CreateAdd(op_def, channels, dst_channels);
78 *ptr = absl::make_unique<GPUOperation>(std::move(operation));
79 }
80
SelectResize(const Resize2DAttributes & attr,const OperationDef & op_def,std::unique_ptr<GPUOperation> * ptr)81 absl::Status SelectResize(const Resize2DAttributes& attr,
82 const OperationDef& op_def,
83 std::unique_ptr<GPUOperation>* ptr) {
84 Resize operation = CreateResize(op_def, attr);
85 *ptr = absl::make_unique<Resize>(std::move(operation));
86 return absl::OkStatus();
87 }
88
SelectConcat(const ConcatAttributes & attr,const std::vector<int> & channels,const OperationDef & op_def,const GpuInfo & gpu_info,std::unique_ptr<GPUOperation> * ptr)89 absl::Status SelectConcat(const ConcatAttributes& attr,
90 const std::vector<int>& channels,
91 const OperationDef& op_def, const GpuInfo& gpu_info,
92 std::unique_ptr<GPUOperation>* ptr) {
93 switch (attr.axis) {
94 case Axis::CHANNELS: {
95 GPUOperation operation = CreateConcatZ(op_def, channels, gpu_info);
96 *ptr = absl::make_unique<GPUOperation>(std::move(operation));
97 return absl::OkStatus();
98 }
99 case Axis::BATCH:
100 case Axis::DEPTH:
101 case Axis::HEIGHT:
102 case Axis::WIDTH: {
103 GPUOperation operation = CreateConcatXY(op_def, attr);
104 *ptr = absl::make_unique<GPUOperation>(std::move(operation));
105 return absl::OkStatus();
106 }
107 default:
108 return absl::UnimplementedError("No concat for this axis.");
109 }
110 }
111
SelectDWConvolutionDynamicWeights(const DepthwiseConvolution2DAttributes & attr,const GpuInfo & gpu_info,const OperationDef & op_def)112 std::unique_ptr<GPUOperation> SelectDWConvolutionDynamicWeights(
113 const DepthwiseConvolution2DAttributes& attr, const GpuInfo& gpu_info,
114 const OperationDef& op_def) {
115 return absl::make_unique<GPUOperation>(
116 CreateDepthwiseConvolution2DDynamicWeights(gpu_info, op_def, attr));
117 }
118
SelectReshape(int src_channels,int dst_channels,const OperationDef & op_def,std::unique_ptr<GPUOperation> * ptr)119 void SelectReshape(int src_channels, int dst_channels,
120 const OperationDef& op_def,
121 std::unique_ptr<GPUOperation>* ptr) {
122 if (src_channels % 4 == 0 && dst_channels % 4 == 0) {
123 GPUOperation operation = CreateReshapex4(op_def);
124 *ptr = absl::make_unique<GPUOperation>(std::move(operation));
125 } else {
126 GPUOperation operation = CreateReshape(op_def);
127 *ptr = absl::make_unique<GPUOperation>(std::move(operation));
128 }
129 }
130
SelectSpaceToDepth(const SpaceToDepthAttributes & attr,const OperationDef & op_def,std::unique_ptr<GPUOperation> * ptr)131 void SelectSpaceToDepth(const SpaceToDepthAttributes& attr,
132 const OperationDef& op_def,
133 std::unique_ptr<GPUOperation>* ptr) {
134 GPUOperation operation = CreateSpaceToDepth(op_def, attr);
135 *ptr = absl::make_unique<GPUOperation>(std::move(operation));
136 }
137
SelectSplit(const SplitAttributes & attr,const OperationDef & op_def,std::unique_ptr<GPUOperation> * ptr)138 absl::Status SelectSplit(const SplitAttributes& attr,
139 const OperationDef& op_def,
140 std::unique_ptr<GPUOperation>* ptr) {
141 if (attr.axis != Axis::CHANNELS) {
142 return absl::UnimplementedError("No split for this axis.");
143 }
144 Split operation = CreateSplit(op_def, attr);
145 *ptr = absl::make_unique<Split>(std::move(operation));
146 return absl::OkStatus();
147 }
148
SelectPadding(const PadAttributes & attr,const OperationDef & op_def,std::unique_ptr<GPUOperation> * ptr)149 void SelectPadding(const PadAttributes& attr, const OperationDef& op_def,
150 std::unique_ptr<GPUOperation>* ptr) {
151 GPUOperation operation = CreatePadding(op_def, attr);
152 *ptr = absl::make_unique<GPUOperation>(std::move(operation));
153 }
154
SelectStridedSlice(const SliceAttributes & attr,const OperationDef & op_def,std::unique_ptr<GPUOperation> * ptr)155 void SelectStridedSlice(const SliceAttributes& attr, const OperationDef& op_def,
156 std::unique_ptr<GPUOperation>* ptr) {
157 StridedSlice operation = CreateStridedSlice(op_def, attr);
158 *ptr = absl::make_unique<StridedSlice>(std::move(operation));
159 }
160
SelectReduce(const std::set<Axis> & axis_to_reduce,const BHWC & src_shape,OperationType op_type,const OperationDef & op_def,const GpuInfo & gpu_info)161 std::unique_ptr<GPUOperation> SelectReduce(const std::set<Axis>& axis_to_reduce,
162 const BHWC& src_shape,
163 OperationType op_type,
164 const OperationDef& op_def,
165 const GpuInfo& gpu_info) {
166 return absl::make_unique<Reduce>(
167 CreateReduce(axis_to_reduce, src_shape, op_type, op_def, gpu_info));
168 }
169
SelectSoftmax(const BHWC & shape,const OperationDef & op_def,std::unique_ptr<GPUOperation> * ptr)170 void SelectSoftmax(const BHWC& shape, const OperationDef& op_def,
171 std::unique_ptr<GPUOperation>* ptr) {
172 if (shape.w == 1 && shape.h == 1) {
173 Softmax1x1 operation = CreateSoftmax1x1(op_def);
174 *ptr = absl::make_unique<Softmax1x1>(std::move(operation));
175 } else {
176 GPUOperation operation = CreateSoftmax(op_def);
177 *ptr = absl::make_unique<GPUOperation>(std::move(operation));
178 }
179 }
180
SelectTranspose(const TransposeAttributes & attr,const OperationDef & op_def,std::unique_ptr<GPUOperation> * ptr)181 void SelectTranspose(const TransposeAttributes& attr,
182 const OperationDef& op_def,
183 std::unique_ptr<GPUOperation>* ptr) {
184 GPUOperation operation = CreateTranspose(op_def, attr);
185 *ptr = absl::make_unique<GPUOperation>(std::move(operation));
186 }
187
SelectWinograd4x4To36(const GpuInfo & gpu_info,const Padding2D & padding,const OperationDef & op_def)188 std::unique_ptr<GPUOperation> SelectWinograd4x4To36(
189 const GpuInfo& gpu_info, const Padding2D& padding,
190 const OperationDef& op_def) {
191 if (gpu_info.IsApple()) {
192 const auto src_storage = op_def.src_tensors[0].storage_type;
193 const auto dst_storage = op_def.src_tensors[0].storage_type;
194 if ((src_storage == TensorStorageType::BUFFER ||
195 src_storage == TensorStorageType::IMAGE_BUFFER) &&
196 (dst_storage == TensorStorageType::BUFFER ||
197 dst_storage == TensorStorageType::IMAGE_BUFFER)) {
198 Winograd4x4To36 operation = CreateWinograd4x4To36(op_def, padding);
199 return absl::make_unique<Winograd4x4To36>(std::move(operation));
200 }
201 }
202 return absl::make_unique<Winograd4x4To36TileX6>(
203 CreateWinograd4x4To36TileX6(gpu_info, op_def, padding));
204 }
205
SelectWinograd36To4x4(const GpuInfo & gpu_info,const OperationDef & op_def,const tflite::gpu::Tensor<Linear,DataType::FLOAT32> & biases)206 std::unique_ptr<GPUOperation> SelectWinograd36To4x4(
207 const GpuInfo& gpu_info, const OperationDef& op_def,
208 const tflite::gpu::Tensor<Linear, DataType::FLOAT32>& biases) {
209 if (gpu_info.IsApple()) {
210 const auto src_storage = op_def.src_tensors[0].storage_type;
211 const auto dst_storage = op_def.src_tensors[0].storage_type;
212 if ((src_storage == TensorStorageType::BUFFER ||
213 src_storage == TensorStorageType::IMAGE_BUFFER) &&
214 (dst_storage == TensorStorageType::BUFFER ||
215 dst_storage == TensorStorageType::IMAGE_BUFFER)) {
216 Winograd36To4x4 operation = CreateWinograd36To4x4(op_def, biases);
217 return absl::make_unique<Winograd36To4x4>(std::move(operation));
218 }
219 }
220 return absl::make_unique<Winograd36To4x4Tile4x1>(
221 CreateWinograd36To4x4Tile4x1(gpu_info, op_def, biases));
222 }
223
SelectQuantizeAndDequantize(const QuantizeAndDequantizeAttributes & attr,const OperationDef & op_def)224 std::unique_ptr<GPUOperation> SelectQuantizeAndDequantize(
225 const QuantizeAndDequantizeAttributes& attr, const OperationDef& op_def) {
226 return absl::make_unique<GPUOperation>(
227 CreateQuantizeAndDequantize(op_def, attr));
228 }
229
230 } // namespace gpu
231 } // namespace tflite
232