Compute Library
 21.05
DepthConcatSubTensorMutator.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2020 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  */
25 
32 
33 #include "support/Cast.h"
34 #include "support/Iterable.h"
35 
36 namespace arm_compute
37 {
38 namespace graph
39 {
41 {
42  return "DepthConcatSubTensorMutator";
43 }
44 
46 {
48 }
49 
51 {
52  // Early exit if no Concatenation layers exist in graph
53  if(g.nodes(NodeType::ConcatenateLayer).empty())
54  {
55  return;
56  }
57 
58  // Perform topological sort
59  std::vector<NodeID> topological_sorted_node_ids = dfs(g);
60 
61  // Should be in reverse order of execution
62  for(auto &node_id : arm_compute::utils::iterable::reverse_iterate(topological_sorted_node_ids))
63  {
64  INode *node = g.node(node_id);
65  if(node != nullptr && node->type() == NodeType::ConcatenateLayer && node->output(0) != nullptr)
66  {
67  // Get output tensor
68  auto output_tensor = node->output(0);
69 
70  // Check concatenation axis (Sub-tensor optimization is supported for concatenation axis >=2)
71  auto *concat_node = arm_compute::utils::cast::polymorphic_downcast<ConcatenateLayerNode *>(node);
72  if(output_tensor == nullptr || get_dimension_idx(output_tensor->desc().layout, concat_node->concatenation_axis()) < 2)
73  {
74  continue;
75  }
76 
77  // Check that all tensor have the same target, valid inputs and same quantization info
78  bool is_valid = std::all_of(node->input_edges().cbegin(), node->input_edges().cend(),
79  [&](const EdgeID & eid)
80  {
81  return (g.edge(eid) != nullptr) && (g.edge(eid)->tensor() != nullptr) && (g.edge(eid)->tensor()->desc().target == output_tensor->desc().target)
82  && (g.edge(eid)->tensor()->desc().quant_info == output_tensor->desc().quant_info);
83  });
84 
85  // Create subtensors
86  if(is_valid && is_target_supported(output_tensor->desc().target))
87  {
88  ARM_COMPUTE_LOG_GRAPH_VERBOSE("Using sub-tensors for the node with ID : "
89  << node->id() << " and name : " << node->name() << std::endl);
90  // Create sub-tensor handles
91  unsigned depth = 0;
92  for(unsigned int i = 0; i < node->input_edges().size(); ++i)
93  {
94  auto input_tensor = node->input(i);
95  const auto input_shape = input_tensor->desc().shape;
96 
97  backends::IDeviceBackend &backend = backends::BackendRegistry::get().get_backend(input_tensor->desc().target);
98  std::unique_ptr<ITensorHandle> handle = backend.create_subtensor(output_tensor->handle(), input_shape, Coordinates(0, 0, depth), false);
99  input_tensor->set_handle(std::move(handle));
100 
101  depth += input_shape.z();
102  }
103 
104  auto *dc_node = arm_compute::utils::cast::polymorphic_downcast<ConcatenateLayerNode *>(node);
105  dc_node->set_enabled(false);
106  }
107  }
108  }
109 }
110 } // namespace graph
111 } // namespace arm_compute
std::string name() const
Returns node's name.
Definition: INode.cpp:107
Tensor * tensor() const
Returns the tensor associated with this edge.
Definition: Edge.h:116
IDeviceBackend & get_backend(Target target)
Get a backend from the registry.
Copyright (c) 2017-2021 Arm Limited.
TensorDescriptor & desc()
TensorInfo metadata accessor.
Definition: Tensor.cpp:40
QuantizationInfo quant_info
Quantization info.
TensorShape input_shape
Validate test suite is to test ARM_COMPUTE_RETURN_ON_* macros we use to check the validity of given a...
Node interface.
Definition: INode.h:45
const std::vector< EdgeID > & input_edges() const
Returns input edge set.
Definition: INode.cpp:127
Tensor * output(size_t idx) const
Returns the tensor of a given output of the node.
Definition: INode.cpp:158
T z() const
Alias to access the size of the third dimension.
Definition: Dimensions.h:97
Coordinates of an item.
Definition: Coordinates.h:37
bool is_target_supported(Target target)
Checks if a specific target is supported.
Definition: Utils.cpp:34
NodeID id() const
Returns node's ID.
Definition: INode.cpp:102
static BackendRegistry & get()
Gets backend registry instance.
std::vector< NodeID > dfs(Graph &g)
Depth first search traversal.
virtual std::unique_ptr< ITensorHandle > create_subtensor(ITensorHandle *parent, TensorShape shape, Coordinates coords, bool extend_parent)=0
Create a backend Sub-Tensor.
unsigned int EdgeID
Definition: Types.h:69
Graph class.
Definition: Graph.h:53
const std::vector< NodeID > & nodes(NodeType type)
Returns graph input nodes.
Definition: Graph.cpp:174
const INode * node(NodeID id) const
Get node object given its id.
Definition: Graph.cpp:204
#define ARM_COMPUTE_LOG_GRAPH_VERBOSE(x)
Definition: Logger.h:50
const Edge * edge(EdgeID id) const
Get edge object given its id.
Definition: Graph.cpp:214
const char * name() override
Returns mutator name.
virtual NodeType type() const =0
Returns node's type.
reverse_iterable< T > reverse_iterate(T &val)
Creates a reverse iterable for a given type.
Definition: Iterable.h:101
MutationType type() const override
Returns mutation type.
Tensor * input(size_t idx) const
Returns the tensor of a given input of the node.
Definition: INode.cpp:150
size_t get_dimension_idx(DataLayout data_layout, const DataLayoutDimension data_layout_dimension)
Get index of a tensor's given dimension depending on its layout.
Definition: Utils.cpp:137
virtual void mutate(Graph &g) override
Walk the graph and perform a specific mutation.