aclnnConvTbcBackward
Applicable Products
| Product | Supported |
|---|---|
| √ | |
| √ | |
| √ | |
| × | |
| × | |
| √ |
Function
Description: Implements backward propagation for 1D convolution with input and output dimensions of T (time or spatial dimension), B (batch), and C (channel).
Formula: Assume that the shape of the forward Conv_tbc input is , and the output gradient
has a shape of , the convolution kernel has a shape of , the bias has a shape of , and the padding for the input during backward propagation is . The relationship among these parameters is:
Convolution backward propagation requires computing the gradients with respect to the convolution forward 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 (corresponding to the bias parameter in the function prototype).
For the gradient of , (corresponding to the gradInput parameter in the function prototype):
Where denotes the batch size, denotes the number of channels, denotes the temporal or spatial dimension, denotes the loss function, and represents the gradient of the output tensor with respect to (corresponding to the self 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 "aclnnConvTbcBackwardGetWorkspaceSize" API to obtain the workspace size required for computation and the executor that contains the operator computation process, and then call the "aclnnConvTbcBackward" API to perform the computation.
aclnnStatus aclnnConvTbcBackwardGetWorkspaceSize(
const aclTensor *self,
const aclTensor *input,
const aclTensor *weight,
const aclTensor *bias,
int64_t pad,
int8_t cubeMathType,
aclTensor *gradInput,
aclTensor *gradWeight,
aclTensor *gradBias,
uint64_t *workspaceSize,
aclOpExecutor **executor)aclnnStatus aclnnConvTbcBackward(
void *workspace,
uint64_t workspaceSize,
aclOpExecutor *executor,
const aclrtStream stream)aclnnConvTbcBackwardGetWorkspaceSize
Parameters:
Parameter Input/Output Description Instruction Data Type Data Format Dimension (Shape) Non-Contiguous Tensor self Input Gradient of the output tensor y with respect to L in the formula, representing the input of the convolution backward pass. - Empty tensor is supported.
- Shape: (N, Cout, Hout).
- The data type must satisfy the data type derivation rule with the data type of weight (see Deduction Relationship).
FLOAT, FLOAT16, BFLOAT16 ND, NCL 3 √ input Input x in the formula, representing the forward convolution input. - Empty tensor is supported.
- Shape: (N, Cin, Hin).
- The data type must satisfy the data type derivation rule with the data type of weight (see Deduction Relationship).
FLOAT, FLOAT16, BFLOAT16 ND, NCL 3 √ weight Input w in the formula, representing the convolution weight. - Empty tensor is supported.
- Shape: (Cout, Cin, K).
- The data type must satisfy the data type derivation rule with the data types of input and self (see Deduction Relationship).
FLOAT, FLOAT16, BFLOAT16 ND, NCL 3 √ bias Input b in the formula represents the convolution bias. - Shape: (Cout).
- One-dimensional and equal to the first dimension of weight. Null pointers are not allowed.
- The data type is consistent with self and weight.
FLOAT, FLOAT16, BFLOAT16 ND, NCL 1 √ pad Input Number of padding elements on the left and right sides of the H dimension of the input during backward propagation. - The size must be in the range [0, 255].
INT64 - - × cubeMathType Input Determines which computation logic the Cube unit should use for calculation. Supported enumeration values are as follows: - 0: KEEP_DTYPE, keeps the input data type for computation.
- 1: ALLOW_FP32_DOWN_PRECISION, allows down-precision computation of the input data.
- 2: USE_FP16, allows conversion to the FLOAT16 data type for computation.
- 3: USE_HF32, allows conversion to the HFLOAT32 data type for computation.
- - - × gradInput Output Gradient of the input tensor x with respect to L in the formula. - Empty tensors are supported.
- The data type is consistent with the input type.
- The shape is (N, Cin, Hin).
FLOAT, FLOAT16, BFLOAT16 ND, NCL - × gradWeight Output Gradient of the convolution kernel weight tensor w with respect to L. - Supports empty tensors.
- The data type is consistent with the weight type.
- Shape: (Cout, Cin, K).
FLOAT, FLOAT16, BFLOAT16, HIFLOAT8, FLOAT8_E4M3FN ND, NCL - × gradBias Output Gradient of bias b with respect to L. - Supports empty tensors.
- The data type is consistent with the bias type.
- The shape is (Cout).
FLOAT, FLOAT16, BFLOAT16 ND, NCL - × workspaceSize Output Returns the workspace size to be applied on the Device side. - - - - × executor Output Returns the operator executor, which includes 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 Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 A null pointer is passed as an input parameter. ACLNN_ERR_PARAM_INVALID 161002 The data type and data format of self, input, weight, bias, gradInput, gradWeight, and gradBias are not within the supported range. The data types of self, input, weight, and bias are inconsistent. The shapes of gradInput, gradWeight, and gradBias do not meet the infershape result. The shapes of gradInput, gradWeight, and gradBias contain values less than 0. The dimension of self, input, and weight is not 3. The dimension of bias is not 1. The value of the third dimension of input is not equal to the value of the second dimension of weight. The value of bias is not equal to the value of the third dimension of weight. The pad value does not meet the requirement. ACLNN_ERR_INNER_NULLPTR 561103 API internal verification error, typically caused by input data or attribute specifications that are outside the supported range.
aclnnConvTbcBackward
Parameters:
Parameter Input/Output Description workspace Input Workspace memory address applied on the Device side. workspaceSize Input Workspace size applied on the Device side, obtained from the first-phase API aclnnConvTbcBackwardGetWorkspaceSize. executor Input Operator executor, which includes the computation flow of the operator. stream Input Specifies the stream for task execution. Return value
aclnnStatus: return code. For details, see aclnn Return Code.
Constraints
Deterministic computation
- aclnnConvTbcBackward defaults to a non-deterministic implementation. Deterministic computation can be enabled through aclrtCtxSetSysParamOpt.
| Constraint Type | |||
|---|---|---|---|
| self constraint |
|
Supports N, C, and L dimensions greater than or equal to 0 (the scenario where they equal 0 is supported only when the N, C, or L dimension of self equals 0). | |
| Input Constraints | For input, the N and C dimensions must be greater than or equal to 0, and the L dimension must be greater than or equal to 0 (the scenario where L equals 0 is supported only when the L dimension derived from out also equals 0). | The input data type does not support HIFLOAT8. The N, C, and L dimensions must be greater than or equal to 0. | The input data type does not support BFLOAT16 or HIFLOAT8. The N, C, and L dimensions must be greater than or equal to 0. |
| Weight Constraints |
|
The weight data type does not support HIFLOAT8. It supports N, C, and L dimensions greater than or equal to 0. | The weight data type does not support BFLOAT16 or HIFLOAT8. It supports N, C, and L dimensions greater than or equal to 0. |
| dtype constraint | HIFLOAT8 and FLOAT8_E4M3FN are supported only in the gradWeight parameter, and are not supported in other parameters. | HIFLOAT8 and FLOAT8_E4M3FN are not supported. | BFLOAT16, HIFLOAT8, and FLOAT8_E4M3FN are not supported. |
| cubeMathType Description |
|
|
|
| Other Constraints |
|
- | - |
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 apply for memory on the device side.
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);
// Call aclrtMemcpy to copy data from the host side to the device memory.
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 aclnnConvTbcBackwardTest(int32_t deviceId, aclrtStream &stream)
{
// 1. Initialize.
auto ret = Init(deviceId, &stream);
CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
// 2. Construct the input and output. Custom construction is required based on the API.
std::vector<int64_t> selfShape = {5, 1, 2};
std::vector<int64_t> inputShape = {5, 1, 2};
std::vector<int64_t> weightShape = {1, 2, 2};
std::vector<int64_t> biasShape = {2};
const int64_t pad = 0;
int8_t cubeMathType = 1;
std::vector<int64_t> gradInputShape = {5, 1, 2};
std::vector<int64_t> gradWeightShape = {1, 2, 2};
std::vector<int64_t> gradBiasShape = {2};
// Create self aclTensor.
std::vector<float> selfData(GetShapeSize(selfShape), 1);
aclTensor *self = nullptr;
void *selfdeviceAddr = nullptr;
ret = CreateAclTensor(selfData, selfShape, &selfdeviceAddr, aclDataType::ACL_FLOAT, &self);
std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor *)> selfTensorPtr(self, aclDestroyTensor);
std::unique_ptr<void, aclError (*)(void *)> selfdeviceAddrPtr(selfdeviceAddr, 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 bias aclTensor.
std::vector<float> biasData(GetShapeSize(biasShape), 1);
aclTensor *bias = nullptr;
void *biasDeviceAddr = nullptr;
ret = CreateAclTensor(biasData, biasShape, &biasDeviceAddr, aclDataType::ACL_FLOAT, &bias);
std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor *)> biasTensorPtr(bias, aclDestroyTensor);
std::unique_ptr<void, aclError (*)(void *)> biasDeviceAddrPtr(biasDeviceAddr, 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 gradBias aclTensor.
std::vector<float> gradBiasData(GetShapeSize(gradBiasShape), 1);
aclTensor *gradBias = nullptr;
void *gradBiasDeviceAddr = nullptr;
ret = CreateAclTensor(gradBiasData, gradBiasShape, &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);
// 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 aclnnConvTbcBackward.
ret = aclnnConvTbcBackwardGetWorkspaceSize(self, input, weight, bias, pad, cubeMathType, gradInput, gradWeight,
gradBias, &workspaceSize, &executor);
CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnConvTbcBackwardGetWorkspaceSize failed. ERROR: %d\n", ret);
return ret);
// Allocate device memory based on the workspaceSize computed 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 aclnnConvTbcBackward.
ret = aclnnConvTbcBackward(workspaceAddr, workspaceSize, executor, stream);
CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnConvTbcBackward failed. ERROR: %d\n", ret); return ret);
// 4. (Boilerplate) Synchronously 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 device memory to host memory. Modify 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.
// Fill in the deviceId based on the actual device.
int32_t deviceId = 0;
aclrtStream stream;
auto ret = aclnnConvTbcBackwardTest(deviceId, stream);
CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnConvTbcBackwardTest failed. ERROR: %d\n", ret); return ret);
Finalize(deviceId, stream);
return 0;
}