ArmNN
 25.02
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 
7 #include "NeonWorkloadUtils.hpp"
11 
12 namespace armnn
13 {
14 
15 /// Utility function used for the two cast layer inputs to convert the output layer tensor types.
16 inline 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
25 inline 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'
39 inline 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 
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.
QueueDescriptor m_Data
Definition: Workload.hpp:74
NeonFloorDivWorkload(const DivisionQueueDescriptor &descriptor, const WorkloadInfo &info)
virtual void Execute() const override
Copyright (c) 2021 ARM Limited and Contributors.
Status
enumeration
Definition: Types.hpp:43
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'.
bool IsAllTensorsSigned32(const std::vector< TensorInfo > &tensorInfos)
Utility function used to check if a vector of tensors are Signed32.
arm_compute::ActivationLayerInfo ConvertAdditionalInfoToAclActivationLayerInfo(const QueueDescriptor &queueDescriptor)
arm_compute::ActivationLayerInfo ConvertActivationDescriptorToAclActivationLayerInfo(const ActivationDescriptor &actDesc)
DataType
Definition: Types.hpp:49
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.
Definition: Descriptors.hpp:37
std::vector< ITensorHandle * > m_Inputs
std::vector< ITensorHandle * > m_Outputs
void ValidateInputsOutputs(const std::string &descName, unsigned int numExpectedIn, unsigned int numExpectedOut) const
Contains information about TensorInfos of a layer.