blob: 7aa643dcb1592809ca3b3d6c6f2537f1236621df [file] [log] [blame]
David Monahanbd738082023-12-08 12:50:02 +00001//
2// Copyright © 2024 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "GpuFsaConvolution2d.hpp"
7
8#include <armnn/Types.hpp>
9
10#include <aclCommon/ArmComputeTensorUtils.hpp>
11
12#include <arm_compute/core/ITensorInfo.h>
13#include <arm_compute/core/TensorInfo.h>
14#include <arm_compute/core/TensorShape.h>
15#include <arm_compute/core/CL/CLKernelLibrary.h>
16#include <arm_compute/core/CL/CLCompileContext.h>
17
18#include <arm_compute/dynamic_fusion/runtime/gpu/cl/ClWorkloadRuntime.h>
19#include <arm_compute/dynamic_fusion/sketch/gpu/GpuWorkloadContext.h>
David Monahanbd738082023-12-08 12:50:02 +000020#include <arm_compute/dynamic_fusion/sketch/gpu/operators/GpuConv2d.h>
21#include <arm_compute/dynamic_fusion/sketch/gpu/operators/GpuOutput.h>
22
23#include <vector>
24#include <iostream>
25
26namespace armnn
27{
28
29using namespace armcomputetensorutils;
30
31arm_compute::Status GpuFsaConvolution2dValidate(const TensorInfo& input,
32 const Convolution2dDescriptor& descriptor,
33 const TensorInfo& weights,
34 const Optional<TensorInfo>& biases)
35{
36 // Create a new workload sketch, for validation purposes
37 auto compileCtx = arm_compute::CLKernelLibrary::get().get_compile_context();
38 auto workloadContext = GpuWorkloadContext(&compileCtx);
39 GpuWorkloadSketch sketch{ &workloadContext };
40
41 // Build and create tensor infos using the sketch
42 const arm_compute::TensorInfo aclInputInfo = BuildArmComputeTensorInfo(input, descriptor.m_DataLayout);
43 arm_compute::TensorInfo aclWeightsInfo = BuildArmComputeTensorInfo(weights, descriptor.m_DataLayout);
44 aclWeightsInfo.set_are_values_constant(weights.IsConstant());
45
46 auto inputInfo = workloadContext.create_tensor_info(aclInputInfo);
47 auto weightInfo = workloadContext.create_tensor_info(aclWeightsInfo);
48
49 // Only create the bias tensor info if enabled, otherwise pass nullptr to validate_op
50 arm_compute::TensorInfo aclBiasInfo;
Orlaith Monahane1ac8692024-01-23 13:52:30 +000051 arm_compute::ITensorInfo* biasSketchInfoPtr = nullptr;
David Monahanbd738082023-12-08 12:50:02 +000052
53 if (descriptor.m_BiasEnabled)
54 {
55 if(!biases.has_value())
56 {
57 throw InvalidArgumentException("GpuFsaConvolution2d::ValidateOp: No biases set when biases are enabled");
58 }
59 aclBiasInfo = BuildArmComputeTensorInfo(biases.value(), descriptor.m_DataLayout);
60 aclBiasInfo.set_are_values_constant(biases.value().IsConstant());
61
Orlaith Monahane1ac8692024-01-23 13:52:30 +000062 biasSketchInfoPtr = workloadContext.create_tensor_info(aclBiasInfo);
David Monahanbd738082023-12-08 12:50:02 +000063 }
64
65 // Set Conv2d attributes using descriptor
66 const arm_compute::Size2D aclDilationInfo = BuildArmComputeSize2D(descriptor.m_DilationX,
67 descriptor.m_DilationY);
68 const arm_compute::Padding2D aclPadInfo = BuildArmComputePaddingInfo(descriptor);
69 const arm_compute::Size2D aclStrideInfo = BuildArmComputeSize2D(descriptor.m_StrideX, descriptor.m_StrideY);
70
71 Conv2dAttributes conv2DAttributes{};
72 conv2DAttributes.dilation(aclDilationInfo);
73 conv2DAttributes.pad(aclPadInfo);
74 conv2DAttributes.stride(aclStrideInfo);
75
76 // Validate operator, check status and update reasonIfUnsupported
77 arm_compute::Status aclStatus = GpuConv2d::validate_op(sketch,
Orlaith Monahane1ac8692024-01-23 13:52:30 +000078 inputInfo,
79 weightInfo,
David Monahanbd738082023-12-08 12:50:02 +000080 biasSketchInfoPtr,
81 conv2DAttributes);
82
83 return aclStatus;
84}
85
86void GpuFsaConvolution2dCreateOp(GpuFsaPreCompiledBlob* blob,
87 const TensorInfo& input,
88 const Convolution2dDescriptor& descriptor,
89 const TensorInfo& weights,
90 const Optional<TensorInfo>& biases)
91{
92/*
Orlaith Monahane1ac8692024-01-23 13:52:30 +000093 * Creating an Op for the GpuFsa backend requires us to create and maintain quite a bit of data, which is then stored
David Monahanbd738082023-12-08 12:50:02 +000094 * in a GpuFsaPreCompiledBlob for execution later. Specifically we need:
95 * GpuWorkloadContext, this contains the TensorInfos and is unique to the Graph being executed
96 * Sketch, this is similar to a subgraph and can contain one or more operations. Multiple ops can be "fused" together
97 * using a single sketch.
Orlaith Monahane1ac8692024-01-23 13:52:30 +000098 * The inputTensorinfos / outputTensorInfos, these are pointers to the TensorInfos used when creating the sketch.
99 * They refer to the TensorInfos stored within the GpuWorkloadContext and are needed when executing the sketch
100 * as the TensorInfos used when creating the Tensors must match those used to create the Sketch. Otherwise the runtime
101 * doesn't know which Tensors to use.
David Monahanbd738082023-12-08 12:50:02 +0000102 */
103 using namespace arm_compute::experimental::dynamic_fusion;
104 GpuWorkloadSketch* sketch = blob->sketch.get();
105 GpuWorkloadContext* workloadContext = blob->workloadContext.get();
Orlaith Monahane1ac8692024-01-23 13:52:30 +0000106 std::vector<arm_compute::ITensorInfo*> inputTensorInfos = {};
107 std::vector<arm_compute::ITensorInfo*> outputTensorInfos = {};
David Monahanbd738082023-12-08 12:50:02 +0000108
109 // Build and create tensor infos using the sketch
110 const arm_compute::TensorInfo aclInputInfo = BuildArmComputeTensorInfo(input, descriptor.m_DataLayout);
111 arm_compute::TensorInfo aclWeightsInfo = BuildArmComputeTensorInfo(weights, descriptor.m_DataLayout);
112 aclWeightsInfo.set_are_values_constant(weights.IsConstant());
David Monahanbd738082023-12-08 12:50:02 +0000113
Orlaith Monahane1ac8692024-01-23 13:52:30 +0000114 inputTensorInfos.emplace_back(workloadContext->create_tensor_info(aclInputInfo));
115 inputTensorInfos.emplace_back(workloadContext->create_tensor_info(aclWeightsInfo));
David Monahanbd738082023-12-08 12:50:02 +0000116
Orlaith Monahane1ac8692024-01-23 13:52:30 +0000117 // Only create the bias tensor info if enabled, otherwise pass nullptr to validate_op / create_op
David Monahanbd738082023-12-08 12:50:02 +0000118 arm_compute::TensorInfo aclBiasInfo;
David Monahanbd738082023-12-08 12:50:02 +0000119 arm_compute::ITensorInfo* biasSketchInfoPtr = nullptr;
120
121 if (descriptor.m_BiasEnabled)
122 {
123 if(!biases.has_value())
124 {
125 throw InvalidArgumentException("GpuFsaConvolution2d::CreateOp: No biases set when biases are enabled");
126 }
127 aclBiasInfo = BuildArmComputeTensorInfo(biases.value(), descriptor.m_DataLayout);
128 aclBiasInfo.set_are_values_constant(biases.value().IsConstant());
129
Orlaith Monahane1ac8692024-01-23 13:52:30 +0000130 inputTensorInfos.emplace_back(workloadContext->create_tensor_info(aclBiasInfo));
131 biasSketchInfoPtr = inputTensorInfos[2];
David Monahanbd738082023-12-08 12:50:02 +0000132 }
133
134 // Set Conv2d attributes using descriptor
135 const arm_compute::Size2D aclDilationInfo = BuildArmComputeSize2D(descriptor.m_DilationX,
136 descriptor.m_DilationY);
137 const arm_compute::Padding2D aclPadInfo = BuildArmComputePaddingInfo(descriptor);
138 const arm_compute::Size2D aclStrideInfo = BuildArmComputeSize2D(descriptor.m_StrideX, descriptor.m_StrideY);
139
140 Conv2dAttributes conv2DAttributes{};
141 conv2DAttributes.dilation(aclDilationInfo);
142 conv2DAttributes.pad(aclPadInfo);
143 conv2DAttributes.stride(aclStrideInfo);
144
145 // Validate operator, check status and update reasonIfUnsupported
Orlaith Monahane1ac8692024-01-23 13:52:30 +0000146 arm_compute::Status aclStatus = GpuConv2d::validate_op(*sketch,
147 inputTensorInfos[0],
148 inputTensorInfos[1],
149 biasSketchInfoPtr,
150 conv2DAttributes);
David Monahanbd738082023-12-08 12:50:02 +0000151
152 const bool supported = (aclStatus.error_code() == arm_compute::ErrorCode::OK);
153 if (!supported)
154 {
155 throw BackendCapabilityException("\"GpuFsa\" backend failed during Convolution2D operation validation");
156 }
157
Orlaith Monahane1ac8692024-01-23 13:52:30 +0000158 // Create the Op within the Sketch using the TensorInfos we have stored
159 arm_compute::ITensorInfo* convOutInfo = GpuConv2d::create_op(*sketch,
160 inputTensorInfos[0],
161 inputTensorInfos[1],
162 biasSketchInfoPtr,
163 conv2DAttributes);
David Monahanbd738082023-12-08 12:50:02 +0000164
Orlaith Monahane1ac8692024-01-23 13:52:30 +0000165 // Create the Output
166 outputTensorInfos.emplace_back(workloadContext->create_tensor_info());
167 GpuOutput::create_op(*sketch, convOutInfo, outputTensorInfos[0]);
David Monahanbd738082023-12-08 12:50:02 +0000168
Orlaith Monahane1ac8692024-01-23 13:52:30 +0000169 // Store the TensorInfos within the blob as unique_ptrs to be used later
170 blob->inputTensorInfos = std::make_unique<std::vector<arm_compute::ITensorInfo*>>(inputTensorInfos);
171 blob->outputTensorInfos = std::make_unique<std::vector<arm_compute::ITensorInfo*>>(outputTensorInfos);
David Monahanbd738082023-12-08 12:50:02 +0000172}
173
174} // namespace armnn