ArmNN
 20.02
SplitterLayer.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 #include "SplitterLayer.hpp"
6 
7 #include "LayerCloneBase.hpp"
8 
9 #include <armnn/TypesUtils.hpp>
12 
13 namespace armnn
14 {
15 
16 SplitterLayer::SplitterLayer(const ViewsDescriptor& param, const char* name)
17  : LayerWithParameters(1, param.GetNumViews(), LayerType::Splitter, param, name)
18 {
19 }
20 
21 std::unique_ptr<IWorkload> SplitterLayer::CreateWorkload(const IWorkloadFactory& factory) const
22 {
23  SplitterQueueDescriptor descriptor;
24 
25  // Copies the window origins to the descriptor.
26  for (unsigned int i = 0; i < m_Param.GetNumViews(); ++i)
27  {
28  descriptor.m_ViewOrigins.emplace_back(
29  std::vector<unsigned int>(m_Param.GetViewOrigin(i), m_Param.GetViewOrigin(i) + m_Param.GetNumDimensions()));
30  }
31 
32  return factory.CreateSplitter(descriptor, PrepInfoAndDesc(descriptor));
33 }
34 
35 template<typename FactoryType>
36 void SplitterLayer::CreateTensors(const FactoryType& factory)
37 {
38  //If sub tensors are supported than all the "splitter" need to do is to
39  //set the outputs to be appropriate sub tensors of the input.
40  bool useSubTensors = factory.SupportsSubTensors();
41 
42  if (useSubTensors)
43  {
44  const OutputSlot* slot = GetInputSlots()[0].GetConnectedOutputSlot();
45  const OutputHandler& outputHandler = GetInputSlots()[0].GetConnectedOutputSlot()->GetOutputHandler();
46 
47  const TensorInfo& parentInfo = outputHandler.GetTensorInfo();
48 
49  ITensorHandle* inputData = outputHandler.GetData();
50 
51  std::vector<std::unique_ptr<ITensorHandle>> subTensors;
52 
53  //Creates the outputs as subtensors of the input.
54  for (unsigned int i = 0; i < m_Param.GetNumViews(); ++i)
55  {
56  const TensorInfo& info = m_OutputHandlers[i].GetTensorInfo();
57 
58  OutputSlot& outSlot = GetOutputSlot(i);
60  auto CreateSubTensor = [&]()
61  {
62  // Make sure quantization parameters are in the same space
63  if (parentInfo.IsTypeSpaceMatch(info) &&
64  factoryId == slot->GetTensorHandleFactoryId())
65  {
66  return factory.CreateSubTensorHandle(*inputData,
67  info.GetShape(),
68  this->m_Param.GetViewOrigin(i));
69  }
70  return std::unique_ptr<ITensorHandle>();
71  };
72 
73  auto subTensor = CreateSubTensor();
74  if (!subTensor)
75  {
76  useSubTensors = false;
77  break; //Failed to create a valid sub-tensor, so stop trying with the rest of the views.
78  }
79  subTensors.push_back(std::move(subTensor));
80  }
81 
82  if (useSubTensors)
83  {
84  unsigned int i = 0;
85  for (auto& subTensor : subTensors)
86  {
87  m_OutputHandlers[i].SetData(std::move(subTensor));
88  ++i;
89  }
90 
91  }
92  }
93 
94  if (!useSubTensors)
95  {
96  for (unsigned int i = 0; i < m_Param.GetNumViews(); ++i)
97  {
98  m_OutputHandlers[i].CreateTensorHandles(factory);
99  }
100  }
101 }
102 
104  const IWorkloadFactory& workloadFactory,
105  const bool IsMemoryManaged)
106 {
107  IgnoreUnused(IsMemoryManaged);
108  OutputSlot& slot = GetOutputSlot(0);
110 
111  if (factoryId == ITensorHandleFactory::LegacyFactoryId)
112  {
113  CreateTensors(workloadFactory);
114  }
115  else
116  {
117  ITensorHandleFactory* handleFactory = registry.GetFactory(factoryId);
118  BOOST_ASSERT(handleFactory);
119  CreateTensors(*handleFactory);
120  }
121 }
122 
124 {
125  return CloneBase<SplitterLayer>(graph, m_Param, GetName());
126 }
127 
128 std::vector<TensorShape> SplitterLayer::InferOutputShapes(const std::vector<TensorShape>& inputShapes) const
129 {
130  IgnoreUnused(inputShapes);
131  BOOST_ASSERT(inputShapes.size() == m_Param.GetNumViews());
132  std::vector<TensorShape> outShapes;
133  //Output shapes must match View shapes.
134  for (unsigned int viewIdx = 0; viewIdx < m_Param.GetNumViews(); viewIdx++)
135  {
136  const uint32_t* sizes = m_Param.GetViewSizes(viewIdx);
137  outShapes.push_back(TensorShape(m_Param.GetNumDimensions(), sizes));
138  }
139  return outShapes;
140 }
141 
143 {
144  std::vector<TensorShape> views;
145  for (unsigned int viewIdx = 0; viewIdx < m_Param.GetNumViews(); viewIdx++)
146  {
147  const uint32_t* sizes = m_Param.GetViewSizes(viewIdx);
148  views.push_back(TensorShape(m_Param.GetNumDimensions(), sizes));
149  }
150 
151  auto inferredShapes = InferOutputShapes(views);
152 
153  BOOST_ASSERT(inferredShapes.size() == m_Param.GetNumViews());
154 
155  for (unsigned int viewIdx = 0; viewIdx < m_Param.GetNumViews(); viewIdx++)
156  {
157  ConditionalThrowIfNotEqual<LayerValidationException>(
158  "SplitterLayer: View sizes must match output tensor shapes.",
159  GetOutputSlot(viewIdx).GetTensorInfo().GetShape(),
160  inferredShapes[viewIdx]);
161  }
162 }
163 
165 {
166  visitor.VisitSplitterLayer(this, GetParameters(), GetName());
167 }
168 
169 } // namespace armnn
virtual std::unique_ptr< IWorkload > CreateSplitter(const SplitterQueueDescriptor &descriptor, const WorkloadInfo &info) const
SplitterLayer(const ViewsDescriptor &param, const char *name)
Constructor to create a SplitterLayer.
This layer represents a split operation.
virtual void CreateTensorHandles(const TensorHandleFactoryRegistry &registry, const IWorkloadFactory &factory, const bool IsMemoryManaged=true) override
Set the outputs to be appropriate sub tensors of the input if sub tensors are supported otherwise cre...
A ViewsDescriptor for the SplitterLayer.
bool IsTypeSpaceMatch(const TensorInfo &other) const
Check that the types are the same and, if quantize, that the quantization parameters are the same...
Definition: Tensor.cpp:218
ViewsDescriptor m_Param
The parameters for the layer (not including tensor-valued weights etc.).
const TensorShape & GetShape() const
Definition: Tensor.hpp:88
uint32_t GetNumDimensions() const
Get the number of dimensions.
std::vector< TensorShape > InferOutputShapes(const std::vector< TensorShape > &inputShapes) const override
By default returns inputShapes if the number of inputs are equal to number of outputs, otherwise infers the output shapes from given input shapes and layer properties.
uint32_t GetNumViews() const
Get the number of views.
Copyright (c) 2020 ARM Limited.
void IgnoreUnused(Ts &&...)
const std::vector< InputSlot > & GetInputSlots() const
Definition: Layer.hpp:231
void Accept(ILayerVisitor &visitor) const override
Apply a visitor to this layer.
ITensorHandle * GetData() const
Gets the allocated tensor memory.
std::vector< OutputHandler > m_OutputHandlers
Definition: Layer.hpp:371
std::vector< ViewOrigin > m_ViewOrigins
const uint32_t * GetViewOrigin(uint32_t idx) const
Get the view origin at the int value idx.
const uint32_t * GetViewSizes(uint32_t idx) const
Get the view sizes at the int value idx.
virtual void VisitSplitterLayer(const IConnectableLayer *layer, const ViewsDescriptor &splitterDescriptor, const char *name=nullptr)=0
Function that a splitter layer should call back to when its Accept(ILayerVisitor&) function is invoke...
ClWorkloadFactory FactoryType
ITensorHandleFactory * GetFactory(ITensorHandleFactory::FactoryId id) const
Find a TensorHandleFactory by Id Returns nullptr if not found.
WorkloadInfo PrepInfoAndDesc(QueueDescriptor &descriptor) const
Helper function to reduce duplication in *LayerCreateWorkload.
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:312
const char * GetName() const override
Returns the name of the layer.
Definition: Layer.hpp:305
ITensorHandleFactory::FactoryId GetTensorHandleFactoryId() const
Definition: Layer.cpp:172
void ValidateTensorShapesFromInputs() override
Check if the input tensor shape(s) will lead to a valid configuration of SplitterLayer.
void Splitter(const SplitterQueueDescriptor &data)
Definition: Splitter.hpp:17
const TensorInfo & GetTensorInfo() const override
Definition: Layer.cpp:63
static const FactoryId LegacyFactoryId
SplitterLayer * Clone(Graph &graph) const override
Creates a dynamically-allocated copy of this layer.
virtual std::unique_ptr< IWorkload > CreateWorkload(const IWorkloadFactory &factory) const override
Makes a workload for the Splitter type.
const TensorInfo & GetTensorInfo() const
Gets the matching TensorInfo for the output.