Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 1 | // |
Teresa Charlin | 2ea403d | 2023-06-19 12:06:19 +0100 | [diff] [blame] | 2 | // Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved. |
Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 3 | // SPDX-License-Identifier: MIT |
| 4 | // |
| 5 | |
| 6 | #include "ClSpaceToBatchNdWorkload.hpp" |
| 7 | |
Jan Eilers | 3c9e045 | 2020-04-10 13:00:44 +0100 | [diff] [blame] | 8 | #include <armnn/utility/PolymorphicDowncast.hpp> |
Teresa Charlin | 2ea403d | 2023-06-19 12:06:19 +0100 | [diff] [blame] | 9 | |
Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 10 | #include <cl/ClTensorHandle.hpp> |
Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 11 | |
Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 12 | namespace armnn |
| 13 | { |
| 14 | using namespace armcomputetensorutils; |
| 15 | |
| 16 | arm_compute::Status ClSpaceToBatchNdWorkloadValidate(const TensorInfo& input, |
| 17 | const TensorInfo& output, |
| 18 | const SpaceToBatchNdDescriptor& descriptor) |
| 19 | { |
Teresa Charlin | 2ea403d | 2023-06-19 12:06:19 +0100 | [diff] [blame] | 20 | arm_compute::TensorInfo aclInputInfo = BuildArmComputeTensorInfo(input, descriptor.m_DataLayout); |
| 21 | arm_compute::TensorInfo aclOutputInfo = BuildArmComputeTensorInfo(output, descriptor.m_DataLayout); |
Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 22 | |
Teresa Charlin | 2ea403d | 2023-06-19 12:06:19 +0100 | [diff] [blame] | 23 | arm_compute::Status statusSpaceToBatch = arm_compute::Status(arm_compute::ErrorCode::OK); |
| 24 | arm_compute::Status statusReshapeInput = arm_compute::Status(arm_compute::ErrorCode::OK); |
| 25 | arm_compute::Status statusReshapeOutput = arm_compute::Status(arm_compute::ErrorCode::OK); |
| 26 | |
| 27 | arm_compute::TensorInfo aclReshapeInputInfo = aclInputInfo; |
| 28 | arm_compute::TensorInfo aclReshapeOutputInfo = aclOutputInfo; |
| 29 | |
| 30 | // When a spacial dimension is missing (rank=3) set W to 1 |
| 31 | const unsigned int rank = input.GetNumDimensions(); |
| 32 | if (rank == 3) |
| 33 | { |
| 34 | const arm_compute::TensorShape inputShape = aclInputInfo.tensor_shape(); |
| 35 | const arm_compute::TensorShape outputShape = aclOutputInfo.tensor_shape(); |
| 36 | |
| 37 | if (descriptor.m_DataLayout == armnn::DataLayout::NHWC) |
| 38 | { |
| 39 | // In ACL dimensions are right to left: C, W, H, N |
| 40 | aclInputInfo.set_tensor_shape({inputShape.x(), 1, inputShape.y(), inputShape.z()}); |
| 41 | aclOutputInfo.set_tensor_shape({outputShape.x(), 1, outputShape.y(), outputShape.z()}); |
| 42 | } |
| 43 | else if (descriptor.m_DataLayout == armnn::DataLayout::NCHW) |
| 44 | { |
| 45 | // In ACL dimensions are right to left: W, H, C, N |
| 46 | aclInputInfo.set_tensor_shape({1, inputShape.x(), inputShape.y(), inputShape.z()}); |
| 47 | aclOutputInfo.set_tensor_shape({1, outputShape.x(), outputShape.y(), outputShape.z()}); |
| 48 | } |
| 49 | else |
| 50 | { |
| 51 | throw InvalidArgumentException("Unsupported or unknown DataLayout", CHECK_LOCATION()); |
| 52 | } |
| 53 | |
| 54 | statusReshapeInput = arm_compute::CLReshapeLayer::validate(&aclInputInfo, &aclReshapeInputInfo); |
| 55 | statusReshapeOutput = arm_compute::CLReshapeLayer::validate(&aclReshapeOutputInfo, &aclOutputInfo); |
| 56 | } |
| 57 | |
| 58 | // ArmNN blockShape is [H, W] ACl asks for W, H |
Matthew Sloyan | 171214c | 2020-09-09 09:07:37 +0100 | [diff] [blame] | 59 | int32_t blockHeight = armnn::numeric_cast<int32_t>(descriptor.m_BlockShape[0]); |
Teresa Charlin | 2ea403d | 2023-06-19 12:06:19 +0100 | [diff] [blame] | 60 | int32_t blockWidth = (rank == 3) ? 1 : armnn::numeric_cast<int32_t>(descriptor.m_BlockShape[1]); |
Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 61 | |
Teresa Charlin | 2ea403d | 2023-06-19 12:06:19 +0100 | [diff] [blame] | 62 | unsigned int padLeft = (rank == 3) ? 0 : descriptor.m_PadList[1].first; |
| 63 | unsigned int padRight = (rank == 3) ? 0 : descriptor.m_PadList[1].second; |
| 64 | arm_compute::Size2D paddingLeftTop = BuildArmComputeSize2D(padLeft, |
| 65 | descriptor.m_PadList[0].first); |
| 66 | arm_compute::Size2D paddingRightBottom = BuildArmComputeSize2D(padRight, |
| 67 | descriptor.m_PadList[0].second); |
Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 68 | |
Teresa Charlin | 2ea403d | 2023-06-19 12:06:19 +0100 | [diff] [blame] | 69 | const arm_compute::Status aclStatus = arm_compute::CLSpaceToBatchLayer::validate(&aclInputInfo, |
| 70 | blockWidth, |
| 71 | blockHeight, |
| 72 | paddingLeftTop, |
| 73 | paddingRightBottom, |
| 74 | &aclOutputInfo); |
| 75 | |
| 76 | if (statusReshapeInput.error_code() == arm_compute::ErrorCode::OK && |
| 77 | statusReshapeOutput.error_code() == arm_compute::ErrorCode::OK && |
| 78 | statusSpaceToBatch.error_code() == arm_compute::ErrorCode::OK) |
| 79 | { |
| 80 | return arm_compute::Status(arm_compute::ErrorCode::OK, |
| 81 | "All SpaceToBatch layers validate status OK."); |
| 82 | } |
| 83 | else |
| 84 | { |
| 85 | return arm_compute::Status(arm_compute::ErrorCode::RUNTIME_ERROR, |
| 86 | "SpaceToBatch layer validate status failed." |
| 87 | + statusSpaceToBatch.error_description() |
| 88 | + statusReshapeInput.error_description() |
| 89 | + statusReshapeOutput.error_description()); |
| 90 | } |
Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 91 | } |
| 92 | |
Teresa Charlin | 2ea403d | 2023-06-19 12:06:19 +0100 | [diff] [blame] | 93 | ClSpaceToBatchNdWorkload::ClSpaceToBatchNdWorkload(const SpaceToBatchNdQueueDescriptor& descriptor, |
| 94 | const WorkloadInfo& info, |
| 95 | const arm_compute::CLCompileContext& clCompileContext) |
Teresa Charlin | 588cbdf | 2022-01-19 15:55:37 +0000 | [diff] [blame] | 96 | : ClBaseWorkload<SpaceToBatchNdQueueDescriptor>(descriptor, info) |
Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 97 | { |
Keith Davis | bcd860a | 2021-08-05 14:20:33 +0100 | [diff] [blame] | 98 | // Report Profiling Details |
| 99 | ARMNN_REPORT_PROFILING_WORKLOAD_DESC("ClSpaceToBatchNdWorkload_Construct", |
| 100 | descriptor.m_Parameters, |
| 101 | info, |
| 102 | this->GetGuid()); |
| 103 | |
Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 104 | m_Data.ValidateInputsOutputs("ClSpaceToBatchNdWorkload", 1, 1); |
| 105 | |
Teresa Charlin | 2ea403d | 2023-06-19 12:06:19 +0100 | [diff] [blame] | 106 | arm_compute::ICLTensor& input = PolymorphicPointerDowncast<IClTensorHandle>(m_Data.m_Inputs[0])->GetTensor(); |
| 107 | arm_compute::ICLTensor& output = PolymorphicPointerDowncast<IClTensorHandle>(m_Data.m_Outputs[0])->GetTensor(); |
Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 108 | |
| 109 | arm_compute::DataLayout aclDataLayout = ConvertDataLayout(m_Data.m_Parameters.m_DataLayout); |
| 110 | input.info()->set_data_layout(aclDataLayout); |
| 111 | output.info()->set_data_layout(aclDataLayout); |
| 112 | |
Teresa Charlin | 2ea403d | 2023-06-19 12:06:19 +0100 | [diff] [blame] | 113 | arm_compute::TensorInfo aclReshapeInputInfo = BuildArmComputeTensorInfo(info.m_InputTensorInfos[0], |
| 114 | m_Data.m_Parameters.m_DataLayout); |
| 115 | arm_compute::TensorInfo aclReshapeOutputInfo = BuildArmComputeTensorInfo(info.m_OutputTensorInfos[0], |
| 116 | m_Data.m_Parameters.m_DataLayout); |
| 117 | |
| 118 | const unsigned int rank = info.m_InputTensorInfos[0].GetNumDimensions(); |
| 119 | if (rank == 3) |
| 120 | { |
| 121 | const arm_compute::TensorShape inputShape = input.info()->tensor_shape(); |
| 122 | const arm_compute::TensorShape outputShape = output.info()->tensor_shape(); |
| 123 | |
| 124 | // When a spacial dimension is missing set W to 1 |
| 125 | if (m_Data.m_Parameters.m_DataLayout == armnn::DataLayout::NHWC) |
| 126 | { |
| 127 | // In ACL dimensions are right to left: C, W, H, N |
| 128 | aclReshapeInputInfo.set_tensor_shape({inputShape.x(), 1, inputShape.y(), inputShape.z()}); |
| 129 | aclReshapeOutputInfo.set_tensor_shape({outputShape.x(), 1, outputShape.y(), outputShape.z()}); |
| 130 | } |
| 131 | else if (m_Data.m_Parameters.m_DataLayout == armnn::DataLayout::NCHW) |
| 132 | { |
| 133 | // In ACL dimensions are right to left: W, H, C, N |
| 134 | aclReshapeInputInfo.set_tensor_shape({1, inputShape.x(), inputShape.y(), inputShape.z()}); |
| 135 | aclReshapeOutputInfo.set_tensor_shape({1, outputShape.x(), outputShape.y(), outputShape.z()}); |
| 136 | } |
| 137 | else |
| 138 | { |
| 139 | throw InvalidArgumentException("Unsupported or unknown DataLayout", CHECK_LOCATION()); |
| 140 | } |
| 141 | |
| 142 | m_ReshapeInputTensor.allocator()->init(aclReshapeInputInfo); |
| 143 | m_ReshapeOutputTensor.allocator()->init(aclReshapeOutputInfo); |
| 144 | |
| 145 | InitialiseArmComputeTensorEmpty(m_ReshapeInputTensor); |
| 146 | InitialiseArmComputeTensorEmpty(m_ReshapeOutputTensor); |
| 147 | |
| 148 | m_LayerReshapeInput.reset(new arm_compute::CLReshapeLayer()); |
| 149 | m_LayerReshapeOutput.reset(new arm_compute::CLReshapeLayer()); |
| 150 | |
| 151 | m_LayerReshapeInput->configure(clCompileContext, &input, &m_ReshapeInputTensor); |
| 152 | m_LayerReshapeOutput->configure(clCompileContext, &m_ReshapeOutputTensor, &output); |
| 153 | } |
| 154 | |
| 155 | // ArmNN blockShape is [H, W] ACl asks for W, H |
| 156 | int32_t blockHeight = armnn::numeric_cast<int32_t>(m_Data.m_Parameters.m_BlockShape[0]); |
| 157 | int32_t blockWidth = (rank == 3) ? 1: armnn::numeric_cast<int32_t>(descriptor.m_Parameters.m_BlockShape[1]); |
| 158 | |
| 159 | unsigned int padLeft = (rank == 3) ? 0 : descriptor.m_Parameters.m_PadList[1].first; |
| 160 | unsigned int padRight = (rank == 3) ? 0 : descriptor.m_Parameters.m_PadList[1].second; |
| 161 | arm_compute::Size2D paddingLeftTop = BuildArmComputeSize2D(padLeft, |
| 162 | descriptor.m_Parameters.m_PadList[0].first); |
| 163 | arm_compute::Size2D paddingRightBottom = BuildArmComputeSize2D(padRight, |
| 164 | descriptor.m_Parameters.m_PadList[0].second); |
| 165 | |
Kevin May | 9f6862d | 2021-10-22 15:42:28 +0100 | [diff] [blame] | 166 | { |
Mike Kelly | 7cbe781 | 2023-07-25 17:37:33 +0100 | [diff] [blame] | 167 | ARMNN_SCOPED_PROFILING_EVENT_CL_NAME_GUID("ClSpaceToBatchNdWorkload_configure"); |
Teresa Charlin | 2ea403d | 2023-06-19 12:06:19 +0100 | [diff] [blame] | 168 | m_Layer.configure(clCompileContext, |
| 169 | rank == 3 ? &m_ReshapeInputTensor : &input, |
| 170 | blockWidth, |
| 171 | blockHeight, |
| 172 | paddingLeftTop, |
| 173 | paddingRightBottom, |
| 174 | rank == 3 ? &m_ReshapeOutputTensor : &output); |
Kevin May | 9f6862d | 2021-10-22 15:42:28 +0100 | [diff] [blame] | 175 | } |
Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 176 | } |
| 177 | |
| 178 | void ClSpaceToBatchNdWorkload::Execute() const |
| 179 | { |
Mike Kelly | 7cbe781 | 2023-07-25 17:37:33 +0100 | [diff] [blame] | 180 | ARMNN_SCOPED_PROFILING_EVENT_CL_NAME_GUID("ClSpaceToBatchNdWorkload_Execute"); |
Teresa Charlin | 2ea403d | 2023-06-19 12:06:19 +0100 | [diff] [blame] | 181 | if (m_LayerReshapeInput) |
| 182 | { |
| 183 | m_LayerReshapeInput->run(); |
| 184 | } |
| 185 | RunClFunction(m_Layer, CHECK_LOCATION()); |
| 186 | if (m_LayerReshapeOutput) |
| 187 | { |
| 188 | m_LayerReshapeOutput->run(); |
| 189 | } |
Sadik Armagan | f446432 | 2018-12-20 16:19:12 +0000 | [diff] [blame] | 190 | } |
| 191 | |
| 192 | } //namespace armnn |