blob: 61639a8f6fea5248d89c7819f73c454b8f93f321 [file] [log] [blame]
Georgios Pinitasd8734b52017-12-22 15:27:52 +00001/*
Michele Di Giorgiod9eaf612020-07-08 11:12:57 +01002 * Copyright (c) 2018-2020 Arm Limited.
Georgios Pinitasd8734b52017-12-22 15:27:52 +00003 *
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#include "arm_compute/graph/mutators/InPlaceOperationMutator.h"
Georgios Pinitasd8734b52017-12-22 15:27:52 +000025
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010026#include "arm_compute/graph/Graph.h"
27#include "arm_compute/graph/Logger.h"
Georgios Pinitasd8734b52017-12-22 15:27:52 +000028
29namespace arm_compute
30{
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010031namespace graph
Georgios Pinitasd8734b52017-12-22 15:27:52 +000032{
Michele Di Giorgio294f6ff2020-06-19 12:11:06 +010033namespace
34{
35// Check if the output edges of the parent node are separate tensors. If not,
36// it means the same output is connected to multiple nodes and computations on
37// these nodes cannot be done in-place.
38bool output_edges_are_separate_tensors(Graph &g, const Edge *input_edge)
39{
40 const auto parent_node = input_edge->producer();
41 const auto input_tensor = input_edge->tensor();
42 const auto input_edge_id = input_edge->id();
43
44 if(parent_node == nullptr)
45 {
46 return false;
47 }
48
49 const auto output_edges = parent_node->output_edges();
50
51 // If the output is connected to only one edge, then computations can
52 // be done in-place.
53 if(output_edges.size() == 1)
54 {
55 return true;
56 }
57
58 return std::all_of(output_edges.begin(),
59 output_edges.end(),
60 [&](const EdgeID & edge_id)
61 {
62 // Skip check on current input edge
63 if(edge_id == input_edge_id)
64 {
65 return true;
66 }
67
68 auto edge = g.edge(edge_id);
69 return edge->tensor() != input_tensor;
70 });
71}
72} // namespace
73
Georgios Pinitasd8734b52017-12-22 15:27:52 +000074const char *InPlaceOperationMutator::name()
75{
76 return "InPlaceOperationMutator";
77}
78
Georgios Pinitasf4261ad2019-12-02 11:58:19 +000079IGraphMutator::MutationType InPlaceOperationMutator::type() const
80{
81 return IGraphMutator::MutationType::Backend;
82}
83
Georgios Pinitasd8734b52017-12-22 15:27:52 +000084void InPlaceOperationMutator::mutate(Graph &g)
85{
Michele Di Giorgio3be0b8c2020-06-18 15:28:54 +010086 std::set<NodeType> in_place_nodes =
87 {
88 NodeType::ActivationLayer,
89 NodeType::BatchNormalizationLayer,
90 NodeType::EltwiseLayer,
Manuel Bottini80feed52020-06-03 13:20:41 +010091 NodeType::UnaryEltwiseLayer,
Michele Di Giorgio3be0b8c2020-06-18 15:28:54 +010092 NodeType::PrintLayer
93 };
Georgios Pinitasd8734b52017-12-22 15:27:52 +000094
95 // Not interested in the order of nodes
96 for(auto &node : g.nodes())
97 {
98 if(node && in_place_nodes.find(node->type()) != std::end(in_place_nodes))
99 {
100 // Get input edge
101 Edge *input_edge = node->input_edge(0);
102
103 // Check if parent has a single output if yes then force in place calculation else not
Michele Di Giorgio294f6ff2020-06-19 12:11:06 +0100104 if((input_edge != nullptr) && output_edges_are_separate_tensors(g, input_edge))
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000105 {
Georgios Pinitasd3a78ab2018-06-18 15:35:09 +0100106 // Get current and new output tensors
107 auto current_output_tensor = node->output(0);
108 auto new_output_tensor = input_edge->tensor();
109
110 ARM_COMPUTE_ERROR_ON(current_output_tensor == nullptr || new_output_tensor == nullptr);
111
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000112 // Prevent in-place operation if there is an accessor bound to the in-place tensor or quantization info are different
Isabella Gottardi2ea37612019-07-16 11:48:51 +0100113 if(new_output_tensor->accessor() != nullptr || current_output_tensor->desc().quant_info != new_output_tensor->desc().quant_info)
114 {
115 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Prevented in-place operation as there is an accessor bound to the input tensor or the quantization info are different.\n");
116 }
117 else
Georgios Pinitasd3a78ab2018-06-18 15:35:09 +0100118 {
119 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Switching to in-place computation for the node with ID : "
120 << node->id() << " and name : " << node->name() << std::endl);
121 // Update accessor
122 new_output_tensor->set_accessor(current_output_tensor->extract_accessor());
123 // Update output
124 node->set_output_tensor(new_output_tensor->id(), 0);
125 }
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000126 }
127 }
128 }
129}
Georgios Pinitasd9eb2752018-04-03 13:44:29 +0100130} // namespace graph
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000131} // namespace arm_compute