blob: d0703317cd5941131387570c9a1aff46a5b5d26e [file] [log] [blame]
Georgios Pinitasd8734b52017-12-22 15:27:52 +00001/*
2 * Copyright (c) 2018 ARM Limited.
3 *
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 */
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010024#ifndef __ARM_COMPUTE_GRAPH_LAYERS_H__
25#define __ARM_COMPUTE_GRAPH_LAYERS_H__
Georgios Pinitasd8734b52017-12-22 15:27:52 +000026
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010027#include "arm_compute/graph/GraphBuilder.h"
28#include "arm_compute/graph/Types.h"
29#include "arm_compute/graph/frontend/ILayer.h"
30#include "arm_compute/graph/frontend/IStream.h"
31#include "arm_compute/graph/frontend/SubStream.h"
Georgios Pinitasd8734b52017-12-22 15:27:52 +000032
33#include "arm_compute/core/utils/misc/Utility.h"
34
35#include <memory>
36#include <string>
37
38namespace arm_compute
39{
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010040namespace graph
Georgios Pinitasd8734b52017-12-22 15:27:52 +000041{
42namespace frontend
43{
44/** Input Layer */
45class InputLayer final : public ILayer
46{
47public:
Alex Gildayc357c472018-03-21 13:54:09 +000048 /** Construct an input layer.
49 *
50 * @param[in] desc Description of input tensor.
51 * @param[in] accessor Accessor to get input tensor data from.
52 */
Georgios Pinitasd8734b52017-12-22 15:27:52 +000053 InputLayer(TensorDescriptor desc, ITensorAccessorUPtr accessor)
54 : _desc(desc), _accessor(std::move(accessor))
55 {
56 }
57
58 NodeID create_layer(IStream &s) override
59 {
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +010060 NodeParams common_params = { name(), s.hints().target_hint };
Georgios Pinitasd8734b52017-12-22 15:27:52 +000061 return GraphBuilder::add_input_node(s.graph(), common_params, _desc, std::move(_accessor));
62 }
63
64private:
65 TensorDescriptor _desc;
66 ITensorAccessorUPtr _accessor;
67};
68
69/** Output Layer */
70class OutputLayer final : public ILayer
71{
72public:
Alex Gildayc357c472018-03-21 13:54:09 +000073 /** Construct an output layer.
74 *
75 * @param[in] accessor Accessor to give output tensor data to.
76 */
Georgios Pinitasd8734b52017-12-22 15:27:52 +000077 OutputLayer(ITensorAccessorUPtr accessor)
78 : _accessor(std::move(accessor))
79 {
80 }
81
82 NodeID create_layer(IStream &s) override
83 {
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +010084 NodeParams common_params = { name(), s.hints().target_hint };
Georgios Pinitasd8734b52017-12-22 15:27:52 +000085 NodeIdxPair input = { s.tail_node(), 0 };
86 return GraphBuilder::add_output_node(s.graph(), common_params, input, std::move(_accessor));
87 }
88
89private:
90 ITensorAccessorUPtr _accessor;
91};
92
93/** Activation Layer */
94class ActivationLayer final : public ILayer
95{
96public:
Alex Gildayc357c472018-03-21 13:54:09 +000097 /** Construct an activation layer.
98 *
99 * @param[in] act_info Activation information
100 */
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000101 ActivationLayer(ActivationLayerInfo act_info)
102 : _act_info(act_info)
103 {
104 }
105
106 NodeID create_layer(IStream &s) override
107 {
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100108 NodeParams common_params = { name(), s.hints().target_hint };
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000109 NodeIdxPair input = { s.tail_node(), 0 };
110 return GraphBuilder::add_activation_node(s.graph(), common_params, input, _act_info);
111 }
112
113private:
114 ActivationLayerInfo _act_info;
115};
116
117/** Batchnormalization Layer */
118class BatchNormalizationLayer final : public ILayer
119{
120public:
Alex Gildayc357c472018-03-21 13:54:09 +0000121 /** Construct a batch normalization layer.
122 *
123 * @param[in] mean Accessor to get mean tensor data from.
124 * @param[in] var Accessor to get var tensor data from.
125 * @param[in] gamma (Optional) Accessor to get gamma tensor data from. Default: nullptr.
126 * @param[in] beta (Optional) Accessor to get beta tensor data from. Default: nullptr.
127 * @param[in] epsilon (Optional) Epsilon value. Default: 0.001.
128 */
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000129 BatchNormalizationLayer(ITensorAccessorUPtr mean,
130 ITensorAccessorUPtr var,
131 ITensorAccessorUPtr gamma = nullptr,
132 ITensorAccessorUPtr beta = nullptr,
133 float epsilon = 0.001f)
134 : _mean(std::move(mean)), _var(std::move(var)), _gamma(std::move(gamma)), _beta(std::move(beta)), _epsilon(epsilon)
135 {
136 }
137
138 NodeID create_layer(IStream &s) override
139 {
140 ARM_COMPUTE_ERROR_ON(_mean == nullptr);
141 ARM_COMPUTE_ERROR_ON(_var == nullptr);
142
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100143 NodeParams common_params = { name(), s.hints().target_hint };
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000144 NodeIdxPair input = { s.tail_node(), 0 };
145 return GraphBuilder::add_batch_normalization_node(s.graph(), common_params, input, _epsilon,
146 std::move(_mean), std::move(_var), std::move(_beta), std::move(_gamma));
147 }
148
149private:
150 ITensorAccessorUPtr _mean;
151 ITensorAccessorUPtr _var;
152 ITensorAccessorUPtr _gamma;
153 ITensorAccessorUPtr _beta;
154 float _epsilon;
155};
156
Manuel Bottinid2048ce2018-10-23 17:00:42 +0100157/** Bounding Box Transform Layer */
158class BoundingBoxTransformLayer final : public ILayer
159{
160public:
161 /** Construct a bounding box transform layer.
162 *
163 * @param[in] sub_stream_input Graph sub-stream for the input
164 * @param[in] sub_stream_deltas Graph sub-stream for the deltas
165 * @param[in] info Contains BoundingBox operation information described in @ref BoundingBoxTransformInfo.
166 */
167 BoundingBoxTransformLayer(SubStream &&sub_stream_input, SubStream &&sub_stream_deltas, BoundingBoxTransformInfo info)
168 : _ss_input(sub_stream_input), _ss_deltas(sub_stream_deltas), _bbox_info(info)
169 {
170 }
171
172 /** Create layer and add to the given stream.
173 *
174 * @param[in] s Stream to add layer to.
175 *
176 * @return ID of the created node.
177 */
178 NodeID create_layer(IStream &s) override
179 {
180 NodeParams common_params = { name(), s.hints().target_hint };
181 NodeIdxPair input = { _ss_input.tail_node(), 0 };
182 NodeIdxPair deltas = { _ss_deltas.tail_node(), 0 };
183 return GraphBuilder::add_bounding_box_transform_node(s.graph(), common_params, input, deltas, _bbox_info);
184 }
185
186private:
187 SubStream _ss_input;
188 SubStream _ss_deltas;
189 BoundingBoxTransformInfo _bbox_info;
190};
191
Georgios Pinitas087eaf62018-05-16 15:52:35 +0100192/** Channel Shuffle Layer */
193class ChannelShuffleLayer final : public ILayer
194{
195public:
196 /** Construct a Channel Shuffle layer.
197 *
198 * @param[in] num_groups Number of groups
199 */
200 ChannelShuffleLayer(unsigned int num_groups)
201 : _num_groups(num_groups)
202 {
203 }
204
205 NodeID create_layer(IStream &s) override
206 {
207 NodeParams common_params = { name(), s.hints().target_hint };
208 NodeIdxPair input = { s.tail_node(), 0 };
209 return GraphBuilder::add_channel_shuffle_node(s.graph(), common_params, input, _num_groups);
210 }
211
212private:
213 unsigned int _num_groups;
214};
215
Georgios Pinitas427bbbf2018-08-28 13:32:02 +0100216/** Concat Layer */
217class ConcatLayer final : public ILayer
218{
219public:
220 /** Construct a concatenation layer
221 *
222 * @param[in] sub_stream1 First graph branch
223 * @param[in] sub_stream2 Second graph branch
224 * @param[in] rest_sub_streams Rest sub-graph branches
225 */
226 template <typename... Ts>
227 ConcatLayer(SubStream &&sub_stream1, SubStream &&sub_stream2, Ts &&... rest_sub_streams)
Pablo Tello32521432018-11-15 14:43:10 +0000228 : _sub_streams(), _axis(DataLayoutDimension::CHANNEL)
229 {
230 _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream1)));
231 _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream2)));
232
233 utility::for_each([&](SubStream && sub_stream)
234 {
235 _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream)));
236 },
237 std::move(rest_sub_streams)...);
238 }
239 /** Construct a concatenation layer
240 *
241 * @param[in] axis Axis over the concatenation will be performed
242 * @param[in] sub_stream1 First graph branch
243 * @param[in] sub_stream2 Second graph branch
244 * @param[in] rest_sub_streams Rest sub-graph branches
245 */
246 template <typename... Ts>
247 ConcatLayer(DataLayoutDimension axis, SubStream &&sub_stream1, SubStream &&sub_stream2, Ts &&... rest_sub_streams)
248 : _sub_streams(), _axis(axis)
Georgios Pinitas427bbbf2018-08-28 13:32:02 +0100249 {
250 _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream1)));
251 _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream2)));
252
253 utility::for_each([&](SubStream && sub_stream)
254 {
255 _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream)));
256 },
257 std::move(rest_sub_streams)...);
258 }
259 /** Construct a concat layer
260 *
261 * @param[in] sub_stream Sub-stream
262 */
263 template <typename... Ts>
264 ConcatLayer(SubStream &&sub_stream)
Pablo Tello32521432018-11-15 14:43:10 +0000265 : _sub_streams(), _axis(DataLayoutDimension::CHANNEL)
Georgios Pinitas427bbbf2018-08-28 13:32:02 +0100266 {
267 _sub_streams.push_back(arm_compute::support::cpp14::make_unique<SubStream>(std::move(sub_stream)));
268 }
269 NodeID create_layer(IStream &s) override
270 {
271 NodeID nid = EmptyNodeID;
272 NodeParams common_params = { name(), s.hints().target_hint };
273 if(_sub_streams.size() == 1 && _sub_streams.at(0) != nullptr)
274 {
275 nid = _sub_streams[0]->tail_node();
276 }
277 else
278 {
279 // Collect tail nodes and concatenate
280 std::vector<NodeIdxPair> nodes;
281 for(auto &ss : _sub_streams)
282 {
283 if(ss && (ss->tail_node() != EmptyNodeID))
284 {
285 const auto tail_node = s.graph().node(ss->tail_node());
286 if(tail_node != nullptr && tail_node->type() != NodeType::Output)
287 {
288 nodes.push_back({ ss->tail_node(), 0 });
289 }
290 }
291 }
Pablo Tello32521432018-11-15 14:43:10 +0000292 nid = GraphBuilder::add_concatenate_node(s.graph(), common_params, nodes, _axis);
Georgios Pinitas427bbbf2018-08-28 13:32:02 +0100293 }
294 return nid;
295 }
296
297private:
298 std::vector<std::unique_ptr<SubStream>> _sub_streams;
Pablo Tello32521432018-11-15 14:43:10 +0000299 DataLayoutDimension _axis;
Georgios Pinitas427bbbf2018-08-28 13:32:02 +0100300};
301
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000302/** Convolution Layer */
303class ConvolutionLayer final : public ILayer
304{
305public:
Alex Gildayc357c472018-03-21 13:54:09 +0000306 /** Construct a convolution layer.
307 *
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100308 * @param[in] conv_width Convolution width.
309 * @param[in] conv_height Convolution height.
310 * @param[in] ofm Output feature map.
311 * @param[in] weights Accessor to get kernel weights from.
312 * @param[in] bias Accessor to get kernel bias from.
313 * @param[in] conv_info Padding and stride information.
314 * @param[in] num_groups (Optional) Number of groups. Default: 1.
315 * @param[in] weights_quant_info (Optional) Weights quantization information
316 * @param[in] out_quant_info (Optional) Output quantization info
Alex Gildayc357c472018-03-21 13:54:09 +0000317 */
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100318 ConvolutionLayer(unsigned int conv_width,
319 unsigned int conv_height,
320 unsigned int ofm,
321 ITensorAccessorUPtr weights,
322 ITensorAccessorUPtr bias,
323 PadStrideInfo conv_info,
324 unsigned int num_groups = 1,
325 const QuantizationInfo weights_quant_info = QuantizationInfo(),
326 const QuantizationInfo out_quant_info = QuantizationInfo())
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000327 : _conv_width(conv_width),
328 _conv_height(conv_height),
329 _ofm(ofm),
330 _conv_info(std::move(conv_info)),
331 _num_groups(num_groups),
332 _weights(std::move(weights)),
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100333 _bias(std::move(bias)),
334 _weights_quant_info(std::move(weights_quant_info)),
335 _out_quant_info(std::move(out_quant_info))
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000336 {
337 }
338
339 NodeID create_layer(IStream &s) override
340 {
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000341 NodeIdxPair input = { s.tail_node(), 0 };
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100342 NodeParams common_params = { name(), s.hints().target_hint };
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000343 return GraphBuilder::add_convolution_node(s.graph(), common_params, input,
Georgios Pinitasee33ea52018-03-08 16:01:29 +0000344 Size2D(_conv_width, _conv_height), _ofm, _conv_info, _num_groups,
Giorgio Arena59631a12018-05-02 13:59:04 +0100345 s.hints().convolution_method_hint, s.hints().fast_math_hint,
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100346 std::move(_weights), std::move(_bias), std::move(_weights_quant_info), std::move(_out_quant_info));
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000347 }
348
349private:
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100350 unsigned int _conv_width;
351 unsigned int _conv_height;
352 unsigned int _ofm;
353 const PadStrideInfo _conv_info;
354 unsigned int _num_groups;
355 ITensorAccessorUPtr _weights;
356 ITensorAccessorUPtr _bias;
357 const QuantizationInfo _weights_quant_info;
358 const QuantizationInfo _out_quant_info;
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000359};
360
Georgios Pinitas087eaf62018-05-16 15:52:35 +0100361/** Deconvolution Layer */
362class DeconvolutionLayer final : public ILayer
363{
364public:
365 /** Construct a convolution layer.
366 *
367 * @param[in] conv_width Convolution width.
368 * @param[in] conv_height Convolution height.
369 * @param[in] ofm Output feature map.
370 * @param[in] weights Accessor to get kernel weights from.
371 * @param[in] bias Accessor to get kernel bias from.
372 * @param[in] deconv_info Padding and stride information.
373 * @param[in] inner_border Inner border padding (right, top)
374 */
375 DeconvolutionLayer(unsigned int conv_width,
376 unsigned int conv_height,
377 unsigned int ofm,
378 ITensorAccessorUPtr weights,
379 ITensorAccessorUPtr bias,
380 PadStrideInfo deconv_info,
381 Size2D inner_border)
382 : _conv_width(conv_width),
383 _conv_height(conv_height),
384 _ofm(ofm),
385 _deconv_info(std::move(deconv_info)),
386 _inner_border(inner_border),
387 _weights(std::move(weights)),
388 _bias(std::move(bias))
389 {
390 }
391
392 NodeID create_layer(IStream &s) override
393 {
394 NodeIdxPair input = { s.tail_node(), 0 };
395 NodeParams common_params = { name(), s.hints().target_hint };
396 return GraphBuilder::add_deconvolution_node(s.graph(), common_params, input,
397 Size2D(_conv_width, _conv_height), _ofm, _deconv_info, _inner_border,
398 std::move(_weights), std::move(_bias));
399 }
400
401private:
402 unsigned int _conv_width;
403 unsigned int _conv_height;
404 unsigned int _ofm;
405 const PadStrideInfo _deconv_info;
406 Size2D _inner_border;
407 ITensorAccessorUPtr _weights;
408 ITensorAccessorUPtr _bias;
409};
410
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000411/** Depthwise Convolution Layer */
412class DepthwiseConvolutionLayer final : public ILayer
413{
414public:
Alex Gildayc357c472018-03-21 13:54:09 +0000415 /** Construct a depthwise convolution layer.
416 *
Georgios Pinitas05045c12018-12-07 18:31:47 +0000417 * @param[in] conv_width Convolution width.
418 * @param[in] conv_height Convolution height.
419 * @param[in] weights Accessor to get kernel weights from.
420 * @param[in] bias Accessor to get kernel bias from.
421 * @param[in] conv_info Padding and stride information.
422 * @param[in] depth_multiplier (Optional) Depth multiplier parameter.
423 * @param[in] quant_info (Optional) Quantization info used for weights
Alex Gildayc357c472018-03-21 13:54:09 +0000424 */
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100425 DepthwiseConvolutionLayer(unsigned int conv_width,
426 unsigned int conv_height,
427 ITensorAccessorUPtr weights,
428 ITensorAccessorUPtr bias,
429 PadStrideInfo conv_info,
Georgios Pinitas05045c12018-12-07 18:31:47 +0000430 int depth_multiplier = 1,
431 const QuantizationInfo quant_info = QuantizationInfo())
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000432 : _conv_width(conv_width),
433 _conv_height(conv_height),
434 _conv_info(std::move(conv_info)),
435 _weights(std::move(weights)),
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100436 _bias(std::move(bias)),
Georgios Pinitas05045c12018-12-07 18:31:47 +0000437 _depth_multiplier(depth_multiplier),
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100438 _quant_info(std::move(quant_info))
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000439 {
440 }
441
442 NodeID create_layer(IStream &s) override
443 {
444 NodeIdxPair input = { s.tail_node(), 0 };
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100445 NodeParams common_params = { name(), s.hints().target_hint };
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000446 return GraphBuilder::add_depthwise_convolution_node(s.graph(), common_params,
Georgios Pinitas05045c12018-12-07 18:31:47 +0000447 input, Size2D(_conv_width, _conv_height), _conv_info, _depth_multiplier,
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000448 s.hints().depthwise_convolution_method_hint,
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100449 std::move(_weights), std::move(_bias), std::move(_quant_info));
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000450 }
451
452private:
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100453 unsigned int _conv_width;
454 unsigned int _conv_height;
455 const PadStrideInfo _conv_info;
456 ITensorAccessorUPtr _weights;
457 ITensorAccessorUPtr _bias;
Georgios Pinitas05045c12018-12-07 18:31:47 +0000458 int _depth_multiplier;
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100459 const QuantizationInfo _quant_info;
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000460};
461
Georgios Pinitas087eaf62018-05-16 15:52:35 +0100462/** Dummy Layer */
463class DummyLayer final : public ILayer
464{
465public:
466 /** Construct an input layer.
467 *
468 * @param[in] shape Output shape
469 */
470 DummyLayer(TensorShape shape)
471 : _shape(shape)
472 {
473 }
474
475 NodeID create_layer(IStream &s) override
476 {
477 NodeParams common_params = { name(), s.hints().target_hint };
478 NodeIdxPair input = { s.tail_node(), 0 };
479 return GraphBuilder::add_dummy_node(s.graph(), common_params, input, _shape);
480 }
481
482private:
483 TensorShape _shape;
484};
485
Georgios Pinitas427bbbf2018-08-28 13:32:02 +0100486class EltwiseLayer final : public ILayer
487{
488public:
489 /** Construct an element-wise operation layer
490 *
491 * @param[in] sub_stream0 First graph sub-stream
492 * @param[in] sub_stream1 First graph sub-stream
493 * @param[in] op Element-wise operation to perform
494 */
495 EltwiseLayer(SubStream &&sub_stream0, SubStream &&sub_stream1, EltwiseOperation op)
496 : _ss0(std::move(sub_stream0)), _ss1(std::move(sub_stream1)), _op(op)
497 {
498 }
499
500 NodeID create_layer(IStream &s) override
501 {
502 NodeParams common_params = { name(), s.hints().target_hint };
503 NodeIdxPair input0 = { _ss0.tail_node(), 0 };
504 NodeIdxPair input1 = { _ss1.tail_node(), 0 };
505
506 return GraphBuilder::add_elementwise_node(s.graph(), common_params, input0, input1, _op);
507 }
508
509private:
510 SubStream _ss0;
511 SubStream _ss1;
512 EltwiseOperation _op;
513};
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000514/** Flatten Layer */
515class FlattenLayer final : public ILayer
516{
517public:
Alex Gildayc357c472018-03-21 13:54:09 +0000518 /** Construct a flatten layer. */
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000519 FlattenLayer()
520 {
521 }
522
523 NodeID create_layer(IStream &s) override
524 {
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100525 NodeParams common_params = { name(), s.hints().target_hint };
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000526 NodeIdxPair input = { s.tail_node(), 0 };
527 return GraphBuilder::add_flatten_node(s.graph(), common_params, input);
528 }
529};
530
531/** Fully Connected Layer */
532class FullyConnectedLayer final : public ILayer
533{
534public:
Alex Gildayc357c472018-03-21 13:54:09 +0000535 /** Construct a fully connected layer.
536 *
Georgios Pinitas2f1366a2018-07-31 16:33:06 +0100537 * @param[in] num_outputs Number of outputs.
538 * @param[in] weights Accessor to get weights from.
539 * @param[in] bias Accessor to get bias from.
Georgios Pinitasc55cef12018-08-01 15:24:18 +0100540 * @param[in] fc_info (Optional) Fully connected layer metadata
Georgios Pinitas2f1366a2018-07-31 16:33:06 +0100541 * @param[in] weights_quant_info (Optional) Weights quantization information
542 * @param[in] out_quant_info (Optional) Output quantization info
Alex Gildayc357c472018-03-21 13:54:09 +0000543 */
Georgios Pinitasc55cef12018-08-01 15:24:18 +0100544 FullyConnectedLayer(unsigned int num_outputs,
545 ITensorAccessorUPtr weights,
546 ITensorAccessorUPtr bias,
547 const FullyConnectedLayerInfo fc_info = FullyConnectedLayerInfo(),
548 const QuantizationInfo weights_quant_info = QuantizationInfo(),
549 const QuantizationInfo out_quant_info = QuantizationInfo())
Georgios Pinitas2f1366a2018-07-31 16:33:06 +0100550 : _num_outputs(num_outputs),
551 _weights(std::move(weights)),
552 _bias(std::move(bias)),
Georgios Pinitasc55cef12018-08-01 15:24:18 +0100553 _fc_info(fc_info),
Georgios Pinitas2f1366a2018-07-31 16:33:06 +0100554 _weights_quant_info(std::move(weights_quant_info)),
555 _out_quant_info(std::move(out_quant_info))
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000556 {
557 }
558
Michele Di Giorgio47e6fed2018-11-13 12:04:25 +0000559 /** Create layer and add to the given stream.
560 *
561 * @param[in] s Stream to add layer to.
562 *
563 * @return ID of the created node.
564 */
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000565 NodeID create_layer(IStream &s) override
566 {
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100567 NodeParams common_params = { name(), s.hints().target_hint };
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000568 NodeIdxPair input = { s.tail_node(), 0 };
569 return GraphBuilder::add_fully_connected_layer(s.graph(), common_params, input, _num_outputs,
Georgios Pinitasc55cef12018-08-01 15:24:18 +0100570 std::move(_weights), std::move(_bias), _fc_info,
Georgios Pinitas2f1366a2018-07-31 16:33:06 +0100571 std::move(_weights_quant_info), std::move(_out_quant_info));
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000572 }
573
574private:
Georgios Pinitasc55cef12018-08-01 15:24:18 +0100575 unsigned int _num_outputs;
576 ITensorAccessorUPtr _weights;
577 ITensorAccessorUPtr _bias;
578 const FullyConnectedLayerInfo _fc_info;
579 const QuantizationInfo _weights_quant_info;
580 const QuantizationInfo _out_quant_info;
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000581};
582
Michele Di Giorgio47e6fed2018-11-13 12:04:25 +0000583/** Generate Proposals Layer */
584class GenerateProposalsLayer final : public ILayer
585{
586public:
587 /** Construct a generate proposals layer.
588 *
589 * @param[in] ss_scores Graph sub-stream for the scores.
590 * @param[in] ss_deltas Graph sub-stream for the deltas.
591 * @param[in] ss_anchors Graph sub-stream for the anchors.
592 * @param[in] info Generate Proposals operation information.
593 */
594 GenerateProposalsLayer(SubStream &&ss_scores, SubStream &&ss_deltas, SubStream &&ss_anchors, GenerateProposalsInfo info)
595 : _ss_scores(std::move(ss_scores)), _ss_deltas(std::move(ss_deltas)), _ss_anchors(std::move(ss_anchors)), _info(info)
596 {
597 }
598
599 /** Create layer and add to the given stream.
600 *
601 * @param[in] s Stream to add layer to.
602 *
603 * @return ID of the created node.
604 */
605 NodeID create_layer(IStream &s) override
606 {
607 NodeParams common_params = { name(), s.hints().target_hint };
608 NodeIdxPair scores = { _ss_scores.tail_node(), 0 };
609 NodeIdxPair deltas = { _ss_deltas.tail_node(), 0 };
610 NodeIdxPair anchors = { _ss_anchors.tail_node(), 0 };
611 return GraphBuilder::add_generate_proposals_node(s.graph(), common_params, scores, deltas, anchors, _info);
612 }
613
614private:
615 SubStream _ss_scores;
616 SubStream _ss_deltas;
617 SubStream _ss_anchors;
618 GenerateProposalsInfo _info;
619};
620
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000621/** Normalization Layer */
622class NormalizationLayer final : public ILayer
623{
624public:
Alex Gildayc357c472018-03-21 13:54:09 +0000625 /** Construct a normalization layer.
626 *
627 * @param[in] norm_info Normalization information.
628 */
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000629 NormalizationLayer(NormalizationLayerInfo norm_info)
630 : _norm_info(norm_info)
631 {
632 }
633
634 NodeID create_layer(IStream &s) override
635 {
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100636 NodeParams common_params = { name(), s.hints().target_hint };
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000637 NodeIdxPair input = { s.tail_node(), 0 };
638 return GraphBuilder::add_normalization_node(s.graph(), common_params, input, _norm_info);
639 }
640
641private:
642 NormalizationLayerInfo _norm_info;
643};
644
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100645/** Normalize planar YUV Layer */
646class NormalizePlanarYUVLayer final : public ILayer
647{
648public:
649 /** Construct a normalize planar YUV layer.
650 *
651 * @param[in] mean Accessor to get mean tensor data from.
652 * @param[in] std Accessor to get std tensor data from.
653 */
654 NormalizePlanarYUVLayer(ITensorAccessorUPtr mean,
655 ITensorAccessorUPtr std)
656 : _mean(std::move(mean)), _std(std::move(std))
657 {
658 }
659
660 NodeID create_layer(IStream &s) override
661 {
662 ARM_COMPUTE_ERROR_ON(_mean == nullptr);
663 ARM_COMPUTE_ERROR_ON(_std == nullptr);
664
665 NodeParams common_params = { name(), s.hints().target_hint };
666 NodeIdxPair input = { s.tail_node(), 0 };
667 return GraphBuilder::add_normalize_planar_yuv_node(s.graph(), common_params, input,
668 std::move(_mean), std::move(_std));
669 }
670
671private:
672 ITensorAccessorUPtr _mean;
673 ITensorAccessorUPtr _std;
674};
675
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100676/** Pad Layer */
677class PadLayer final : public ILayer
678{
679public:
680 /** Construct a pad layer.
681 *
682 * @param[in] padding The padding for each spatial dimension of the input tensor. The pair padding[i]
683 * specifies the front and the end padding in the i-th dimension.
684 */
685 PadLayer(PaddingList padding)
686 : _padding(padding)
687 {
688 }
689
690 NodeID create_layer(IStream &s) override
691 {
692 NodeParams common_params = { name(), s.hints().target_hint };
693 NodeIdxPair input = { s.tail_node(), 0 };
694 return GraphBuilder::add_pad_node(s.graph(), common_params, input, _padding);
695 }
696
697private:
698 PaddingList _padding;
699};
700
Georgios Pinitas57c48242018-08-02 13:41:49 +0100701/** Permute Layer */
702class PermuteLayer final : public ILayer
703{
704public:
705 /** Construct a permute layer.
706 *
707 * @param[in] perm Permutation vector.
708 * @param[in] layout (Optional) Data layout to assign to permuted tensor.
709 * If UNKNOWN then the input's layout will be used.
710 */
711 PermuteLayer(PermutationVector perm, DataLayout layout = DataLayout::UNKNOWN)
712 : _perm(perm), _layout(layout)
713 {
714 }
715
716 NodeID create_layer(IStream &s) override
717 {
718 NodeParams common_params = { name(), s.hints().target_hint };
719 NodeIdxPair input = { s.tail_node(), 0 };
720 return GraphBuilder::add_permute_node(s.graph(), common_params, input, _perm, _layout);
721 }
722
723private:
724 PermutationVector _perm;
725 DataLayout _layout;
726};
727
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000728/** Pooling Layer */
729class PoolingLayer final : public ILayer
730{
731public:
Alex Gildayc357c472018-03-21 13:54:09 +0000732 /** Construct a pooling layer.
733 *
734 * @param[in] pool_info Pooling information.
735 */
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000736 PoolingLayer(PoolingLayerInfo pool_info)
737 : _pool_info(pool_info)
738 {
739 }
740
741 NodeID create_layer(IStream &s) override
742 {
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100743 NodeParams common_params = { name(), s.hints().target_hint };
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000744 NodeIdxPair input = { s.tail_node(), 0 };
745 return GraphBuilder::add_pooling_node(s.graph(), common_params, input, _pool_info);
746 }
747
748private:
749 PoolingLayerInfo _pool_info;
750};
751
Pablo Tello32521432018-11-15 14:43:10 +0000752/** PriorBox Layer */
753class PriorBoxLayer final : public ILayer
754{
755public:
756 /** Construct a priorbox layer.
757 *
758 * @param[in] sub_stream First graph sub-stream
759 * @param[in] prior_info PriorBox parameters.
760 */
761 PriorBoxLayer(SubStream &&sub_stream, PriorBoxLayerInfo prior_info)
762 : _ss(std::move(sub_stream)), _prior_info(prior_info)
763 {
764 }
765
766 NodeID create_layer(IStream &s) override
767 {
768 NodeParams common_params = { name(), s.hints().target_hint };
769 NodeIdxPair input0 = { s.tail_node(), 0 };
770 NodeIdxPair input1 = { _ss.tail_node(), 0 };
771 return GraphBuilder::add_priorbox_node(s.graph(), common_params, input0, input1, _prior_info);
772 }
773
774private:
775 SubStream _ss;
776 PriorBoxLayerInfo _prior_info;
777};
778
Gian Marco Iodice23e24792018-09-07 15:32:14 +0100779/** Reorg Layer */
780class ReorgLayer final : public ILayer
781{
782public:
783 /** Construct a reorg layer.
784 *
785 * @param[in] stride Stride value to use for reorganizing the values in the output tensor.
786 * It defines the spatial distance between 2 consecutive pixels in the x and y direction
787 */
788 ReorgLayer(int stride)
789 : _stride(stride)
790 {
791 }
792
793 NodeID create_layer(IStream &s) override
794 {
795 NodeParams common_params = { name(), s.hints().target_hint };
796 NodeIdxPair input = { s.tail_node(), 0 };
797 return GraphBuilder::add_reorg_node(s.graph(), common_params, input, _stride);
798 }
799
800private:
801 int _stride;
802};
803
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000804/** Reshape Layer */
805class ReshapeLayer final : public ILayer
806{
807public:
Alex Gildayc357c472018-03-21 13:54:09 +0000808 /** Construct a reshape layer.
809 *
810 * @param[in] shape Target shape.
811 */
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000812 ReshapeLayer(TensorShape shape)
813 : _shape(shape)
814 {
815 }
816
817 NodeID create_layer(IStream &s) override
818 {
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100819 NodeParams common_params = { name(), s.hints().target_hint };
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000820 NodeIdxPair input = { s.tail_node(), 0 };
821 return GraphBuilder::add_reshape_node(s.graph(), common_params, input, _shape);
822 }
823
824private:
825 TensorShape _shape;
826};
827
Georgios Pinitas087eaf62018-05-16 15:52:35 +0100828/** Resize Layer */
829class ResizeLayer final : public ILayer
830{
831public:
832 ResizeLayer(InterpolationPolicy policy, float width_scale, float height_scale)
833 : _policy(policy), _width_scale(width_scale), _height_scale(height_scale)
834 {
835 }
836
837 NodeID create_layer(IStream &s) override
838 {
839 NodeParams common_params = { name(), s.hints().target_hint };
840 NodeIdxPair input = { s.tail_node(), 0 };
841 return GraphBuilder::add_resize_node(s.graph(), common_params, input, _policy, _width_scale, _height_scale);
842 }
843
844private:
845 InterpolationPolicy _policy;
846 float _width_scale;
847 float _height_scale;
848};
849
Manuel Bottini3f9d4d72018-10-19 14:04:42 +0100850/** ROIAlign Layer */
851class ROIAlignLayer final : public ILayer
852{
853public:
854 /** Construct a RoiAlign layer.
855 *
856 * @param[in] sub_stream_input Graph sub-stream for the input
857 * @param[in] sub_stream_rois Graph sub-stream for the rois
858 * @param[in] pool_info Pooling information.
859 */
860 ROIAlignLayer(SubStream &&sub_stream_input, SubStream &&sub_stream_rois, ROIPoolingLayerInfo pool_info)
861 : _ss_input(sub_stream_input), _ss_rois(sub_stream_rois), _pool_info(pool_info)
862 {
863 }
864
865 /** Prevent instances of this class from being copy constructed */
866 ROIAlignLayer(const ROIAlignLayer &) = delete;
867 /** Prevent instances of this class from being copied */
868 ROIAlignLayer &operator=(const ROIAlignLayer &) = delete;
869
870 NodeID create_layer(IStream &s) override
871 {
872 NodeParams common_params = { name(), s.hints().target_hint };
873 NodeIdxPair input = { _ss_input.tail_node(), 0 };
874 NodeIdxPair rois = { _ss_rois.tail_node(), 0 };
875 return GraphBuilder::add_roi_align_node(s.graph(), common_params, input, rois, _pool_info);
876 }
877
878private:
879 SubStream _ss_input;
880 SubStream _ss_rois;
881 ROIPoolingLayerInfo _pool_info;
882};
883
Isabella Gottardi88d5b222018-04-06 12:24:55 +0100884/** Scale Layer */
885class ScaleLayer final : public ILayer
886{
887public:
888 /** Construct a scale layer.
889 *
890 * @param[in] mul_w Accessor to get mul weight from.
891 * @param[in] add_w Accessor to get add weight from.
892 */
893 ScaleLayer(ITensorAccessorUPtr mul_w,
894 ITensorAccessorUPtr add_w)
895 : _mul_w(std::move(mul_w)), _add_w(std::move(add_w))
896 {
897 }
898
899 NodeID create_layer(IStream &s) override
900 {
901 NodeParams common_params = { name(), s.hints().target_hint };
902 NodeIdxPair input = { s.tail_node(), 0 };
903 return GraphBuilder::add_scale_layer(s.graph(), common_params, input, std::move(_mul_w), std::move(_add_w));
904 }
905
906private:
907 ITensorAccessorUPtr _mul_w;
908 ITensorAccessorUPtr _add_w;
909};
910
Michele Di Giorgioc30b6682018-09-12 17:44:08 +0100911/** Slice Layer */
912class SliceLayer final : public ILayer
913{
914public:
915 /** Construct a slice layer.
916 *
917 * @param[in] starts The starts of the dimensions of the input tensor to be sliced. The length must be of rank(input).
918 * @param[in] ends The ends of the dimensions of the input tensor to be sliced. The length must be of rank(input).
919 */
920 SliceLayer(Coordinates &starts, Coordinates &ends)
921 : _starts(starts), _ends(ends)
922 {
923 }
924
925 NodeID create_layer(IStream &s) override
926 {
927 NodeParams common_params = { name(), s.hints().target_hint };
928 NodeIdxPair input = { s.tail_node(), 0 };
929 return GraphBuilder::add_slice_node(s.graph(), common_params, input, _starts, _ends);
930 }
931
932private:
933 Coordinates _starts;
934 Coordinates _ends;
935};
936
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000937/** Softmax Layer */
938class SoftmaxLayer final : public ILayer
939{
940public:
Alex Gildayc357c472018-03-21 13:54:09 +0000941 /** Construct a softmax layer.
942 *
943 * @param[in] beta (Optional) Beta value. Default 1.0.
944 */
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000945 SoftmaxLayer(float beta = 1.0f)
946 : _beta(beta)
947 {
948 }
949
950 NodeID create_layer(IStream &s) override
951 {
Georgios Pinitas5c2fb3f2018-05-01 15:26:20 +0100952 NodeParams common_params = { name(), s.hints().target_hint };
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000953 NodeIdxPair input = { s.tail_node(), 0 };
954 return GraphBuilder::add_softmax_node(s.graph(), common_params, input, _beta);
955 }
956
957private:
958 float _beta;
959};
Michalis Spyrou96f67692018-09-13 11:39:28 +0100960
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +0100961/** Upsample Layer */
962class UpsampleLayer final : public ILayer
963{
964public:
965 /** Construct a Upsample layer.
966 *
967 * @param[in] info Stride info
968 * @param[in] upsampling_policy Upsampling policy
969 */
970 UpsampleLayer(Size2D info, InterpolationPolicy upsampling_policy)
971 : _info(info), _upsampling_policy(upsampling_policy)
972 {
973 }
974
975 NodeID create_layer(IStream &s) override
976 {
977 NodeParams common_params = { name(), s.hints().target_hint };
978 NodeIdxPair input = { s.tail_node(), 0 };
979 return GraphBuilder::add_upsample_node(s.graph(), common_params, input, _info, _upsampling_policy);
980 }
981
982private:
983 Size2D _info;
984 InterpolationPolicy _upsampling_policy;
985};
986
Michalis Spyrou96f67692018-09-13 11:39:28 +0100987/** YOLO Layer */
988class YOLOLayer final : public ILayer
989{
990public:
991 /** Construct a YOLO layer.
992 *
993 * @param[in] act_info Activation info
994 * @param[in] num_classes Number of classes to activate
995 */
996 YOLOLayer(ActivationLayerInfo act_info, int32_t num_classes)
997 : _act_info(act_info), _num_classes(num_classes)
998 {
999 }
1000
1001 NodeID create_layer(IStream &s) override
1002 {
1003 NodeParams common_params = { name(), s.hints().target_hint };
1004 NodeIdxPair input = { s.tail_node(), 0 };
1005 return GraphBuilder::add_yolo_node(s.graph(), common_params, input, _act_info, _num_classes);
1006 }
1007
1008private:
1009 ActivationLayerInfo _act_info;
1010 int32_t _num_classes;
1011};
Georgios Pinitasd8734b52017-12-22 15:27:52 +00001012} // namespace frontend
Georgios Pinitasd9eb2752018-04-03 13:44:29 +01001013} // namespace graph
Georgios Pinitasd8734b52017-12-22 15:27:52 +00001014} // namespace arm_compute
Georgios Pinitasd9eb2752018-04-03 13:44:29 +01001015#endif /* __ARM_COMPUTE_GRAPH_LAYERS_H__ */