Release 18.02
[platform/upstream/armnn.git] / src / armnn / Layer.cpp
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // See LICENSE file in the project root for full license information.
4 //
5 #include "Layer.hpp"
6
7 #include "Graph.hpp"
8 #include "backends/WorkloadData.hpp"
9
10 #include <boost/cast.hpp>
11 #include <boost/format.hpp>
12 #include <boost/log/trivial.hpp>
13
14 #include <numeric>
15
16 namespace armnn
17 {
18
19 void InputSlot::Insert(Layer& layer)
20 {
21     BOOST_ASSERT(layer.GetNumInputSlots() <= 1);
22     BOOST_ASSERT(layer.GetNumOutputSlots() == 1);
23
24     OutputSlot* const prevSlot = GetConnectedOutputSlot();
25
26     if (prevSlot != nullptr)
27     {
28         // Disconnect parent from this
29         prevSlot->Disconnect(*this);
30
31         // Connect inserted layer to parent
32         BOOST_ASSERT(layer.GetNumInputSlots() == 1);
33         prevSlot->Connect(layer.GetInputSlot(0));
34
35         // Set tensor info for inserted layer
36         const TensorInfo& tensorInfo = prevSlot->GetTensorInfo();
37         layer.GetOutputHandler().SetTensorInfo(tensorInfo);
38     }
39
40     // Connect inserted layer to this
41     layer.GetOutputSlot(0).Connect(*this);
42 }
43
44 const InputSlot* OutputSlot::GetConnection(unsigned int index) const
45 {
46     ValidateConnectionIndex(index);
47     return m_Connections[index];
48 }
49
50 InputSlot* OutputSlot::GetConnection(unsigned int index)
51 {
52     ValidateConnectionIndex(index);
53     return m_Connections[index];
54 }
55
56 void OutputSlot::SetTensorInfo(const TensorInfo& tensorInfo)
57 {
58     GetOutputHandler().SetTensorInfo(tensorInfo);
59 }
60
61 const TensorInfo& OutputSlot::GetTensorInfo() const
62 {
63     return GetOutputHandler().GetTensorInfo();
64 }
65
66 bool OutputSlot::IsTensorInfoSet() const
67 {
68     return GetOutputHandler().IsTensorInfoSet();
69 }
70
71 bool OutputSlot::ValidateTensorShape(const TensorShape& shape) const
72 {
73     BOOST_ASSERT_MSG(IsTensorInfoSet(), "TensorInfo must be set in order to validate the shape.");
74     return shape == m_OutputHandler.GetTensorInfo().GetShape();
75 }
76
77 int OutputSlot::Connect(InputSlot& destination)
78 {
79     destination.SetConnection(this);
80     m_Connections.push_back(&destination);
81     return boost::numeric_cast<int>(m_Connections.size() - 1);
82 }
83
84 void OutputSlot::Disconnect(InputSlot& slot)
85 {
86     slot.SetConnection(nullptr);
87     m_Connections.erase(std::remove(m_Connections.begin(), m_Connections.end(), &slot), m_Connections.end());
88 }
89
90 void OutputSlot::DisconnectAll()
91 {
92     while (GetNumConnections() > 0)
93     {
94         InputSlot& connection = *GetConnection(0);
95         Disconnect(connection);
96     }
97 }
98
99 void OutputSlot::MoveAllConnections(OutputSlot& destination)
100 {
101     while (GetNumConnections() > 0)
102     {
103         InputSlot& connection = *GetConnection(0);
104         Disconnect(connection);
105         destination.Connect(connection);
106     }
107 }
108
109 void OutputSlot::ValidateConnectionIndex(unsigned int index) const
110 {
111     if (boost::numeric_cast<std::size_t>(index) >= m_Connections.size())
112     {
113         throw InvalidArgumentException(
114             boost::str(boost::format("GetConnection: Invalid index %1% provided") % index));
115     }
116 }
117
118 Layer::Layer(unsigned int numInputSlots, unsigned int numOutputSlots, LayerType type, const char* name)
119 : m_OutputHandlers(numOutputSlots)
120 , m_LayerName(name ? name : "")
121 , m_Type(type)
122 , m_ComputeDevice(Compute::Undefined)
123 {
124     m_InputSlots.reserve(numInputSlots);
125     for (unsigned int i = 0; i < numInputSlots; ++i)
126     {
127         m_InputSlots.emplace_back(*this, i);
128     }
129
130     m_OutputSlots.reserve(numOutputSlots);
131     for (unsigned int i = 0; i < numOutputSlots; ++i)
132     {
133         m_OutputSlots.emplace_back(*this, m_OutputHandlers[i]);
134     }
135 }
136
137 void Layer::CollectWorkloadInputs(WorkloadDataCollector& dataCollector, const Graph& graph) const
138 {
139     for (auto&& inputSlot : GetInputSlots())
140     {
141         // The graph must be well-formed at this point
142         BOOST_ASSERT(inputSlot.GetConnection());
143         const OutputHandler& outputHandler = inputSlot.GetConnectedOutputSlot()->GetOutputHandler();
144         dataCollector.Push(outputHandler.GetData(), outputHandler.GetTensorInfo());
145     }
146 }
147
148 void Layer::CollectWorkloadOutputs(WorkloadDataCollector& dataCollector, const Graph& graph) const
149 {
150     for (auto&& outputHandler : m_OutputHandlers)
151     {
152         outputHandler.CollectWorkloadOutputs(dataCollector);
153     }
154 }
155
156 void Layer::CreateTensorHandles(Graph& graph, const IWorkloadFactory& factory)
157 {
158     for (auto&& outputHandler : m_OutputHandlers)
159     {
160         outputHandler.CreateTensorHandles(factory);
161     }
162 }
163
164 DataType Layer::GetDataType() const
165 {
166     if (GetNumInputSlots() > 0) // Ignore the input layer
167     {
168         return GetInputSlot(0).GetConnection()->GetTensorInfo().GetDataType();
169     }
170     return DataType::Float32;
171 }
172
173 void Layer::ResetPriority() const
174 {
175     m_Priority = 0;
176     m_Visiting = false;
177 }
178
179 LayerPriority Layer::GetPriority() const
180 {
181     constexpr LayerPriority inputPrio = std::numeric_limits<LayerPriority>::lowest();
182     constexpr LayerPriority outputPrio = std::numeric_limits<LayerPriority>::max();
183
184     if (GetType() == LayerType::Input)
185     {
186         m_Priority = inputPrio;
187     }
188     else if (GetType() == LayerType::Output)
189     {
190         m_Priority = outputPrio;
191     }
192     else if (m_Priority == 0)
193     {
194         if (m_Visiting)
195         {
196             throw GraphValidationException("Graph has circular dependencies: cannot walk");
197         }
198
199         auto maxPrio = [](const LayerPriority prio, const InputSlot& slot) -> LayerPriority
200             {
201                 const Layer& input = slot.GetConnectedOutputSlot()->GetOwningLayer();
202                 return std::max(prio, input.GetPriority());
203             };
204
205         m_Visiting = true;
206         LayerPriority parentPrio = std::accumulate(GetInputSlots().cbegin(), GetInputSlots().cend(), 0U, maxPrio);
207         m_Visiting = false;
208
209         if (parentPrio >= outputPrio)
210         {
211             throw GraphValidationException("Graph has too many edges");
212         }
213
214         m_Priority = parentPrio + 1U;
215     }
216
217     return m_Priority;
218 }
219
220 } // namespace armnn