Release 18.02
[platform/upstream/armnn.git] / src / armnn / Layer.hpp
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // See LICENSE file in the project root for full license information.
4 //
5 #pragma once
6
7 #include "LayerFwd.hpp"
8
9 #include "backends/OutputHandler.hpp"
10 #include "backends/WorkloadDataCollector.hpp"
11 #include "backends/WorkloadInfo.hpp"
12 #include "InternalTypes.hpp"
13
14 #include <armnn/Types.hpp>
15 #include <armnn/Tensor.hpp>
16 #include <armnn/INetwork.hpp>
17
18 #include <algorithm>
19 #include <memory>
20 #include <string>
21 #include <vector>
22
23 #include <boost/numeric/conversion/cast.hpp>
24 #include <boost/core/ignore_unused.hpp>
25 #include <boost/cast.hpp>
26
27 namespace armnn
28 {
29
30 class IWorkload;
31 class IWorkloadFactory;
32 class Layer;
33 class Graph;
34
35 class InputSlot final : public IInputSlot
36 {
37 public:
38     explicit InputSlot(Layer& owner, unsigned int slotIndex)
39     : m_OwningLayer(owner)
40     , m_Connection(nullptr)
41     , m_SlotIndex(slotIndex)
42     {}
43
44     ~InputSlot();
45
46     Layer& GetOwningLayer() const { return m_OwningLayer; }
47     unsigned int GetSlotIndex() const { return m_SlotIndex; }
48
49     const OutputSlot* GetConnectedOutputSlot() const { return m_Connection; }
50     OutputSlot* GetConnectedOutputSlot() { return m_Connection; }
51
52     /// Links the slot to an output slot or breaks an existing link if passing nullptr
53     void SetConnection(OutputSlot* source)
54     {
55         if (m_Connection != nullptr && source != nullptr)
56         {
57             throw InvalidArgumentException("Tried to connect an output slot to an input slot, "
58                 "but the latter already has a connection");
59         }
60         m_Connection = source;
61     }
62
63     // Insert single-output existing layer at this point in the graph.
64     void Insert(Layer& layer);
65
66     // IInputSlot
67
68     const IOutputSlot* GetConnection() const override;
69     IOutputSlot* GetConnection() override;
70
71 private:
72     Layer& m_OwningLayer;
73     OutputSlot* m_Connection;
74     const unsigned int m_SlotIndex;
75 };
76
77 class OutputSlot final : public IOutputSlot
78 {
79 public:
80     explicit OutputSlot(Layer& owner, OutputHandler& outputHandler)
81     : m_OwningLayer(owner)
82     , m_OutputHandler(outputHandler)
83     {}
84
85     ~OutputSlot()
86     {
87         DisconnectAll();
88     }
89
90     Layer& GetOwningLayer() const { return m_OwningLayer; }
91
92     const OutputHandler& GetOutputHandler() const { return m_OutputHandler; }
93     OutputHandler& GetOutputHandler() { return m_OutputHandler; }
94
95     int Connect(InputSlot& destination);
96     void Disconnect(InputSlot& slot);
97
98     const std::vector<InputSlot*>& GetConnections() const { return m_Connections; }
99
100     bool ValidateTensorShape(const TensorShape& shape) const;
101
102     // Disconnect all conections
103     void DisconnectAll();
104
105     /// Move all connections to another OutputSlot
106     void MoveAllConnections(OutputSlot& destination);
107
108     // IOutputSlot
109
110     unsigned int GetNumConnections() const override { return boost::numeric_cast<unsigned int>(m_Connections.size()); }
111     const InputSlot* GetConnection(unsigned int index) const override;
112     InputSlot* GetConnection(unsigned int index) override;
113
114     void SetTensorInfo(const TensorInfo& tensorInfo) override;
115     const TensorInfo& GetTensorInfo() const override;
116     bool IsTensorInfoSet() const override;
117
118     int Connect(IInputSlot& destination) override
119     {
120         return Connect(*boost::polymorphic_downcast<InputSlot*>(&destination));
121     }
122
123     void Disconnect(IInputSlot& slot) override
124     {
125         return Disconnect(*boost::polymorphic_downcast<InputSlot*>(&slot));
126     }
127
128 private:
129     void ValidateConnectionIndex(unsigned int index) const;
130
131     Layer& m_OwningLayer;
132     OutputHandler& m_OutputHandler;
133     std::vector<InputSlot*> m_Connections;
134 };
135
136 // InputSlot inlines that need OutputSlot declaration
137
138 inline InputSlot::~InputSlot()
139 {
140     if (m_Connection != nullptr)
141     {
142         m_Connection->Disconnect(*this);
143     }
144 }
145
146 inline const IOutputSlot* InputSlot::GetConnection() const { return GetConnectedOutputSlot(); }
147 inline IOutputSlot* InputSlot::GetConnection() { return GetConnectedOutputSlot(); }
148
149 // Base layer class
150
151 using LayerPriority = unsigned int;
152
153 class Layer : public IConnectableLayer
154 {
155 public:
156     /// @param name Optional name for the layer (may be nullptr)
157     Layer(unsigned int numInputSlots, unsigned int numOutputSlots, LayerType type, const char* name);
158
159     const std::string& GetNameStr() const
160     {
161         return m_LayerName;
162     }
163
164     const OutputHandler& GetOutputHandler(unsigned int i = 0) const
165     {
166         return m_OutputHandlers[i];
167     }
168
169     OutputHandler& GetOutputHandler(unsigned int i = 0)
170     {
171         return const_cast<OutputHandler&>(const_cast<const Layer*>(this)->GetOutputHandler(i));
172     }
173
174     const std::vector<InputSlot>& GetInputSlots() const { return m_InputSlots; }
175     const std::vector<OutputSlot>& GetOutputSlots() const { return m_OutputSlots; }
176
177     // Allow non-const access to input slots, but don't expose vector (vector size is fixed at layer construction).
178     std::vector<InputSlot>::iterator BeginInputSlots() { return m_InputSlots.begin(); }
179     std::vector<InputSlot>::iterator EndInputSlots() { return m_InputSlots.end(); }
180
181     // Allow non-const access to output slots, but don't expose vector (vector size is fixed at layer construction).
182     std::vector<OutputSlot>::iterator BeginOutputSlots() { return m_OutputSlots.begin(); }
183     std::vector<OutputSlot>::iterator EndOutputSlots() { return m_OutputSlots.end(); }
184
185     // Check whether the outputs of this layer don't have any connection
186     bool IsOutputUnconnected()
187     {
188         unsigned int numConnections = 0;
189
190         for (auto&& output : GetOutputSlots())
191         {
192             numConnections += output.GetNumConnections();
193         }
194
195         return (GetNumOutputSlots() > 0) && (numConnections == 0);
196     }
197
198     // Used for sorting
199     void ResetPriority() const;
200     LayerPriority GetPriority() const;
201
202     LayerType GetType() const { return m_Type; }
203
204     DataType GetDataType() const;
205
206     Compute GetComputeDevice() const { return m_ComputeDevice; }
207     void SetComputeDevice(Compute device) { m_ComputeDevice = device; }
208
209     // Virtuals
210
211     virtual std::unique_ptr<IWorkload> CreateWorkload(const Graph& graph, const IWorkloadFactory& factory) const = 0;
212
213     virtual void CreateTensorHandles(Graph& graph, const IWorkloadFactory& factory);
214
215     /// Creates a dynamically-allocated copy of this layer
216     /// @param graph The Graph into which this Layer is being cloned
217     virtual Layer* Clone(Graph& graph) const = 0;
218
219     virtual void ValidateTensorShapesFromInputs() = 0;
220
221     // IConnectableLayer
222
223     const char* GetName() const override { return m_LayerName.c_str(); }
224
225     unsigned int GetNumInputSlots() const override { return static_cast<unsigned int>(m_InputSlots.size()); }
226     unsigned int GetNumOutputSlots() const override { return static_cast<unsigned int>(m_OutputSlots.size()); }
227
228     const InputSlot& GetInputSlot(unsigned int index) const override { return m_InputSlots.at(index); }
229     InputSlot& GetInputSlot(unsigned int index) override { return  m_InputSlots.at(index); }
230     const OutputSlot& GetOutputSlot(unsigned int index = 0) const override { return m_OutputSlots.at(index); }
231     OutputSlot& GetOutputSlot(unsigned int index = 0) override { return m_OutputSlots.at(index); }
232
233 protected:
234     // Graph needs access to the virtual destructor
235     friend class Graph;
236     virtual ~Layer() = default;
237
238     template <typename QueueDescriptor>
239     void CollectQueueDescriptorInputs(QueueDescriptor& descriptor, WorkloadInfo& info, const Graph& graph) const
240     {
241         WorkloadDataCollector dataCollector(descriptor.m_Inputs, info.m_InputTensorInfos);
242         CollectWorkloadInputs(dataCollector, graph);
243     }
244
245     template <typename QueueDescriptor>
246     void CollectQueueDescriptorOutputs(QueueDescriptor& descriptor, WorkloadInfo& info, const Graph& graph) const
247     {
248         WorkloadDataCollector dataCollector(descriptor.m_Outputs, info.m_OutputTensorInfos);
249         CollectWorkloadOutputs(dataCollector, graph);
250     }
251
252     /// Helper function to reduce duplication in *Layer::CreateWorkload
253     template <typename QueueDescriptor>
254     WorkloadInfo PrepInfoAndDesc(QueueDescriptor& descriptor, const Graph& graph) const
255     {
256         WorkloadInfo info;
257         CollectQueueDescriptorInputs(descriptor, info, graph);
258         CollectQueueDescriptorOutputs(descriptor, info, graph);
259         return info;
260     }
261
262     template <typename LayerType, typename ... Params>
263     LayerType* CloneBase(Graph& graph, Params&& ... params) const;
264
265 private:
266     void CollectWorkloadInputs(WorkloadDataCollector& dataCollector, const Graph& graph) const;
267     void CollectWorkloadOutputs(WorkloadDataCollector& dataCollector, const Graph& graph) const;
268
269 protected:
270     std::vector<OutputHandler> m_OutputHandlers;
271
272 private:
273     const std::string m_LayerName;
274
275     std::vector<InputSlot> m_InputSlots;
276     std::vector<OutputSlot> m_OutputSlots;
277
278     const LayerType m_Type;
279     Compute m_ComputeDevice;
280
281     /// Used for sorting
282     mutable LayerPriority m_Priority = 0;
283     mutable bool m_Visiting = false;
284 };
285
286 // A layer user-provided data can be bound to (e.g. inputs, outputs)
287 class BindableLayer : public Layer
288 {
289 public:
290     BindableLayer(unsigned int numInputSlots,
291         unsigned int numOutputSlots,
292         LayerType type,
293         const char* name,
294         LayerBindingId id)
295     : Layer(numInputSlots, numOutputSlots, type, name)
296     , m_Id(id)
297     {
298     }
299
300     LayerBindingId GetBindingId() const { return m_Id; };
301
302 protected:
303     ~BindableLayer() = default;
304
305 private:
306     LayerBindingId m_Id;
307 };
308
309 }