blob: e97256713f0ef6e9f34b469ba1e1f693c66a672e [file] [log] [blame]
Georgios Pinitase29acf12018-07-16 14:40:09 +01001/*
Matthew Bentham92046462020-03-07 22:15:55 +00002 * Copyright (c) 2018-2020 ARM Limited.
Georgios Pinitase29acf12018-07-16 14:40:09 +01003 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#include "arm_compute/runtime/CL/functions/CLConcatenateLayer.h"
25
Vidhya Sudhan Loganathan338595b2019-06-28 14:09:53 +010026#include "arm_compute/core/CL/kernels/CLBatchConcatenateLayerKernel.h"
Georgios Pinitas09f24972019-05-17 18:14:40 +010027#include "arm_compute/core/CL/kernels/CLDepthConcatenateLayerKernel.h"
Pablo Tello6a14adb2019-03-05 17:33:08 +000028#include "arm_compute/core/CL/kernels/CLHeightConcatenateLayerKernel.h"
Georgios Pinitas09f24972019-05-17 18:14:40 +010029#include "arm_compute/core/CL/kernels/CLWidthConcatenate2TensorsKernel.h"
30#include "arm_compute/core/CL/kernels/CLWidthConcatenate4TensorsKernel.h"
31#include "arm_compute/core/CL/kernels/CLWidthConcatenateLayerKernel.h"
Pablo Tello6a14adb2019-03-05 17:33:08 +000032#include "arm_compute/core/utils/misc/ShapeCalculator.h"
33#include "arm_compute/runtime/CL/CLScheduler.h"
Georgios Pinitase29acf12018-07-16 14:40:09 +010034
35#include "arm_compute/core/CL/ICLTensor.h"
36#include "arm_compute/core/Error.h"
37#include "arm_compute/core/TensorInfo.h"
38#include "arm_compute/core/Types.h"
Matthew Bentham92046462020-03-07 22:15:55 +000039#include "support/MemorySupport.h"
Georgios Pinitase29acf12018-07-16 14:40:09 +010040
41namespace arm_compute
42{
43CLConcatenateLayer::CLConcatenateLayer()
Michalis Spyrou8c571692019-04-05 11:29:52 +010044 : _concat_kernels(),
Pablo Tello6a14adb2019-03-05 17:33:08 +000045 _num_inputs(0),
46 _axis(Window::DimX)
Georgios Pinitase29acf12018-07-16 14:40:09 +010047{
48}
49
Manuel Bottini10c53f12019-07-17 16:11:53 +010050void CLConcatenateLayer::configure(std::vector<ICLTensor *> &inputs_vector, ICLTensor *output, size_t axis)
51{
Manuel Bottini2b84be52020-04-08 10:15:51 +010052 configure(CLKernelLibrary::get().get_compile_context(), inputs_vector, output, axis);
53}
54
55void CLConcatenateLayer::configure(const CLCompileContext &compile_context, std::vector<ICLTensor *> &inputs_vector, ICLTensor *output, size_t axis)
56{
57 configure_internal(compile_context, std::move(inputs_vector), output, axis);
Manuel Bottini10c53f12019-07-17 16:11:53 +010058}
59
60void CLConcatenateLayer::configure(std::vector<const ICLTensor *> &inputs_vector, ICLTensor *output, size_t axis)
61{
Manuel Bottini2b84be52020-04-08 10:15:51 +010062 configure(CLKernelLibrary::get().get_compile_context(), inputs_vector, output, axis);
63}
64
65void CLConcatenateLayer::configure(const CLCompileContext &compile_context, std::vector<const ICLTensor *> &inputs_vector, ICLTensor *output, size_t axis)
66{
67 configure_internal(compile_context, std::move(inputs_vector), output, axis);
Manuel Bottini10c53f12019-07-17 16:11:53 +010068}
69
70Status CLConcatenateLayer::validate(const std::vector<ITensorInfo *> &inputs_vector, const ITensorInfo *output, size_t axis)
71{
72 return validate_internal(inputs_vector, output, axis);
73}
74
75Status CLConcatenateLayer::validate(const std::vector<const ITensorInfo *> &inputs_vector, const ITensorInfo *output, size_t axis)
76{
77 return validate_internal(inputs_vector, output, axis);
78}
79
80template <typename TensorType>
Manuel Bottini2b84be52020-04-08 10:15:51 +010081void CLConcatenateLayer::configure_internal(const CLCompileContext &compile_context, std::vector<TensorType *> &&inputs_vector, ICLTensor *output, size_t axis)
Pablo Tello6a14adb2019-03-05 17:33:08 +000082{
Michalis Spyrou8c571692019-04-05 11:29:52 +010083 ARM_COMPUTE_ERROR_ON(output == nullptr);
Georgios Pinitas9e4824c2019-04-12 13:15:58 +010084 _axis = axis;
Pablo Tello6a14adb2019-03-05 17:33:08 +000085 _num_inputs = inputs_vector.size();
86
87 std::vector<ITensorInfo *> inputs_vector_info(inputs_vector.size());
Manuel Bottini10c53f12019-07-17 16:11:53 +010088 std::transform(inputs_vector.begin(), inputs_vector.end(), inputs_vector_info.begin(), [](TensorType * t)
Pablo Tello6a14adb2019-03-05 17:33:08 +000089 {
90 ARM_COMPUTE_ERROR_ON_NULLPTR(t);
91 return t->info();
92 });
Michalis Spyroua9c44722019-04-05 17:18:36 +010093 TensorShape output_shape = arm_compute::misc::shape_calculator::calculate_concatenate_shape(inputs_vector, _axis);
Pablo Tello6a14adb2019-03-05 17:33:08 +000094
95 // Output auto inizialitation if not yet initialized
96 auto_init_if_empty(*output->info(), output_shape, 1, inputs_vector[0]->info()->data_type());
Michalis Spyrou8c571692019-04-05 11:29:52 +010097 ARM_COMPUTE_ERROR_THROW_ON(CLConcatenateLayer::validate(inputs_vector_info, output->info(), axis));
Pablo Tello6a14adb2019-03-05 17:33:08 +000098
Michalis Spyrou8c571692019-04-05 11:29:52 +010099 unsigned int offset = 0;
Pablo Tello6a14adb2019-03-05 17:33:08 +0000100 switch(_axis)
Georgios Pinitase29acf12018-07-16 14:40:09 +0100101 {
Michalis Spyrou8c571692019-04-05 11:29:52 +0100102 case Window::DimX:
Georgios Pinitase29acf12018-07-16 14:40:09 +0100103 {
Michalis Spyrou8c571692019-04-05 11:29:52 +0100104 switch(_num_inputs)
105 {
106 case 2:
107 {
108 // Configure WidthConcatenate2Tensors kernel
109 auto kernel = support::cpp14::make_unique<CLWidthConcatenate2TensorsKernel>();
Manuel Bottini2b84be52020-04-08 10:15:51 +0100110 kernel->configure(compile_context, inputs_vector.at(0), inputs_vector.at(1), output);
Michalis Spyrou8c571692019-04-05 11:29:52 +0100111 _concat_kernels.emplace_back(std::move(kernel));
112 break;
113 }
114 case 4:
115 {
116 // Configure WidthConcatenate4Tensors kernel
117 auto kernel = support::cpp14::make_unique<CLWidthConcatenate4TensorsKernel>();
Manuel Bottini2b84be52020-04-08 10:15:51 +0100118 kernel->configure(compile_context, inputs_vector.at(0), inputs_vector.at(1), inputs_vector.at(2), inputs_vector.at(3), output);
Michalis Spyrou8c571692019-04-05 11:29:52 +0100119 _concat_kernels.emplace_back(std::move(kernel));
120 break;
121 }
122 default:
123 {
124 // Configure generic case WidthConcatenate kernels
125 for(unsigned int i = 0; i < _num_inputs; ++i)
126 {
127 auto kernel = support::cpp14::make_unique<CLWidthConcatenateLayerKernel>();
Manuel Bottini2b84be52020-04-08 10:15:51 +0100128 kernel->configure(compile_context, inputs_vector.at(i), offset, output);
Michalis Spyrou8c571692019-04-05 11:29:52 +0100129 offset += inputs_vector.at(i)->info()->dimension(_axis);
130 _concat_kernels.emplace_back(std::move(kernel));
131 }
132 break;
133 }
134 }
Georgios Pinitase29acf12018-07-16 14:40:09 +0100135 break;
136 }
Michalis Spyrou8c571692019-04-05 11:29:52 +0100137 case Window::DimY:
Pablo Tello6a14adb2019-03-05 17:33:08 +0000138 {
Michalis Spyrou8c571692019-04-05 11:29:52 +0100139 for(unsigned int i = 0; i < _num_inputs; ++i)
140 {
141 auto kernel = support::cpp14::make_unique<CLHeightConcatenateLayerKernel>();
Manuel Bottini2b84be52020-04-08 10:15:51 +0100142 kernel->configure(compile_context, inputs_vector.at(i), offset, output);
Michalis Spyrou8c571692019-04-05 11:29:52 +0100143 offset += inputs_vector.at(i)->info()->dimension(_axis);
144 _concat_kernels.emplace_back(std::move(kernel));
145 }
Pablo Tello6a14adb2019-03-05 17:33:08 +0000146 break;
147 }
Michalis Spyrou8c571692019-04-05 11:29:52 +0100148 case Window::DimZ:
Georgios Pinitase29acf12018-07-16 14:40:09 +0100149 {
Michalis Spyrou8c571692019-04-05 11:29:52 +0100150 for(unsigned int i = 0; i < _num_inputs; ++i)
151 {
152 auto kernel = support::cpp14::make_unique<CLDepthConcatenateLayerKernel>();
Manuel Bottini2b84be52020-04-08 10:15:51 +0100153 kernel->configure(compile_context, inputs_vector.at(i), offset, output);
Michalis Spyrou8c571692019-04-05 11:29:52 +0100154 offset += inputs_vector.at(i)->info()->dimension(_axis);
155 _concat_kernels.emplace_back(std::move(kernel));
156 }
Georgios Pinitase29acf12018-07-16 14:40:09 +0100157 break;
158 }
Vidhya Sudhan Loganathan338595b2019-06-28 14:09:53 +0100159 case 3:
160 {
161 for(unsigned int i = 0; i < _num_inputs; ++i)
162 {
163 auto kernel = support::cpp14::make_unique<CLBatchConcatenateLayerKernel>();
Manuel Bottini2b84be52020-04-08 10:15:51 +0100164 kernel->configure(compile_context, inputs_vector.at(i), offset, output);
Vidhya Sudhan Loganathan338595b2019-06-28 14:09:53 +0100165 offset += inputs_vector.at(i)->info()->dimension(_axis);
166 _concat_kernels.emplace_back(std::move(kernel));
167 }
168 break;
169 }
Georgios Pinitase29acf12018-07-16 14:40:09 +0100170 default:
Michalis Spyrou8c571692019-04-05 11:29:52 +0100171 ARM_COMPUTE_ERROR("Axis not supported");
Georgios Pinitase29acf12018-07-16 14:40:09 +0100172 }
173}
174
Manuel Bottini10c53f12019-07-17 16:11:53 +0100175template <typename TensorInfoType>
176Status CLConcatenateLayer::validate_internal(const std::vector<TensorInfoType *> &inputs_vector, const ITensorInfo *output, size_t axis)
Georgios Pinitase29acf12018-07-16 14:40:09 +0100177{
178 ARM_COMPUTE_RETURN_ERROR_ON(output == nullptr);
Michalis Spyrou8c571692019-04-05 11:29:52 +0100179 const unsigned int num_inputs = inputs_vector.size();
Georgios Pinitase29acf12018-07-16 14:40:09 +0100180
Michalis Spyrou8c571692019-04-05 11:29:52 +0100181 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(output);
182 ARM_COMPUTE_RETURN_ERROR_ON(num_inputs < 2);
Michalis Spyrou8c571692019-04-05 11:29:52 +0100183
Michalis Spyrou8c571692019-04-05 11:29:52 +0100184 unsigned int offset = 0;
Georgios Pinitas9e4824c2019-04-12 13:15:58 +0100185 switch(axis)
Michalis Spyrou8c571692019-04-05 11:29:52 +0100186 {
187 case Window::DimX:
188 {
189 switch(num_inputs)
190 {
191 case 2:
192 // Validate WidthConcatenate2Tensors kernels if there are 2 inputs
193 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(inputs_vector[0], inputs_vector[1]);
Michalis Spyroua9c44722019-04-05 17:18:36 +0100194 ARM_COMPUTE_RETURN_ON_ERROR(CLWidthConcatenate2TensorsKernel::validate(inputs_vector[0], inputs_vector[1], output));
Michalis Spyrou8c571692019-04-05 11:29:52 +0100195 break;
196 case 4:
197 // Validate WidthConcatenate4Tensors kernels if there are 4 inputs
198 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(inputs_vector[0], inputs_vector[1], inputs_vector[2], inputs_vector[3]);
Michalis Spyroua9c44722019-04-05 17:18:36 +0100199 ARM_COMPUTE_RETURN_ON_ERROR(CLWidthConcatenate4TensorsKernel::validate(inputs_vector[0], inputs_vector[1], inputs_vector[2], inputs_vector[3], output));
Michalis Spyrou8c571692019-04-05 11:29:52 +0100200 break;
201 default:
202 // Validate generic case of WidthConcatenate kernel
203 for(const auto &input : inputs_vector)
204 {
205 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input);
Michalis Spyroua9c44722019-04-05 17:18:36 +0100206 ARM_COMPUTE_RETURN_ON_ERROR(CLWidthConcatenateLayerKernel::validate(input, offset, output));
Georgios Pinitas9e4824c2019-04-12 13:15:58 +0100207 offset += input->dimension(axis);
Michalis Spyrou8c571692019-04-05 11:29:52 +0100208 }
209 break;
210 }
211 break;
212 }
213 case Window::DimY:
214 {
215 for(const auto &input : inputs_vector)
216 {
Michalis Spyroua9c44722019-04-05 17:18:36 +0100217 ARM_COMPUTE_RETURN_ON_ERROR(CLHeightConcatenateLayerKernel::validate(input, offset, output));
Georgios Pinitas9e4824c2019-04-12 13:15:58 +0100218 offset += input->dimension(axis);
Michalis Spyrou8c571692019-04-05 11:29:52 +0100219 }
220 break;
221 }
222 case Window::DimZ:
223 {
224 for(const auto &input : inputs_vector)
225 {
Michalis Spyroua9c44722019-04-05 17:18:36 +0100226 ARM_COMPUTE_RETURN_ON_ERROR(CLDepthConcatenateLayerKernel::validate(input, offset, output));
Georgios Pinitas9e4824c2019-04-12 13:15:58 +0100227 offset += input->dimension(axis);
Michalis Spyrou8c571692019-04-05 11:29:52 +0100228 }
229 break;
230 }
Vidhya Sudhan Loganathan338595b2019-06-28 14:09:53 +0100231 case 3:
232 {
233 for(const auto &input : inputs_vector)
234 {
235 ARM_COMPUTE_RETURN_ON_ERROR(CLBatchConcatenateLayerKernel::validate(input, offset, output));
236 offset += input->dimension(axis);
237 }
238 break;
239 }
Michalis Spyrou8c571692019-04-05 11:29:52 +0100240 default:
241 ARM_COMPUTE_ERROR("Axis not supported");
242 }
243
Michalis Spyroua9c44722019-04-05 17:18:36 +0100244 if(output->total_size() != 0)
245 {
246 TensorShape output_shape = arm_compute::misc::shape_calculator::calculate_concatenate_shape(inputs_vector, axis);
247 ARM_COMPUTE_RETURN_ERROR_ON(output_shape.total_size() != output->tensor_shape().total_size());
248 }
249
Georgios Pinitase29acf12018-07-16 14:40:09 +0100250 return Status{};
251}
252
253void CLConcatenateLayer::run()
254{
Michalis Spyrou8c571692019-04-05 11:29:52 +0100255 for(auto &kernel : _concat_kernels)
Pablo Tello6a14adb2019-03-05 17:33:08 +0000256 {
Michalis Spyrou8c571692019-04-05 11:29:52 +0100257 CLScheduler::get().enqueue(*kernel, true);
Pablo Tello6a14adb2019-03-05 17:33:08 +0000258 }
Georgios Pinitase29acf12018-07-16 14:40:09 +0100259}
260} // namespace arm_compute