37 template<
typename FactoryType>
38 void ConcatLayer::CreateTensors(
const FactoryType& factory)
45 if (factory.SupportsSubTensors())
49 std::queue<ConcatLayer*> m_ConcatLayers;
51 m_ConcatLayers.push(
this);
52 while (!m_ConcatLayers.empty())
62 std::vector<std::unique_ptr<ITensorHandle>> subTensors(0);
63 subTensors.reserve(numInputSlots);
64 for (
unsigned int i = 0; i < numInputSlots; ++i)
69 auto CreateSubTensor = [&]()
83 return factory.CreateSubTensorHandle(*parentTensor,
87 return std::unique_ptr<ITensorHandle>();
90 auto subTensor = CreateSubTensor();
97 subTensors.push_back(std::move(subTensor));
102 if (subTensors.size() < numInputSlots)
109 for (
auto& subTensor : subTensors)
114 BOOST_ASSERT_MSG(subTensor,
"ConcatLayer: Expected a valid sub-tensor for substitution.");
115 outputHandler.
SetData(std::move(subTensor));
121 m_ConcatLayers.push(boost::polymorphic_downcast<ConcatLayer*>(&inputLayer));
131 const bool IsMemoryManaged)
133 boost::ignore_unused(IsMemoryManaged);
139 CreateTensors(workloadFactory);
144 BOOST_ASSERT(handleFactory);
145 CreateTensors(*handleFactory);
159 for (
unsigned int i=0; i< inputShapes.size(); i++)
161 auto& inputShape = inputShapes[i];
163 ConditionalThrowIfNotEqual<LayerValidationException>(
164 "ConcatLayer: Num Dimensions must match all inputs.",
166 inputShape.GetNumDimensions());
170 std::vector<unsigned int> extentMin(numDims);
171 std::vector<unsigned int> extentMax(numDims);
172 for (
unsigned int i = 0; i < inputShapes.size(); i++)
176 for (
unsigned int d = 0; d < numDims; d++)
178 extentMin[d] = std::min(extentMin[d], origin[d]);
179 extentMax[d] = std::max(extentMax[d], origin[d] + shape[d]);
184 if (!std::all_of(extentMin.begin(), extentMin.end(), [](
unsigned int s) {
return s == 0; }))
192 for (
unsigned int a = 0; a < inputShapes.size(); a++)
196 for (
unsigned int b = 0; b < a; b++)
201 bool allAxesOverlap =
true;
202 for (
unsigned int d = 0; d < numDims && allAxesOverlap; d++)
204 unsigned int a1 = aOrigin[d];
205 unsigned int a2 = aOrigin[d] + aShape[d];
207 unsigned int b1 = bOrigin[d];
208 unsigned int b2 = bOrigin[d] + bShape[d];
210 if (a2 <= b1 || b2 <= a1)
212 allAxesOverlap =
false;
225 unsigned int totalViewsVolume = 0;
226 for (
unsigned int i = 0; i < inputShapes.size(); i++)
228 totalViewsVolume += inputShapes[i].GetNumElements();
230 unsigned int outputVolume = 1;
231 for (
unsigned int d = 0; d < numDims; d++)
233 outputVolume *= (extentMax[d] - extentMin[d]);
236 ConditionalThrowIfNotEqual<LayerValidationException>(
237 "ConcatLayer: there are some gaps between views",
241 return std::vector<TensorShape>({
TensorShape({numDims, extentMax.data()}) });
247 ConditionalThrowIfNotEqual<LayerValidationException>(
248 "ConcatLayer: Num Inputs must match num views.",
254 std::vector<TensorShape> inputShapes;
262 BOOST_ASSERT(inferredShapes.size() == 1);
264 ConditionalThrowIfNotEqual<LayerValidationException>(
265 "ConcatLayer: TensorShape set on OutputSlot[0] does not match the inferred shape.",
const OutputHandler & GetOutputHandler(unsigned int i=0) const
LayerType GetType() const
ConcatLayer(const OriginsDescriptor ¶m, const char *name)
const char * GetName() const override
virtual void VisitConcatLayer(const IConnectableLayer *layer, const OriginsDescriptor &concatDescriptor, const char *name=nullptr)
ITensorHandleFactory::FactoryId GetTensorHandleFactoryId() const
std::vector< TensorShape > InferOutputShapes(const std::vector< TensorShape > &inputShapes) const override
const TensorInfo & GetTensorInfo() const
Gets the matching TensorInfo for the output.
This layer represents a merge operation.
static const FactoryId LegacyFactoryId
virtual std::unique_ptr< IWorkload > CreateWorkload(const IWorkloadFactory &factory) const override
void ValidateTensorShapesFromInputs() override
std::vector< ViewOrigin > m_ViewOrigins
ITensorHandleFactory * GetFactory(ITensorHandleFactory::FactoryId id) const
void SetData(std::unique_ptr< ITensorHandle > data)
unsigned int GetNumConnections() const override
virtual std::unique_ptr< IWorkload > CreateConcat(const ConcatQueueDescriptor &descriptor, const WorkloadInfo &info) const
const OriginsDescriptor & GetParameters() const
bool IsTypeSpaceMatch(const TensorInfo &other) const
Check that the types are the same and, if quantize, that the quantization parameters are the same...
const uint32_t * GetViewOrigin(uint32_t idx) const
Return the view origin at the int value idx.
uint32_t GetNumViews() const
Get the number of views.
const OutputHandler & GetOutputHandler() const
uint32_t GetNumDimensions() const
Get the number of dimensions.
OriginsDescriptor m_Param
The parameters for the layer (not including tensor-valued weights etc.).
void VerifyLayerConnections(unsigned int expectedConnections, const CheckLocation &location) const
WorkloadInfo PrepInfoAndDesc(QueueDescriptor &descriptor) const
Helper function to reduce duplication in *LayerCreateWorkload.
ClWorkloadFactory FactoryType
std::vector< OutputHandler > m_OutputHandlers
ITensorHandle * GetData() const
Gets the allocated tensor memory.
void Accept(ILayerVisitor &visitor) const override
unsigned int GetNumInputSlots() const override
ConcatLayer * Clone(Graph &graph) const override
const TensorShape & GetShape() const
const TensorInfo & GetTensorInfo() const override
Layer & GetOwningLayer() const
virtual void CreateTensorHandles(const TensorHandleFactoryRegistry ®istry, const IWorkloadFactory &factory, const bool IsMemoryManaged=true) override
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
const TensorInfo & GetTensorInfo(const ITensorHandle *tensorHandle)
float32 helpers
An OriginsDescriptor for the ConcatLayer. Descriptor to configure the concatenation process...
const InputSlot & GetInputSlot(unsigned int index) const override