aclnnConvolutionBackward
Applicable Products
| Product | Supported |
|---|---|
| √ | |
| √ | |
| √ | |
| × | |
| √ | |
| √ |
Function
Description: Backward propagation of convolution. Computes the gradients of the input, weight, and bias based on the output mask settings. This function supports 1D, 2D, and 3D convolution.
Formula:
The relationship between the input (), output (), convolution stride (), convolution kernel size (, , , ), and dilation parameter () is:
Convolution backward propagation needs to compute the gradients with respect to the input tensor (corresponding to the input parameter in the function prototype), the convolution kernel weight tensor (corresponding to the weight parameter in the function prototype), and the bias .
For the gradient of , (corresponding to the gradInput parameter in the function prototype):
Where is the loss function, and is the gradient of the output tensor with respect to (corresponding to the gradOutput parameter in the function prototype).
For the gradient of , (corresponding to the gradWeight parameter in the function prototype):
For the gradient of , (corresponding to the gradBias parameter in the function prototype):
Function Prototype
Each operator is divided into a two-phase API. First call the "aclnnConvolutionBackwardGetWorkspaceSize" API to obtain the workspace size required for computation and the executor that contains the operator computation process, and then call the "aclnnConvolutionBackward" API to perform the computation.
aclnnStatus aclnnConvolutionBackwardGetWorkspaceSize(
const aclTensor *gradOutput,
const aclTensor *input,
const aclTensor *weight,
const aclIntArray *biasSizes,
const aclIntArray *stride,
const aclIntArray *padding,
const aclIntArray *dilation,
bool transposed,
const aclIntArray *outputPadding,
int groups,
const aclBoolArray *outputMask,
int8_t cubeMathType,
aclTensor *gradInput,
aclTensor *gradWeight,
aclTensor *gradBias,
uint64_t *workspaceSize,
aclOpExecutor **executor)aclnnStatus aclnnConvolutionBackward(
void *workspace,
uint64_t workspaceSize,
aclOpExecutor *executor,
const aclrtStream stream)aclnnConvolutionBackwardGetWorkspaceSize
Parameters:
Parameter Input/Output Description Instruction Data Type Data Format Dimension (Shape) Non-Contiguous Tensor gradOutput Input Gradient of the output tensor y with respect to L. - Supports empty tensors.
- The data type must satisfy the data type deduction rules with input and weight (see Deduction Relationship and Constraints).
- Broadcast is not supported for the shape. The shape must satisfy the convolution input-output shape deduction relationship with input and weight.
- The data format must be consistent with input and gradInput.
FLOAT, FLOAT16, BFLOAT16 NCL, NCHW, NCDHW See Constraints. √ input Input x in the formula. - Supports empty tensors.
- The data type must satisfy the data type deduction rules with gradOutput and weight (see Deduction Relationship and Constraints).
- The shape does not support broadcast and must satisfy the convolution input/output shape deduction relationship with gradOutput and weight.
- The data format must be consistent with gradOutput and gradInput.
FLOAT, FLOAT16, BFLOAT16 NCL, NCHW, NCDHW See Constraints. √ weight Input w in the formula. - Supports empty tensors.
- The data type, along with gradOutput and input, must satisfy the data type deduction rules (see Deduction Relationship and Constraints).
- The shape does not support broadcast and must satisfy the convolution input-output shape deduction relationship with gradOutput and input.
- The data format must be consistent with gradWeight.
FLOAT, FLOAT16, BFLOAT16 NCL, NCHW, NCDHW See Constraints. √ biasSizes Input Shape of the bias in the forward convolution process. - The array length is 1.
- In standard convolution, it equals [weight.shape[0]]; in transposed convolution, it equals [weight.shape[1] * groups].
- In the empty tensor scenario, when outputMask specifies that the bias gradient needs to be computed, biasSizes cannot be nullptr.
INT64 - - × stride Input Specifies the step size at which the convolution kernel moves over the input during backward propagation. - For 1D convolution backward, the array length must be 1.
- The array length equals the weight dimension minus 2, and the value must be greater than 0.
INT64 - See Constraints. × padding Input Padding for the input during backward propagation. - For 1D convolution backward, the array length must be 1.
- The array length can be the weight dimension minus 2. In 2D scenarios, the array length can be 4.
- The value must be greater than or equal to 0.
INT64 - See Constraints. × dilation Input Dilation parameter in the backward propagation process. - For 1D convolution backward, the array length must be 1.
- The array length can be the weight dimension minus 2.
- The value must be greater than 0.
INT64 - See Constraints. × transposed Input Transposed convolution enable flag. When set to True, enables transposed convolution. - - - - × outputPadding Input Output padding during backward propagation. - The array length can be the weight dimension minus 2, and the value range of each dimension satisfies [0, stride value of the corresponding dimension).
- When transposed is False, each element value must be 0.
INT64 - - × groups Input Number of groups for input channels during backward propagation. The condition groups * C dimension of weight = C dimension of input must be met. The value range of groups is [1, 65535]. INT32 - - × outputMask Input - Output mask parameter, which specifies whether the output contains the gradients of input, weight, and bias.
- During backward propagation, outputs the gradient at the position where the mask parameter is True.
- - - - × cubeMathType Input Determines which computation logic the Cube unit should use for the operation. - If the input data type has a deduction relationship, this parameter processes the data type after deduction by default.
- The supported enumeration values are as follows:
- 0: KEEP_DTYPE, keeps the input data type for computation.
- 1: ALLOW_FP32_DOWN_PRECISION, allows reducing the precision of the input data for computation.
- 2: USE_FP16, allows conversion to the FLOAT16 data type for computation. When the input data type is FLOAT, it is converted to FLOAT16 for computation.
- 3: USE_HF32, allows conversion to the HFLOAT32 data type for computation. When the input is FLOAT16, FLOAT16 is still used for computation.
- - - × gradInput Output Gradient of the input tensor x with respect to L. - Supports empty tensors.
- The data type must be consistent with input.
- The data format must be consistent with input and gradOutput
FLOAT, FLOAT16, BFLOAT16 NCL, NCHW, NCDHW - × gradWeight Output Gradient of the convolution kernel weight tensor w with respect to L. - Supports empty tensors.
- The data format must be consistent with weight.
FLOAT, FLOAT16, BFLOAT16 NCL, NCHW, NCDHW - × gradBias Output Gradient of bias b with respect to L. - Supports empty tensor.
- The data type is the same as that of gradOutput
FLOAT, FLOAT16, BFLOAT16 ND - × workspaceSize Output Returns the workspace size to be requested on the Device side. - - - - × executor Output Returns the operator executor, which contains the operator computation flow. - - - - × Return value
aclnnStatus: return code. For details, see aclnn Return Code.
The first-phase API performs input parameter validation and returns an error in the following scenarios:
Return Value Return Code Description ACLNN_ERR_PARAM_NULLPTR 161001 The passed gradOutput, input, weight, biasSizes, stride, padding, dilation, outputPadding, outputMask, gradInput, and gradWeight are null pointers. When the output includes the gradient of bias, the passed gradBias is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data type of gradOutput, input, or weight is not within the supported range. The data formats of gradOutput, input, and weight are not within the supported range. The shapes of gradOutput, input, and weight do not meet the constraints. The shapes of biasSizes, stride, padding, dilation, and outputPadding do not meet the constraints. The condition groups * C dimension of weight = C dimension of input is not satisfied. The current processor does not support Convolution Backward. ACLNN_ERR_INNER_NULLPTR 561103 API internal verification error, typically caused by input data or attributes falling outside the supported specifications.
aclnnConvolutionBackward
Parameters:
Parameter Input/Output Description workspace Input Address of the workspace memory applied on the Device side. workspaceSize Input Size of the workspace applied on the Device side, obtained through the first-phase API aclnnConvolutionBackwardGetWorkspaceSize. executor Input Operator executor, which contains the operator computation flow. stream Input Specifies the stream for task execution. Return value
aclnnStatus: return code. For details, see aclnn Return Code.
Constraints
deterministic computation
- aclnnConvolutionBackward defaults to a non-deterministic implementation. You can enable deterministic computation by calling aclrtCtxSetSysParamOpt.
| Constraint Type | |||
|---|---|---|---|
| Empty Tensor Constraints |
|
- | |
| gradOutput Constraints | - | In 1d, 2d, and 3d transposed=false scenarios, the size of each dimension must be greater than or equal to 1. When input is an empty tensor, the N, C, D, H, and W dimensions can be 0. | Empty tensors are not supported. |
| input Constraints |
|
In 1D, 2D, and 3D transposed=false scenarios, the size of each dimension must be greater than or equal to 1.
|
- |
| weight Constraints |
|
For 2D and 3D transposed=false scenarios, the sizes of H and W must be in the range [1, 255], and the sizes of other dimensions must be greater than or equal to 1. For 1D transposed=false scenarios, the size of L must be in the range [1, 255], and the sizes of other dimensions must be greater than or equal to 1.
|
Empty tensors are not supported. |
| Stride Constraints | For 1D, 2D, and 3D transposed=false scenarios, each value must be greater than or equal to 1. For 1D, 2D, and 3D transposed=true scenarios, strideD must be in the range [1, 1000000], and strideH and strideW must be in the range [1, 2147483646]. | For 3D transposed=false scenarios, strideD must be greater than or equal to 1, and strideH and strideW must be in the range [1, 63]. For 1D and 2D transposed=false scenarios, each value must be greater than or equal to 1. | - |
| Padding Constraints | In 1D, 2D, and 3D transposed=false scenarios, each value must be greater than or equal to 0. In 1D, 2D, and 3D transposed=true scenarios, paddingD must be in the range [0, 1000000], and paddingH and paddingW must be in the range [0, 2147483646]. | In 3D transposed=false scenarios, paddingD must be greater than or equal to 0, and paddingH and paddingW must be in the range [0, 255]. In 1D and 2D transposed=false scenarios, each value must be in the range [0, 255]. | - |
| dilation Constraints | In 1D, 2D, and 3D transposed=false scenarios, each value must be greater than or equal to 1. In 1D, 2D, and 3D transposed=true scenarios, dilationD must be in the range [1, 1000000], and dilationH and dilationW must be in the range [1, 2147483646]. | In 1D, 2D, and 3D transposed=false scenarios, each value must be in the range [1, 255]. | - |
| dtype Constraints | The data type supports HIFLOAT8 and FLOAT8_E4M3FN only when transposed=true and output_mask[0]=true. | HIFLOAT8 and FLOAT8_E4M3FN are not supported. | BFLOAT16, HIFLOAT8, and FLOAT8_E4M3FN are not supported. |
| cubeMathType Description |
|
|
|
| Other Constraints | The computation behavior of gradients in the padding region depends on the input shape. Depending on the operator optimization strategy, gradients in the padding region may be directly set to 0. | - | Currently, only backward propagation for 1D and 2D convolution is supported. Backward propagation for 3D convolution is not supported yet. |
- Formula 1:
Due to hardware resource limitations, the operator may fail to execute under certain combinations of parameter values. Analyze and troubleshoot the issue based on the log information. If the issue persists, click Link to obtain technical support.
Example
The following provides example code for reference only. For details about compilation and running, see Compile and Run Samples.
#include <iostream>
#include <memory>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_convolution_backward.h"
#define CHECK_RET(cond, return_expr) \
do { \
if (!(cond)) { \
return_expr; \
} \
} while (0)
#define CHECK_FREE_RET(cond, return_expr) \
do { \
if (!(cond)) { \
Finalize(deviceId, stream); \
return_expr; \
} \
} while (0)
#define LOG_PRINT(message, ...) \
do { \
printf(message, ##__VA_ARGS__); \
} while (0)
int64_t GetShapeSize(const std::vector<int64_t> &shape)
{
int64_t shapeSize = 1;
for (auto i : shape) {
shapeSize *= i;
}
return shapeSize;
}
int Init(int32_t deviceId, aclrtStream *stream)
{
// Boilerplate: resource initialization.
auto ret = aclInit(nullptr);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
ret = aclrtSetDevice(deviceId);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
ret = aclrtCreateStream(stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
return 0;
}
template <typename T>
int CreateAclTensor(const std::vector<T> &hostData, const std::vector<int64_t> &shape, void **DeviceAddr,
aclDataType dataType, aclTensor **tensor)
{
auto size = GetShapeSize(shape) * sizeof(T);
// Call aclrtMalloc to allocate device memory.
auto ret = aclrtMalloc(DeviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
// Copy data from the host side to the device memory using aclrtMemcpy.
ret = aclrtMemcpy(*DeviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
// Calculate the strides of a contiguous tensor.
std::vector<int64_t> strides(shape.size(), 1);
for (int64_t i = shape.size() - 2; i >= 0; i--) {
strides[i] = shape[i + 1] * strides[i + 1];
}
// Call the aclCreateTensor API to create an aclTensor.
if (shape.size() == 4) {
*tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_NCHW,
shape.data(), shape.size(), *DeviceAddr);
} else {
*tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
shape.data(), shape.size(), *DeviceAddr);
}
return 0;
}
void Finalize(int32_t deviceId, aclrtStream stream)
{
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
}
int aclnnConvolutionBackwardTest(int32_t deviceId, aclrtStream &stream)
{
// 1. Initialization.
auto ret = Init(deviceId, &stream);
CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
// 2. Construct inputs and outputs. Customize the construction based on the API.
std::vector<int64_t> gradOutputShape = {2, 2, 7, 7};
std::vector<int64_t> inputShape = {2, 2, 7, 7};
std::vector<int64_t> weightShape = {2, 2, 1, 1};
std::vector<int64_t> biasSize = {2};
std::vector<int64_t> stride = {1, 1};
std::vector<int64_t> padding = {0, 0};
std::vector<int64_t> dilation = {1, 1};
bool transposed = false;
std::vector<int64_t> outputPadding = {0, 0};
int groups = 1;
bool outputMask[3] = {true, true, true};
int8_t cubeMathType = 1;
std::vector<int64_t> gradInputShape = {2, 2, 7, 7};
std::vector<int64_t> gradWeightShape = {2, 2, 1, 1};
std::vector<int64_t> gradBiasShape = {2};
// Create gradOutput aclTensor.
std::vector<float> gradOutputData(GetShapeSize(gradOutputShape), 1);
aclTensor *gradOutput = nullptr;
void *gradOutputDeviceAddr = nullptr;
ret = CreateAclTensor(gradOutputData, gradOutputShape, &gradOutputDeviceAddr, aclDataType::ACL_FLOAT, &gradOutput);
std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor *)> gradOutputTensorPtr(gradOutput, aclDestroyTensor);
std::unique_ptr<void, aclError (*)(void *)> gradOutputDeviceAddrPtr(gradOutputDeviceAddr, aclrtFree);
CHECK_FREE_RET(ret == ACL_SUCCESS, return ret);
// Create input aclTensor.
std::vector<float> inputData(GetShapeSize(inputShape), 1);
aclTensor *input = nullptr;
void *inputDeviceAddr = nullptr;
ret = CreateAclTensor(inputData, inputShape, &inputDeviceAddr, aclDataType::ACL_FLOAT, &input);
std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor *)> inputTensorPtr(input, aclDestroyTensor);
std::unique_ptr<void, aclError (*)(void *)> inputDeviceAddrPtr(inputDeviceAddr, aclrtFree);
CHECK_FREE_RET(ret == ACL_SUCCESS, return ret);
// Create weight aclTensor.
std::vector<float> weightData(GetShapeSize(weightShape), 1);
aclTensor *weight = nullptr;
void *weightDeviceAddr = nullptr;
ret = CreateAclTensor(weightData, weightShape, &weightDeviceAddr, aclDataType::ACL_FLOAT, &weight);
std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor *)> weightTensorPtr(weight, aclDestroyTensor);
std::unique_ptr<void, aclError (*)(void *)> weightDeviceAddrPtr(weightDeviceAddr, aclrtFree);
CHECK_FREE_RET(ret == ACL_SUCCESS, return ret);
// Create gradInput aclTensor.
std::vector<float> gradInputData(GetShapeSize(inputShape), 1);
aclTensor *gradInput = nullptr;
void *gradInputDeviceAddr = nullptr;
ret = CreateAclTensor(gradInputData, inputShape, &gradInputDeviceAddr, aclDataType::ACL_FLOAT, &gradInput);
std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor *)> gradInputTensorPtr(gradInput, aclDestroyTensor);
std::unique_ptr<void, aclError (*)(void *)> gradInputDeviceAddrPtr(gradInputDeviceAddr, aclrtFree);
CHECK_FREE_RET(ret == ACL_SUCCESS, return ret);
// Create gradWeight aclTensor.
std::vector<float> gradWeightData(GetShapeSize(weightShape), 1);
aclTensor *gradWeight = nullptr;
void *gradWeightDeviceAddr = nullptr;
ret = CreateAclTensor(gradWeightData, weightShape, &gradWeightDeviceAddr, aclDataType::ACL_FLOAT, &gradWeight);
std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor *)> gradWeightTensorPtr(gradWeight, aclDestroyTensor);
std::unique_ptr<void, aclError (*)(void *)> gradWeightDeviceAddrPtr(gradWeightDeviceAddr, aclrtFree);
CHECK_FREE_RET(ret == ACL_SUCCESS, return ret);
// Create the gradBias aclTensor.
std::vector<float> gradBiasData(GetShapeSize(biasSize), 1);
aclTensor *gradBias = nullptr;
void *gradBiasDeviceAddr = nullptr;
ret = CreateAclTensor(gradBiasData, biasSize, &gradBiasDeviceAddr, aclDataType::ACL_FLOAT, &gradBias);
std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor *)> gradBiasTensorPtr(gradBias, aclDestroyTensor);
std::unique_ptr<void, aclError (*)(void *)> gradBiasDeviceAddrPtr(gradBiasDeviceAddr, aclrtFree);
CHECK_FREE_RET(ret == ACL_SUCCESS, return ret);
// Create the biasSizes aclIntArray.
aclIntArray *biasSizes = aclCreateIntArray(biasSize.data(), 1);
std::unique_ptr<aclIntArray, aclnnStatus (*)(const aclIntArray *)> biasSizesPtr(biasSizes, aclDestroyIntArray);
CHECK_FREE_RET(biasSizes != nullptr, return ACL_ERROR_INTERNAL_ERROR);
// Create the strides aclIntArray.
aclIntArray *strides = aclCreateIntArray(stride.data(), 2);
std::unique_ptr<aclIntArray, aclnnStatus (*)(const aclIntArray *)> stridesPtr(strides, aclDestroyIntArray);
CHECK_FREE_RET(strides != nullptr, return ACL_ERROR_INTERNAL_ERROR);
// Create the pads aclIntArray.
aclIntArray *pads = aclCreateIntArray(padding.data(), 2);
std::unique_ptr<aclIntArray, aclnnStatus (*)(const aclIntArray *)> padsPtr(pads, aclDestroyIntArray);
CHECK_FREE_RET(pads != nullptr, return ACL_ERROR_INTERNAL_ERROR);
// Create the dilations aclIntArray.
aclIntArray *dilations = aclCreateIntArray(dilation.data(), 2);
std::unique_ptr<aclIntArray, aclnnStatus (*)(const aclIntArray *)> dilationsPtr(dilations, aclDestroyIntArray);
CHECK_FREE_RET(dilations != nullptr, return ACL_ERROR_INTERNAL_ERROR);
// Create outputPads aclIntArray.
aclIntArray *outputPads = aclCreateIntArray(outputPadding.data(), 2);
std::unique_ptr<aclIntArray, aclnnStatus (*)(const aclIntArray *)> outputPadsPtr(outputPads, aclDestroyIntArray);
CHECK_FREE_RET(outputPads != nullptr, return ACL_ERROR_INTERNAL_ERROR);
// Create outMask aclBoolArray.
aclBoolArray *outMask = aclCreateBoolArray(outputMask, 3);
std::unique_ptr<aclBoolArray, aclnnStatus (*)(const aclBoolArray *)> outMaskPtr(outMask, aclDestroyBoolArray);
CHECK_FREE_RET(outMask != nullptr, return ACL_ERROR_INTERNAL_ERROR);
// 3. Call the CANN operator library API. Replace with the specific API name.
uint64_t workspaceSize = 0;
aclOpExecutor *executor;
// Call the first-phase API of aclnnConvolutionBackwardGetWorkspaceSize.
ret = aclnnConvolutionBackwardGetWorkspaceSize(gradOutput, input, weight, biasSizes, strides, pads, dilations,
transposed, outputPads, groups, outMask, cubeMathType, gradInput,
gradWeight, gradBias, &workspaceSize, &executor);
CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnConvolutionBackwardGetWorkspaceSize failed. ERROR: %d\n", ret);
return ret);
// Apply for device memory based on the workspaceSize calculated by the first-phase API.
void *workspaceAddr = nullptr;
std::unique_ptr<void, aclError (*)(void *)> workspaceAddrPtr(nullptr, aclrtFree);
if (workspaceSize > 0) {
ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
workspaceAddrPtr.reset(workspaceAddr);
}
// Call the second-phase API of aclnnConvolutionBackward.
ret = aclnnConvolutionBackward(workspaceAddr, workspaceSize, executor, stream);
CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnConvolutionBackward failed. ERROR: %d\n", ret); return ret);
// 4. (Boilerplate) Synchronize and wait for task execution to complete.
ret = aclrtSynchronizeStream(stream);
CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
// 5. Obtain the output value and copy the result from the device memory to the host memory. Modify this step based on the specific API definition.
auto size = GetShapeSize(gradInputShape);
std::vector<float> gradInputResult(size, 0);
ret = aclrtMemcpy(gradInputResult.data(), gradInputResult.size() * sizeof(gradInputResult[0]), gradInputDeviceAddr,
size * sizeof(gradInputResult[0]), ACL_MEMCPY_DEVICE_TO_HOST);
CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret);
return ret);
for (int64_t i = 0; i < size; i++) {
LOG_PRINT("gradInputResult[%ld] is: %f\n", i, gradInputResult[i]);
}
size = GetShapeSize(gradWeightShape);
std::vector<float> gradWeightResult(size, 0);
ret = aclrtMemcpy(gradWeightResult.data(), gradWeightResult.size() * sizeof(gradWeightResult[0]), gradWeightDeviceAddr,
size * sizeof(gradWeightResult[0]), ACL_MEMCPY_DEVICE_TO_HOST);
CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret);
return ret);
for (int64_t i = 0; i < size; i++) {
LOG_PRINT("gradWeightResult[%ld] is: %f\n", i, gradWeightResult[i]);
}
size = GetShapeSize(gradBiasShape);
std::vector<float> gradBiasResult(size, 0);
ret = aclrtMemcpy(gradBiasResult.data(), gradBiasResult.size() * sizeof(gradBiasResult[0]), gradBiasDeviceAddr,
size * sizeof(gradBiasResult[0]), ACL_MEMCPY_DEVICE_TO_HOST);
CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret);
return ret);
for (int64_t i = 0; i < size; i++) {
LOG_PRINT("gradBiasResult[%ld] is: %f\n", i, gradBiasResult[i]);
}
return ACL_SUCCESS;
}
int main()
{
// 1. (Boilerplate) Initialize the device/stream.
// Set deviceId based on the actual device.
int32_t deviceId = 0;
aclrtStream stream;
auto ret = aclnnConvolutionBackwardTest(deviceId, stream);
CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnConvolutionBackwardTest failed. ERROR: %d\n", ret); return ret);
Finalize(deviceId, stream);
return 0;
}