aclnnNpuFormatCast
Applicable Products
| Product | Supported |
|---|---|
| √ | |
| √ | |
| √ | |
| × | |
| × | |
| × |
Function
Description:
Ascend 950PR/Ascend 950DT :Converts ND Data Format to FRACTAL_NZ Data Format with a specified C0 size. C0 is the size of the last dimension of the FRACTAL_NZ Data Format, determined by
additionalDtype.Atlas A3 training products/Atlas A3 inference products ,Atlas A2 training products/Atlas A2 inference products :Converts ND←→NZ. C0 is the size of the last dimension of the NZ data format. The calculation method is C0 = 32B / ge::GetSizeByDataType(static_cast additionalDtype).
Converts NCDHW←→NDC1HWC0 and NCDHW←→NDC1HWC0. C0 is strongly related to the microarchitecture and equals the size of the cube unit, for example, 16. C1 is obtained by splitting the C dimension according to C0: C1 = C / C0. If the result is not divisible, the last portion of data needs to be padded to C0. The calculation method is C0 = 32B / srcDataType (for example, FP16 is 2 bytes).
Calculation Process:
aclnnNpuFormatCastCalculateSizeAndFormat calculates the shape and actual data format of the destination tensor dstTensor after conversion based on the source tensor srcTensor, the data type additionalDtype, and the data format dstFormat of the destination tensor. This information is used to construct dstTensor. Then, call aclnnNpuFormatCast to convert srcTensor into the destination tensor dstTensor with the actual data format.
Function Prototype
You must first call aclnnNpuFormatCastCalculateSizeAndFormat to calculate the shape and actual data format of dstTensor, and then call the two-phase API. For the two-phase API, first call aclnnNpuFormatCastGetWorkSpaceSize to obtain the workspace size required for computation and an executor that contains the operator computation process, and then call aclnnNpuFormatCast to perform the computation.
aclnnStatus aclnnNpuFormatCastCalculateSizeAndFormat(
const aclTensor* srcTensor,
const int dstFormat,
int additionalDtype,
int64_t** dstShape,
uint64_t* dstShapeSize,
int* actualFormat)aclnnStatus aclnnNpuFormatCastGetWorkspaceSize(
const aclTensor* srcTensor,
aclTensor* dstTensor,
uint64_t* workspaceSize,
aclOpExecutor** executor)aclnnStatus aclnnNpuFormatCast(
void* workspace,
uint64_t workspaceSize,
aclOpExecutor* executor,
aclrtStream stream)aclnnNpuFormatCastCalculateSizeAndFormat
Parameters
Parameter Input/Output Description Instruction Data Type Data Format Dimension (Shape) Non-contiguous Tensor srcTensor (aclTensor*) Input The source tensor to be converted. - INT8, UINT8, INT32, UINT32, FLOAT, FLOAT16, BFLOAT162, FLOAT8_E4M3FN, FLOAT8_E4M3FN2, FLOAT4_E2M12 ND, NZ, NCDHW, NDC1HWC0, FRACTAL_Z_3D, NCL2 2-6 - dstFormat (int) Input Data format of the output tensor. - None ND, NZ, NCDHW, NDC1HWC0, FRACTAL_Z_3D None - additionalDtype (int) Optional input. The base data type used to infer the C0 size when converting to the FRACTAL_NZ data format. - ACL_FLOAT16(1), ACL_BF16(27), INT8(2), ACL_FLOAT8_E4M3FN(36) None None - dstShape (int64_t**) Output Pointer to the array for outputting the shape of dstTensor. The memory pointed to by this pointer is allocated by this API and released by the caller. - None None 4-8 - dstShapeSize (uint64_t*) Output Pointer to the size of the shape array for outputting dstTensor. - None None None - actualFormat (int*) Output Pointer used to output the actual data format of dstTensor. - None ACL_FORMAT_ND(2), ACL_FORMAT_FRACTAL_NZ(29), ACL_FORMAT_NCDHW(30), ACL_FORMAT_NDC1HWC0(32), ACL_FRACTAL_Z_3D(33), ACL_FORMAT_FRACTAL_NZ_C0_16(50)2, ACL_FORMAT_FRACTAL_NZ_C0_32(51)2 None - Ascend 950PR/Ascend 950DT :- Superscript "1" in the data type column of the table above indicates a data type or data format not supported by this series.
Atlas A2 training products/Atlas A2 inference products ,Atlas A3 training products/Atlas A3 inference products :- Superscript "2" in the data type column of the table above indicates a data type or data format not supported by this series.
Return value
aclnnStatus: return code. For details, see aclnn Return Codes.
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 The passed-in srcTensor is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data format of srcTensor is not ND, NZ, NCDHW, NDC1HWC0, FRACTAL_Z_3D, or NCL, or the data type is not INT8, UINT8, INT32, UINT32, FLOAT, FLOAT16, BFLOAT16, FLOAT8_E4M3FN, or FLOAT4_E2M1. The data format of dstFormat is not ND, NZ, NCDHW, NDC1HWC0, or FRACTAL_Z_3D. The data type of additionalDtype is not ACL_FLOAT16(1), ACL_BF16(27), INT8(2), or ACL_FLOAT8_E4M3FN(36). The dimension of the view shape of srcTensor is not in the range of [2, 6]. srcTensor is an empty tensor. ACLNN_ERR_RUNTIME_ERROR 361001 The product model is not supported. The conversion format is not supported.
aclnnNpuFormatCastGetWorkspaceSize
Parameters
Parameter Input/Output Description Instruction Data Type Data Format Dimension (Shape) Non-Contiguous Tensor srcTensor (aclTensor*) Input Input tensor. The input data supports only contiguous tensors. - INT8, UINT8, INT32, UINT32, FLOAT, FLOAT16, BFLOAT162, FLOAT8_E4M3FN2, FLOAT4_E2M12 ND, NZ, NCDHW, NDC1HWC0, FRACTAL_Z_3D, NCL2 2-6 - dstTensor (aclTensor*) Input The destination tensor after conversion. Only contiguous tensors are supported. - INT8, UINT8, INT32, UINT32, FLOAT, FLOAT16, BFLOAT162, FLOAT8_E4M3FN, FLOAT8_E4M3FN2, FLOAT4_E2M12 ND, NZ, NCDHW, NDC1HWC0, FRACTAL_Z_3D, ACL_FORMAT_FRACTAL_NZ_C0_16(50)2, ACL_FORMAT_FRACTAL_NZ_C0_32(51)2 4-8 - workspaceSize (uint64_t*) Input Size of the workspace to be allocated on the Device side. - None None None - executor (aclOpExecutor**) Input The op executor that contains the operator computation process. - None None None - Ascend 950PR/Ascend 950DT :- Superscript "1" in the data type column of the preceding table indicates a data type or data format not supported by this series.
Atlas A2 training products/Atlas A2 inference products ,Atlas A3 training products/Atlas A3 inference products :- Superscript "2" in the data type column of the preceding table indicates a data type or data format not supported by this series.
Return value
aclnnStatus: return code. For details, see aclnn Return Codes.
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 The passed srcTensor or dstTensor is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data type of srcTensor is not INT8, UINT8, INT32, UINT32, FLOAT, FLOAT16, BFLOAT16, FLOAT8_E4M3FN, or FLOAT4_E2M1, or the data format is not ND, NZ, NCDHW, NDC1HWC0, FRACTAL_Z_3D, or NCL. The data type of dstTensor is not INT8, UINT8, INT32, UINT32, FLOAT, FLOAT16, BFLOAT16, FLOAT8_E4M3FN, or FLOAT4_E2M1, or the data format is not ND, NZ, NCDHW, NDC1HWC0, or FRACTAL_Z_3D. srcTensor or dstTensor is a non-contiguous tensor. The view shape dimension of srcTensor is not in the range of [2, 6], and the storage shape dimension of dstTensor is not in the range of [4, 8].2 ACLNN_ERR_RUNTIME_ERROR 361001 The product model is not supported. Ascend 950PR/Ascend 950DT :- The superscript "1" in the data type column of the table above indicates an interception type not supported by this series.
Atlas A2 training products/Atlas A2 inference products ,Atlas A3 training products/Atlas A3 inference products :- The superscript "2" in the data type column of the table above indicates an interception type not supported by this series.
aclnnNpuFormatCast
Parameters
Parameter Input/Output Description workspace Input Workspace memory address applied for on the Device side. workspaceSize Input Size of the workspace applied for on the Device side, obtained by the first-phase API aclnnNpuFormatCastGetWorkspaceSize. executor Input The op 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 Codes.
Constraints
Deterministic computation: aclnnNpuFormatCast defaults to a deterministic implementation.
The input and output support the following data type combinations:
Ascend 950PR/Ascend 950DT Parameters of the aclnnNpuFormatCastCalculateSizeAndFormat API:
srcTensor dstFormat additionalDtype actualFormat INT8 ACL_FORMAT_FRACTAL_NZ(29) ACL_INT8(2) ACL_FORMAT_FRACTAL_NZ(29) INT32 ACL_FORMAT_FRACTAL_NZ(29) ACL_FLOAT16(1), ACL_BF16(27) ACL_FORMAT_FRACTAL_NZ_C0_16(50) FLOAT ACL_FORMAT_FRACTAL_NZ(29) ACL_FLOAT16(1), ACL_BF16(27) ACL_FORMAT_FRACTAL_NZ_C0_16(50) FLOAT ACL_FORMAT_FRACTAL_NZ(29) ACL_FLOAT8_E4M3FN(36) ACL_FORMAT_FRACTAL_NZ_C0_32(51) FLOAT16 ACL_FORMAT_FRACTAL_NZ(29) ACL_FLOAT16(1) ACL_FORMAT_FRACTAL_NZ(29) BFLOAT16 ACL_FORMAT_FRACTAL_NZ(29) ACL_BF16(27) ACL_FORMAT_FRACTAL_NZ(29) FLOAT8_E4M3FN ACL_FORMAT_FRACTAL_NZ(29) ACL_FLOAT8_E4M3FN(36) ACL_FORMAT_FRACTAL_NZ(29) FLOAT4_E2M1 ACL_FORMAT_FRACTAL_NZ(29) ACL_FLOAT8_E4M3FN(36) ACL_FORMAT_FRACTAL_NZ(29) aclnnNpuFormatCastGetWorkspaceSize API:
srcTensor Data Type of dstTensor dstTensor Data Format INT8 INT8 ACL_FORMAT_FRACTAL_NZ(29) INT32 INT32 ACL_FORMAT_FRACTAL_NZ_C0_16(50) FLOAT FLOAT ACL_FORMAT_FRACTAL_NZ_C0_16(50)/ACL_FORMAT_FRACTAL_NZ_C0_32(51) FLOAT16 FLOAT16 ACL_FORMAT_FRACTAL_NZ(29) BFLOAT16 BFLOAT16 ACL_FORMAT_FRACTAL_NZ(29) FLOAT8_E4M3FN FLOAT8_E4M3FN ACL_FORMAT_FRACTAL_NZ(29) FLOAT4_E2M1 FLOAT4_E2M1 ACL_FORMAT_FRACTAL_NZ_C0_32(51) C0 calculation method:
additionalDtype C0 ACL_INT8(2) 32 ACL_FLOAT16(1) 16 ACL_BF16(27) 16 ACL_FLOAT8_E4M3FN(36) 32 Currently unsupported special scenarios:
When the data type of srcTensor is the same as additionalDtype and the type is FLOAT16 or BFLOAT16, if the dimensions are expressed as [k, n], the scenario where k is 1 is not supported.
After calling this API to convert to the Ascend-friendly Data Format FRACTAL_NZ, performing any operations that modify the tensor, such as contiguous, pad, and slice, is not supported.
When either of the last two dimensions of srcTensor's shape equals 1, converting to the Ascend-friendly Data Format FRACTAL_NZ and then performing any tensor modification operations, including transpose, is also not allowed.
Atlas A3 training products/Atlas A3 inference products ,Atlas A2 training products/Atlas A2 inference products aclnnNpuFormatCastCalculateSizeAndFormat API parameters:
srcTensor dstFormat additionalDtype actualFormat INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FORMAT_FRACTAL_NZ(29) INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FORMAT_FRACTAL_NZ(29) INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FORMAT_ND(2) INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FORMAT_ND(2) INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FORMAT_NCDHW(30) INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FORMAT_NCDHW(30) INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FORMAT_NDC1HWC0(32) INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FORMAT_NDC1HWC0(32) INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FRACTAL_Z_3D(33) INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FRACTAL_Z_3D(33) aclnnNpuFormatCastGetWorkspaceSize API:
srcTensor dstTensor Data Type dstTensor Data Format INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FORMAT_FRACTAL_NZ(29) INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FORMAT_ND(2) INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FORMAT_NCDHW(30) INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FORMAT_NDC1HWC0(32) INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 INT8, UINT8, FLOAT, FLOAT16, BF16, INT32, UINT32 ACL_FRACTAL_Z_3D(33) C0 calculation formula:
srcTensor Base Type C0 ACL_FLOAT(0), ACL_INT32(3), ACL_UINT32(8) 8 ACL_FLOAT16(1), ACL_BF16(27) 16 ACL_INT8(2), ACL_UINT8(4) 32 Currently unsupported special scenarios:
Calling this API to convert to the Ascend-friendly Data Format FRACTAL_NZ and then performing any tensor-modifying operations, such as contiguous, pad, and slice, is not supported.
Converting to the Ascend-friendly Data Format FRACTAL_NZ and then performing any tensor-modifying operations, including transpose, is not allowed.
Example
Ascend 950PR/Ascend 950DT :
The following provides example code for reference only. For details about compilation and running, see Compile and Run Samples.
#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_npu_format_cast.h"
#define CHECK_RET(cond, return_expr) \
do { \
if (!(cond)) { \
return_expr; \
} \
} while (0)
#define LOG_PRINT(message, ...) \
do { \
printf(message, ##__VA_ARGS__); \
} while (0)
#define CEIL_DIV(x, y) ((((x) + (y)) - 1) / (y))
#define CEIL_ALIGN(x, y) ((((x) + (y)) - 1) / (y) * (y))
int64_t GetShapeSize(const std::vector<int64_t>& shape) {
int64_t shapeSize = 1;
for (auto i : shape) {
shapeSize *= i;
}
return shapeSize;
}
extern "C" aclnnStatus aclnnNpuFormatCastCalculateSizeAndFormat(const aclTensor* srcTensor, const int dstFormat, const int additionalDtype, int64_t** dstShape, uint64_t* dstShapeSize, int* actualFormat);
extern "C" aclnnStatus aclnnNpuFormatCastGetWorkspaceSize(const aclTensor* srcTensor, aclTensor* dstTensor,uint64_t* workspaceSize, aclOpExecutor** executor);
extern "C" aclnnStatus aclnnNpuFormatCast(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream);
int Init(int32_t deviceId, aclrtStream* stream) {
// Boilerplate. Initialize resources.
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 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.
*tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
shape.data(), shape.size(), *deviceAddr);
return 0;
}
template <typename T>
int CreateAclTensorWithFormat(const std::vector<T>& hostData, const std::vector<int64_t>& shape, int64_t** storageShape, uint64_t* storageShapeSize, void** deviceAddr,
aclDataType dataType, aclTensor** tensor, aclFormat format) {
auto size = hostData.size() * sizeof(T);
// Call aclrtMalloc to allocate 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);
// Copy host data to 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];
}
*tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0,
format, *storageShape, *storageShapeSize, *deviceAddr);
return 0;
}
int main() {
// 1. (Boilerplate) Initialize the device/stream. See the ACL API manual.
// Set deviceId based on the actual device.
int32_t deviceId = 0;
aclrtStream stream;
auto ret = Init(deviceId, &stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
// 2. Construct the input and output. Customize the construction based on the API.
int64_t k = 64;
int64_t n = 128;
int64_t srcDim0 = k;
int64_t srcDim1 = n;
int dstFormat = 29;
aclDataType srcDtype = aclDataType::ACL_INT32;
aclDataType additionalDtype = aclDataType::ACL_FLOAT16;
std::vector<int64_t> srcShape = {srcDim0, srcDim1};
void* srcDeviceAddr = nullptr;
void* dstDeviceAddr = nullptr;
aclTensor* srcTensor = nullptr;
aclTensor* dstTensor= nullptr;
std::vector<int32_t> srcHostData(k * n, 1);
for (size_t i = 0; i < k; i++) {
for (size_t j = 0; j < n; j++) {
srcHostData[i * n + j] = (j + 1) % 128;
}
}
std::vector<int32_t> dstTensorHostData(k * n, 1);
int64_t* dstShape = nullptr;
uint64_t dstShapeSize = 0;
int actualFormat;
// Create the source aclTensor.
ret = CreateAclTensor(srcHostData, srcShape, &srcDeviceAddr, srcDtype, &srcTensor);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// 3. Call the CANN operator library API.
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
void* workspaceAddr = nullptr;
// Calculate the shape and format of the target tensor.
ret = aclnnNpuFormatCastCalculateSizeAndFormat(srcTensor, 29, additionalDtype, &dstShape, &dstShapeSize, &actualFormat);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnNpuFormatCastCalculateSizeAndFormat failed. ERROR: %d\n", ret); return ret);
ret = CreateAclTensorWithFormat(dstTensorHostData, srcShape, &dstShape, &dstShapeSize, &dstDeviceAddr, srcDtype, &dstTensor, static_cast<aclFormat>(actualFormat));
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("CreateAclTensorWithFormat failed. ERROR: %d\n", ret); return ret);
// Call the first-phase API aclnnNpuFormatCastGetWorkspaceSize.
ret = aclnnNpuFormatCastGetWorkspaceSize(srcTensor, dstTensor, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnNpuFormatCastGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
// Allocate device memory based on the workspaceSize calculated by the first-phase API.
if (workspaceSize > 0) {
ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
}
// Call the second-phase API of aclnnNpuFormatCastGetWorkspaceSize.
ret = aclnnNpuFormatCast(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnNpuFormatCast failed. ERROR: %d\n", ret); return ret);
// 4. (Boilerplate) Synchronously wait for task execution to finish.
ret = aclrtSynchronizeStream(stream);
CHECK_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.
auto size = 1;
for (size_t i = 0; i < dstShapeSize; i++) {
size *= dstShape[i];
}
std::vector<int32_t> resultData(size, 0);
ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), dstDeviceAddr,
size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
CHECK_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("result[%ld] is: %d\n", i, resultData[i]);
}
// 6. Release dstShape, aclTensor, and aclScalar.
delete[] dstShape;
aclDestroyTensor(srcTensor);
aclDestroyTensor(dstTensor);
// 7. Release device resources.
aclrtFree(srcDeviceAddr);
aclrtFree(dstDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}Atlas A3 training products/Atlas A3 inference products ,Atlas A2 training products/Atlas A2 inference products :
The following provides example code for reference only. For details about compilation and running, see Compile and Run Samples.
#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_npu_format_cast.h"
#define CHECK_RET(cond, return_expr) \
do { \
if (!(cond)) { \
return_expr; \
} \
} while (0)
#define LOG_PRINT(message, ...) \
do { \
printf(message, ##__VA_ARGS__); \
} while (0)
#define CEIL_DIV(x, y) ((((x) + (y)) - 1) / (y))
#define CEIL_ALIGN(x, y) ((((x) + (y)) - 1) / (y) * (y))
int64_t GetShapeSize(const std::vector<int64_t>& shape) {
int64_t shapeSize = 1;
for (auto i : shape) {
shapeSize *= i;
}
return shapeSize;
}
extern "C" aclnnStatus aclnnNpuFormatCastCalculateSizeAndFormat(const aclTensor* srcTensor, const int dstFormat, const int additionalDtype, int64_t** dstShape, uint64_t* dstShapeSize, int* actualFormat);
extern "C" aclnnStatus aclnnNpuFormatCastGetWorkspaceSize(const aclTensor* srcTensor, aclTensor* dstTensor,uint64_t* workspaceSize, aclOpExecutor** executor);
extern "C" aclnnStatus aclnnNpuFormatCast(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream);
int Init(int32_t deviceId, aclrtStream* stream) {
// Boilerplate for 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 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.
// Modify the format of src here.
*tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_NCDHW,
shape.data(), shape.size(), *deviceAddr);
return 0;
}
template <typename T>
int CreateAclTensorWithFormat(const std::vector<T>& hostData, const std::vector<int64_t>& shape, int64_t** storageShape, uint64_t* storageShapeSize, void** deviceAddr,
aclDataType dataType, aclTensor** tensor, aclFormat format) {
auto size = hostData.size() * sizeof(T);
// Call aclrtMalloc to allocate 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];
}
*tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0,
format, *storageShape, *storageShapeSize, *deviceAddr);
return 0;
}
int main() {
// 1. (Boilerplate) Initialize the device/stream. See the acl API manual.
// Set deviceId based on the actual device.
int32_t deviceId = 0;
aclrtStream stream;
auto ret = Init(deviceId, &stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
// 2. Construct the input and output. Customize the construction based on the API interface.
int dstFormat = 32;
//Modify the target format here.
aclDataType srcDtype = aclDataType::ACL_INT32;
int additionalDtype = -1;
// std::vector<int64_t> srcShape = {srcDim0 , srcDim1};
int64_t N = 1;
int64_t C = 17;
int64_t D = 1;
int64_t H = 2;
int64_t W = 2;
std::vector<int64_t> srcShape = {N, C, D, H, W};
void* srcDeviceAddr = nullptr;
void* dstDeviceAddr = nullptr;
aclTensor* srcTensor = nullptr;
aclTensor* dstTensor= nullptr;
std::vector<int32_t> srcHostData(N * C * D * H * W, 1);
int num = 0;
for (int n = 0; n < N; ++n) {
for (int c = 0; c < C; ++c) {
for (int d = 0; d < D; ++d) {
for (int h = 0; h < H; ++h) {
for (int w = 0; w < W; ++w) {
// Arrange in row-major order and compute the linear index.
int index = (((n * C + c) * D + d) * H + h) * W + w;
srcHostData[index] = num;
num++;
}
}
}
}
}
std::vector<int32_t> dstTensorHostData(N * C * D * H * W, 1);
int64_t* dstShape = nullptr;
uint64_t dstShapeSize = 0;
int actualFormat;
// Create src aclTensor.
ret = CreateAclTensor(srcHostData, srcShape, &srcDeviceAddr, srcDtype, &srcTensor);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// 3. Call the CANN operator library API.
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
void* workspaceAddr = nullptr;
std::cout << "init actualFormat = " << actualFormat << std::endl;
// Calculate the shape and format of the target tensor.
ret = aclnnNpuFormatCastCalculateSizeAndFormat(srcTensor, dstFormat, additionalDtype, &dstShape, &dstShapeSize, &actualFormat);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnNpuFormatCastCalculateSizeAndFormat failed. ERROR: %d\n", ret); return ret);
std::cout << "actualFormat = " << actualFormat << std::endl;
std::cout << "&dstShape = " << &dstShape << std::endl;
std::cout << "dstShape = [ ";
for (int64_t i = 0; i < dstShapeSize; ++i) {
std::cout << dstShape[i] << " ";
}
std::cout << "]" << std::endl;
ret = CreateAclTensorWithFormat(dstTensorHostData, srcShape, &dstShape, &dstShapeSize, &dstDeviceAddr, srcDtype, &dstTensor, static_cast<aclFormat>(actualFormat));
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("CreateAclTensorWithFormat failed. ERROR: %d\n", ret); return ret);
// Call the first-phase API aclnnNpuFormatCastGetWorkspaceSize.
ret = aclnnNpuFormatCastGetWorkspaceSize(srcTensor, dstTensor, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnNpuFormatCastGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
// Apply for device memory based on the workspaceSize calculated by the first-phase API.
if (workspaceSize > 0) {
ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
}
// Call the second-phase API of aclnnNpuFormatCastGetWorkspaceSize.
ret = aclnnNpuFormatCast(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnNpuFormatCast failed. ERROR: %d\n", ret); return ret);
// 4. (Boilerplate) Synchronously wait for task execution to complete.
ret = aclrtSynchronizeStream(stream);
CHECK_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.
auto size = 1;
for (size_t i = 0; i < dstShapeSize; i++) {
size *= dstShape[i];
}
std::vector<int32_t> resultData(size, 0);
ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), dstDeviceAddr,
size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
CHECK_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("result[%ld] is: %d\n", i, resultData[i]);
}
// 6. Release dstShape, aclTensor, and aclScalar.
delete[] dstShape;
aclDestroyTensor(srcTensor);
aclDestroyTensor(dstTensor);
// 7. Release device resources.
aclrtFree(srcDeviceAddr);
aclrtFree(dstDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}