blob: bebd043e9b8082ac3b2189780dc2e8b183a877a6 [file] [log] [blame]
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00001//
Matthew Sloyan6dd07022023-01-25 12:40:11 +00002// Copyright © 2020 Samsung Electronics Co Ltd and Contributors. All rights reserved.
Declan-ARM7c75e332024-03-12 16:40:25 +00003// Copyright © 2023-2024 Arm Ltd and Contributors. All rights reserved.
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +00004// SPDX-License-Identifier: MIT
5//
6
7#include "ReduceLayer.hpp"
8#include "LayerCloneBase.hpp"
9
10#include <armnn/TypesUtils.hpp>
11
Colm Donelan0c479742021-12-10 12:43:54 +000012#include <armnn/backends/WorkloadData.hpp>
13#include <armnn/backends/WorkloadFactory.hpp>
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +000014
15namespace armnn
16{
17
18ReduceLayer::ReduceLayer(const ReduceDescriptor& param, const char* name)
19 : LayerWithParameters(1, 1, LayerType::Reduce, param, name)
20{
21}
22
23std::unique_ptr<IWorkload> ReduceLayer::CreateWorkload(const IWorkloadFactory& factory) const
24{
25 ReduceQueueDescriptor descriptor;
Sadik Armagan58fb0ee2021-03-12 09:15:35 +000026 descriptor.m_Parameters.m_vAxis = m_Param.m_vAxis;
27 descriptor.m_Parameters.m_KeepDims = m_Param.m_KeepDims;
28 descriptor.m_Parameters.m_ReduceOperation = m_Param.m_ReduceOperation;
29 SetAdditionalInfo(descriptor);
30
Teresa Charlin611c7fb2022-01-07 09:47:29 +000031 return factory.CreateWorkload(LayerType::Reduce, descriptor, PrepInfoAndDesc(descriptor));
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +000032}
33
34ReduceLayer* ReduceLayer::Clone(Graph& graph) const
35{
Sadik Armagan58fb0ee2021-03-12 09:15:35 +000036 auto layer = CloneBase<ReduceLayer>(graph, m_Param, GetName());
37 layer->m_Param.m_vAxis = m_Param.m_vAxis;
38 layer->m_Param.m_KeepDims = m_Param.m_KeepDims;
39 layer->m_Param.m_ReduceOperation = m_Param.m_ReduceOperation;
40
41 return std::move(layer);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +000042}
43
44void ReduceLayer::ValidateTensorShapesFromInputs()
45{
46 VerifyLayerConnections(1, CHECK_LOCATION());
47
48 const TensorShape& outputShape = GetOutputSlot(0).GetTensorInfo().GetShape();
49
50 VerifyShapeInferenceType(outputShape, m_ShapeInferenceMethod);
51
Mike Kellya9ac6ba2023-06-30 15:18:26 +010052 const TensorInfo& input = GetInputSlot(0).GetTensorInfo();
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +000053
Declan-ARM7c75e332024-03-12 16:40:25 +000054 if (auto inputDims = input.GetNumDimensions(); inputDims != std::clamp(inputDims, 1u, 4u))
55 {
56 throw armnn::LayerValidationException("ReduceLayer: Reduce supports up to 4D input.");
57 }
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +000058
Mike Kelly377fb212023-01-10 15:55:28 +000059 std::vector<TensorShape> inferredShapes = InferOutputShapes( {input.GetShape() });
60
61 ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "ReduceLayer");
62}
63
64std::vector<TensorShape> ReduceLayer::InferOutputShapes(const std::vector<TensorShape>& inputShapes) const
65{
Declan-ARM7c75e332024-03-12 16:40:25 +000066 if (inputShapes.size() != 1)
67 {
68 throw armnn::Exception("inputShapes' size is \"" + std::to_string(inputShapes.size()) +
69 "\" - should be \"1\".");
70 }
71
Mike Kelly377fb212023-01-10 15:55:28 +000072 const TensorShape& input = inputShapes[0];
73
Declan-ARM7c75e332024-03-12 16:40:25 +000074 if (auto inputDims = input.GetNumDimensions(); inputDims != std::clamp(inputDims, 1u, 4u))
75 {
76 throw armnn::Exception("ReduceLayer: Reduce supports up to 4D input.");
77 }
Mike Kelly377fb212023-01-10 15:55:28 +000078
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +000079 unsigned int rank = input.GetNumDimensions();
80 unsigned int outputRank = 0;
81
82 // Calculate output dimension
83 if (m_Param.m_KeepDims)
84 {
85 outputRank = rank;
86 }
87 else if (m_Param.m_vAxis.empty())
88 {
89 outputRank = 1;
90 }
91 else if (m_Param.m_vAxis.size() > input.GetNumDimensions())
92 {
93 throw LayerValidationException("ReduceLayer: Dimensions to reduce can not be bigger than input dimensions");
94 }
95 else
96 {
97 outputRank = input.GetNumDimensions() - armnn::numeric_cast<unsigned int>(m_Param.m_vAxis.size());
98 if (outputRank == 0)
99 {
100 outputRank = 1;
101 }
102 }
103
104 std::vector<unsigned int> dimSizes(outputRank, 1);
105 if (!m_Param.m_vAxis.empty())
106 {
107 // Skip the dimension that has been reduced unless keepDims is true.
108 unsigned int outputIndex = 0;
109 for (unsigned int i = 0; i < input.GetNumDimensions(); ++i)
110 {
111 if (std::find(m_Param.m_vAxis.begin(), m_Param.m_vAxis.end(), i) == m_Param.m_vAxis.end())
112 {
Mike Kelly377fb212023-01-10 15:55:28 +0000113 dimSizes[outputIndex] = armnn::numeric_cast<unsigned int>(input[i]);
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +0000114 ++outputIndex;
115 }
116 else if (m_Param.m_KeepDims)
117 {
118 dimSizes[outputIndex] = 1;
119 ++outputIndex;
120 }
121 }
122 }
Mike Kelly377fb212023-01-10 15:55:28 +0000123 return std::vector<TensorShape>({ TensorShape(outputRank, dimSizes.data()) });
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +0000124}
125
Nikhil Raj4d2eec02022-05-30 11:08:52 +0100126void ReduceLayer::ExecuteStrategy(IStrategy& strategy) const
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +0000127{
Nikhil Raj4d2eec02022-05-30 11:08:52 +0100128 strategy.ExecuteStrategy(this, GetParameters(), {}, GetName());
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +0000129}
Sadik Armagan0c3ea5b2021-02-03 09:29:30 +0000130
131} // namespace armnn