24.02
|
Go to the documentation of this file.
39 template<
typename FactoryType>
41 const FactoryType& factory,
49 if (factory.SupportsSubTensors())
55 && ((concatAxis == numberOfDimensions - 1) || (concatAxis == numberOfDimensions - 2));
59 std::queue<ConcatLayer*> m_ConcatLayers;
61 m_ConcatLayers.push(
this);
62 while (!m_ConcatLayers.empty())
72 bool canUseSubTensorOnXorY =
true;
73 bool isTensorHandleFactory = std::is_same<armnn::ITensorHandleFactory, FactoryType>::value;
74 if (isTensorHandleFactory)
76 for (
unsigned int i = 0; i < numInputSlots; ++i)
80 std::vector<Capability> capabilities =
86 canUseSubTensorOnXorY =
false;
87 if (capabilities.empty())
89 canUseSubTensorOnXorY =
true;
96 && (PolymorphicDowncast<const Layer*>(currentLayer))->GetType() ==
LayerType::Concat)
98 canUseSubTensorOnXorY =
false;
101 if (!canUseSubTensorOnXorY)
108 std::vector<std::unique_ptr<ITensorHandle>> subTensors(0);
109 subTensors.reserve(numInputSlots);
110 for (
unsigned int i = 0; i < numInputSlots; ++i)
115 auto CreateSubTensor = [&]()
126 factoryId == slot->GetTensorHandleFactoryId() &&
129 slot->GetNumConnections() == 1 &&
130 canUseSubTensorOnXorY &&
135 return factory.CreateSubTensorHandle(*parentTensor,
140 return std::unique_ptr<ITensorHandle>();
143 auto subTensor = CreateSubTensor();
150 subTensors.push_back(std::move(subTensor));
155 if (subTensors.size() < numInputSlots)
162 for (
auto& subTensor : subTensors)
167 ARMNN_ASSERT_MSG(subTensor,
"ConcatLayer: Expected a valid sub-tensor for substitution.");
168 outputHandler.SetData(std::move(subTensor));
170 Layer& inputLayer = slot->GetOwningLayer();
174 m_ConcatLayers.push(PolymorphicDowncast<ConcatLayer*>(&inputLayer));
184 const bool isMemoryManaged)
191 CreateTensors(registry, workloadFactory, isMemoryManaged);
197 CreateTensors(registry, *handleFactory, isMemoryManaged);
211 for (
unsigned int i=0; i< inputShapes.size(); i++)
213 auto& inputShape = inputShapes[i];
215 ConditionalThrowIfNotEqual<LayerValidationException>(
216 "ConcatLayer: Num Dimensions must match all inputs.",
218 inputShape.GetNumDimensions());
222 std::vector<unsigned int> extentMin(numDims);
223 std::vector<unsigned int> extentMax(numDims);
224 for (
unsigned int i = 0; i < inputShapes.size(); i++)
228 for (
unsigned int d = 0; d < numDims; d++)
230 extentMin[d] = std::min(extentMin[d], origin[d]);
231 extentMax[d] = std::max(extentMax[d], origin[d] + shape[d]);
236 if (!std::all_of(extentMin.begin(), extentMin.end(), [](
unsigned int s) { return s == 0; }))
244 for (
unsigned int a = 0; a < inputShapes.size(); a++)
248 for (
unsigned int b = 0; b < a; b++)
253 bool allAxesOverlap =
true;
254 for (
unsigned int d = 0; d < numDims && allAxesOverlap; d++)
256 unsigned int a1 = aOrigin[d];
257 unsigned int a2 = aOrigin[d] + aShape[d];
259 unsigned int b1 = bOrigin[d];
260 unsigned int b2 = bOrigin[d] + bShape[d];
262 if (a2 <= b1 || b2 <= a1)
264 allAxesOverlap =
false;
277 unsigned int totalViewsVolume = 0;
278 for (
unsigned int i = 0; i < inputShapes.size(); i++)
280 totalViewsVolume += inputShapes[i].GetNumElements();
282 unsigned int outputVolume = 1;
283 for (
unsigned int d = 0; d < numDims; d++)
285 outputVolume *= (extentMax[d] - extentMin[d]);
288 ConditionalThrowIfNotEqual<LayerValidationException>(
289 "ConcatLayer: there are some gaps between views",
293 return std::vector<TensorShape>({
TensorShape({numDims, extentMax.data()}) });
299 ConditionalThrowIfNotEqual<LayerValidationException>(
300 "ConcatLayer: Num Inputs must match num views.",
310 std::vector<TensorShape> inputShapes;
#define ARMNN_ASSERT(COND)
unsigned int GetConcatAxis() const
Get the concatenation axis value.
uint32_t GetNumViews() const
Get the number of views.
This layer represents a merge operation.
const TensorInfo & GetTensorInfo() const override
const OutputHandler & GetOutputHandler() const
ConcatLayer * Clone(Graph &graph) const override
Creates a dynamically-allocated copy of this layer.
ITensorHandleFactory * GetFactory(ITensorHandleFactory::FactoryId id) const
Find a TensorHandleFactory by Id Returns nullptr if not found.
uint32_t GetNumDimensions() const
Get the number of dimensions.
void ValidateAndCopyShape(const TensorShape &outputShape, const TensorShape &inferredShape, const ShapeInferenceMethod shapeInferenceMethod, const std::string &layerName, const unsigned int outputSlotIndex=0)
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
virtual std::unique_ptr< IWorkload > CreateWorkload(const IWorkloadFactory &factory) const override
Makes a workload for the Concat type.
#define ARMNN_NO_DEPRECATE_WARN_BEGIN
std::vector< OutputHandler > m_OutputHandlers
#define ARMNN_ASSERT_MSG(COND, MSG)
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
const OriginsDescriptor & GetParameters() const override
ITensorHandle * GetData() const
Gets the allocated tensor memory.
Layer(unsigned int numInputSlots, unsigned int numOutputSlots, LayerType type, const char *name)
const char * GetName() const override
Returns the name of the layer.
static const FactoryId LegacyFactoryId
virtual std::vector< Capability > GetCapabilities(const IConnectableLayer *layer, const IConnectableLayer *connectedLayer, CapabilityClass capabilityClass)
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,...
Layer & GetOwningLayer() const
OriginsDescriptor m_Param
The parameters for the layer (not including tensor-valued weights etc.).
WorkloadInfo PrepInfoAndDesc(QueueDescriptor &descriptor) const
Helper function to reduce duplication in *Layer::CreateWorkload.
bool IsTypeSpaceMatch(const TensorInfo &other) const
Check that the types are the same and, if quantize, that the quantization parameters are the same.
void ValidateTensorShapesFromInputs() override
Check if the input tensor shape(s) will lead to a valid configuration of ConcatLayer.
const OutputHandler & GetOutputHandler(unsigned int i=0) const
void VerifyShapeInferenceType(const TensorShape &outputShape, ShapeInferenceMethod shapeInferenceMethod)
void SetAdditionalInfo(QueueDescriptor &descriptor) const
virtual void CreateTensorHandles(const TensorHandleFactoryRegistry ®istry, 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...
void ExecuteStrategy(IStrategy &strategy) const override
Apply a visitor to this layer.
unsigned int GetNumInputSlots() const override
Returns the number of connectable input slots.
const TensorShape & GetShape() const
#define ARMNN_NO_DEPRECATE_WARN_END
std::vector< ViewOrigin > m_ViewOrigins
An OriginsDescriptor for the ConcatLayer.
ITensorHandleFactory::FactoryId GetTensorHandleFactoryId() const
Copyright (c) 2021 ARM Limited and Contributors.
void VerifyLayerConnections(unsigned int expectedConnections, const CheckLocation &location) const
const TensorInfo & GetTensorInfo() const
Gets the matching TensorInfo for the output.
const uint32_t * GetViewOrigin(uint32_t idx) const
Return the view origin at the int value idx.
ShapeInferenceMethod m_ShapeInferenceMethod
LayerType
When adding a new layer, adapt also the LastLayer enum value in the enum class LayerType below.
const InputSlot * GetConnection(unsigned int index) const override
ConcatLayer(const OriginsDescriptor ¶m, const char *name)
Constructor to create a ConcatLayer.
virtual std::unique_ptr< IWorkload > CreateWorkload(LayerType type, const QueueDescriptor &descriptor, const WorkloadInfo &info) const =0
Backends should implement their own CreateWorkload function with a switch statement.
virtual void ExecuteStrategy(const IConnectableLayer *layer, const armnn::BaseDescriptor &descriptor, const std::vector< armnn::ConstTensor > &constants, const char *name, const armnn::LayerBindingId id=0)=0