ArmNN
 25.11
Loading...
Searching...
No Matches
NeonFloorDivWorkload.cpp
Go to the documentation of this file.
1//
2// Copyright © 2024 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
11
12namespace armnn
13{
14
15/// Utility function used for the two cast layer inputs to convert the output layer tensor types.
16inline TensorInfo ConvertTensorToFloat32(const TensorInfo& tensorInfo)
17{
18 // Change datatype of tensor info and return the new tensor
19 TensorInfo newTensorInfo(tensorInfo);
20 newTensorInfo.SetDataType(DataType::Float32);
21 return newTensorInfo;
22}
23
24/// Utility function used to check if a vector of tensors are Signed32
25inline bool IsAllTensorsSigned32(const std::vector<TensorInfo>& tensorInfos)
26{
27 for (const auto& tensorInfo : tensorInfos)
28 {
29 // For every tensorInfo, check the data type, return false if not Signed32
30 if(tensorInfo.GetDataType() != armnn::DataType::Signed32)
31 {
32 return false;
33 }
34 }
35 return true;
36}
37
38/// Utility function used to check if statuses are returning 'OK'
39inline bool IsValidationPassing(const std::vector<arm_compute::Status>& statuses)
40{
41 // For each status, check if code is 'OK', if not, return false
42 for (const auto& status : statuses)
43 {
44 if(status.error_code() != arm_compute::ErrorCode::OK)
45 {
46 return false;
47 }
48 }
49 return true;
50}
51
52arm_compute::Status NeonFloorDivWorkloadValidate(const TensorInfo& input0Info,
53 const TensorInfo& input1Info,
54 const TensorInfo& outputInfo,
55 const ActivationDescriptor* activationDescriptor)
56{
57 // Transform ArmNN TensorInfo to ACL TensorInfo
58 const arm_compute::TensorInfo inputInfo0 = BuildArmComputeTensorInfo(input0Info);
59 const arm_compute::TensorInfo inputInfo1 = BuildArmComputeTensorInfo(input1Info);
60 const arm_compute::TensorInfo outputInfo0 = BuildArmComputeTensorInfo(outputInfo);
61
62 const arm_compute::ActivationLayerInfo activationInfo = ConvertActivationDescriptorToAclActivationLayerInfo(
63 activationDescriptor);
64
65 // If Tensors are Signed32 we need to Cast them to floats, this is to ensure we get the correct
66 // output if the result is a negative number, as we should floor towards -(infinity)
67 if (IsAllTensorsSigned32({input0Info, input1Info, outputInfo}))
68 {
69 // Validate Cast0
70 TensorInfo outputCast0_Info = ConvertTensorToFloat32(input0Info);
71 const arm_compute::TensorInfo outputCast0 = BuildArmComputeTensorInfo(outputCast0_Info);
72
73 auto statusCast0 = arm_compute::NECast::validate(&inputInfo0,
74 &outputCast0,
75 arm_compute::ConvertPolicy::WRAP);
76 // Validate Cast1
77 TensorInfo outputCast1_Info = ConvertTensorToFloat32(input1Info);
78 const arm_compute::TensorInfo outputCast1 = BuildArmComputeTensorInfo(outputCast1_Info);
79
80 auto statusCast1 = arm_compute::NECast::validate(&inputInfo1,
81 &outputCast1,
82 arm_compute::ConvertPolicy::WRAP);
83
84 // Validate Div
85 TensorInfo outputDiv_Info = ConvertTensorToFloat32(outputInfo);
86 const arm_compute::TensorInfo outputDivInfo = BuildArmComputeTensorInfo(outputDiv_Info);
87
88 auto statusDiv = arm_compute::NEElementwiseDivision::validate(&outputCast0,
89 &outputCast1,
90 &outputDivInfo,
91 activationInfo);
92 // Validate Floor
93 TensorInfo outputFloor_Info = ConvertTensorToFloat32(outputInfo);
94 const arm_compute::TensorInfo outputFloorInfo = BuildArmComputeTensorInfo(outputFloor_Info);
95
96 auto statusFloor = arm_compute::NEFloor::validate(&outputDivInfo,
97 &outputFloorInfo);
98 // Validate Cast2
99 auto statusCast2 = arm_compute::NECast::validate(&outputFloorInfo,
100 &outputInfo0,
101 arm_compute::ConvertPolicy::WRAP);
102
103 // Return OK if all the layers are valid
104 if (IsValidationPassing({statusCast0, statusCast1, statusDiv, statusFloor, statusCast2}))
105 {
106 return arm_compute::Status(arm_compute::ErrorCode::OK);
107 }
108 }
109 else
110 {
111 // Validate Div
112 auto statusDiv = arm_compute::NEElementwiseDivision::validate(&inputInfo0,
113 &inputInfo1,
114 &outputInfo0,
115 activationInfo);
116 // Validate Floor
117 auto statusFloor = arm_compute::NEFloor::validate(&outputInfo0,
118 &outputInfo0);
119 // Return OK if all the layers are valid
120 if (IsValidationPassing({statusDiv, statusFloor}))
121 {
122 return arm_compute::Status(arm_compute::ErrorCode::OK);
123 }
124 }
125 return arm_compute::Status(arm_compute::ErrorCode::RUNTIME_ERROR,
126 "NeonFloorDivValidation: FloorDiv layer validation failed.");
127}
128
130 const WorkloadInfo& info)
132{
133 m_Data.ValidateInputsOutputs("NeonFloorDivWorkload", 2, 1);
134
135 TensorInfo input0Info = info.m_InputTensorInfos[0];
136 TensorInfo input1Info = info.m_InputTensorInfos[1];
137 TensorInfo outputInfo = info.m_OutputTensorInfos[0];
138
139 arm_compute::ITensor& input0 = PolymorphicDowncast<IAclTensorHandle*>(m_Data.m_Inputs[0])->GetTensor();
140 arm_compute::ITensor& input1 = PolymorphicDowncast<IAclTensorHandle*>(m_Data.m_Inputs[1])->GetTensor();
141 arm_compute::ITensor& output = PolymorphicDowncast<IAclTensorHandle*>(m_Data.m_Outputs[0])->GetTensor();
142
143 // Get data type of input and output
144 arm_compute::DataType inputDataType = PolymorphicDowncast<NeonTensorHandle*>(m_Data.m_Inputs[0])->GetDataType();
145 arm_compute::DataType outputDataType = PolymorphicDowncast<NeonTensorHandle*>(m_Data.m_Outputs[0])->GetDataType();
146
147 const arm_compute::ActivationLayerInfo activationInfo =
149
150 // If Tensors are Signed32 we need to Cast them to floats, this is to ensure we get the correct
151 // output if the result is a negative number, as we should floor towards -(infinity)
152 if(inputDataType == arm_compute::DataType::S32 && outputDataType == arm_compute::DataType::S32)
153 {
154 // Create new Cast layer pointers if type is S32
155 m_CastLayer0.reset(new arm_compute::NECast());
156 m_CastLayer1.reset(new arm_compute::NECast());
157 m_CastLayer2.reset(new arm_compute::NECast());
158
159 // Cast Input 0 to type float32
160 TensorInfo outputCast0_Info = ConvertTensorToFloat32(input0Info);
161
162 // Initialise output tensor based on Float32 type
163 BuildArmComputeTensor(m_OutputCast0, outputCast0_Info);
164 armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_OutputCast0);
165
166 // Configure first Cast Layer
167 m_CastLayer0->configure(&input0, &m_OutputCast0, arm_compute::ConvertPolicy::WRAP);
168
169 // Cast Input 1 to type Float32
170 TensorInfo outputCast1_Info = ConvertTensorToFloat32(input1Info);
171
172 // Initialise Output tensor based on Float32 type
173 BuildArmComputeTensor(m_OutputCast1, outputCast1_Info);
174 armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_OutputCast1);
175
176 // Configure second Cast Layer
177 m_CastLayer1->configure(&input1, &m_OutputCast1, arm_compute::ConvertPolicy::WRAP);
178
179 // Create Div output tensor
180 TensorInfo outputDiv_Info = ConvertTensorToFloat32(outputInfo);
181 BuildArmComputeTensor(m_OutputDiv, outputDiv_Info);
182 armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_OutputDiv);
183
184 // Configure Div Layer
185 m_DivLayer.configure(&m_OutputCast0, &m_OutputCast1, &m_OutputDiv, activationInfo);
186
187 // Create Floor output tensor
188 BuildArmComputeTensor(m_OutputFloor, outputDiv_Info);
189 armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_OutputFloor);
190
191 // Configure Floor Layer
192 m_FloorLayer.configure(&m_OutputDiv, &m_OutputFloor);
193
194 // Configure third Cast Layer
195 m_CastLayer2->configure(&m_OutputFloor, &output, arm_compute::ConvertPolicy::WRAP);
196 }
197 else
198 {
199 // Create Div output tensor
200 BuildArmComputeTensor(m_OutputDiv, outputInfo);
201 armcomputetensorutils::InitialiseArmComputeTensorEmpty(m_OutputDiv);
202
203 // Configure Div Layer
204 m_DivLayer.configure(&input0, &input1, &m_OutputDiv, activationInfo);
205
206 // Configure Floor Layer
207 m_FloorLayer.configure(&m_OutputDiv, &output);
208 }
209}
210
212{
213 ARMNN_SCOPED_PROFILING_EVENT_NEON_NAME_GUID("NeonFloorDivWorkload_Execute");
214 // Only run Cast Layers if needed. e.g. if it exists
215 if(m_CastLayer0 && m_CastLayer1)
216 {
217 m_CastLayer0->run();
218 m_CastLayer1->run();
219
220 // Delete objects after running
221 m_CastLayer0.reset();
222 m_CastLayer1.reset();
223 }
224 m_DivLayer.run();
225 m_FloorLayer.run();
226 if(m_CastLayer2)
227 {
228 m_CastLayer2->run();
229
230 // Delete object after running layer
231 m_CastLayer2.reset();
232 }
233}
234} //namespace armnn
#define ARMNN_SCOPED_PROFILING_EVENT_NEON_NAME_GUID(label)
Creates a profiling event that uses GetGuid() and GetName() from the calling class.
NeonBaseWorkload(const DivisionQueueDescriptor &descriptor, const WorkloadInfo &info)
NeonFloorDivWorkload(const DivisionQueueDescriptor &descriptor, const WorkloadInfo &info)
virtual void Execute() const override
Copyright (c) 2021 ARM Limited and Contributors.
arm_compute::ActivationLayerInfo ConvertAdditionalInfoToAclActivationLayerInfo(const QueueDescriptor &queueDescriptor)
arm_compute::Status NeonFloorDivWorkloadValidate(const TensorInfo &input0Info, const TensorInfo &input1Info, const TensorInfo &outputInfo, const ActivationDescriptor *activationDescriptor)
Validation for the Floor Div Workload.
bool IsValidationPassing(const std::vector< arm_compute::Status > &statuses)
Utility function used to check if statuses are returning 'OK'.
DestType PolymorphicDowncast(SourceType *value)
Polymorphic downcast for build in pointers only.
bool IsAllTensorsSigned32(const std::vector< TensorInfo > &tensorInfos)
Utility function used to check if a vector of tensors are Signed32.
arm_compute::ActivationLayerInfo ConvertActivationDescriptorToAclActivationLayerInfo(const ActivationDescriptor &actDesc)
TensorInfo ConvertTensorToFloat32(const TensorInfo &tensorInfo)
Utility function used for the two cast layer inputs to convert the output layer tensor types.
An ActivationDescriptor for the ActivationLayer.
Contains information about TensorInfos of a layer.