aclnnCast
Applicable Products
| Product | Supported |
|---|---|
| √ | |
| √ | |
| √ | |
| × | |
| √ | |
| √ |
Function
Converts the input tensor to the specified dtype.
Function Prototype
Each operator is divided into a two-phase API. The "aclnnCastGetWorkspaceSize" API must be called first to obtain the workspace size required for computation and the executor that encapsulates the operator computation flow. Then, the "aclnnCast" API is called to perform the computation.
aclnnStatus aclnnCastGetWorkspaceSize(
const aclTensor *self,
const aclDataType dtype,
aclTensor *out,
uint64_t *workspaceSize,
aclOpExecutor **executor)aclnnStatus aclnnCast(
void *workspace,
uint64_t workspaceSize,
aclOpExecutor *executor,
aclrtStream stream)aclnnCastGetWorkspaceSize
Parameters:
Parameter Input/Output Description Instruction Data Type Data Format Dimensions (Shape) Non-contiguous Tensor self Input Specifies the input parameter for the cast computation, which is an aclTensor on the Device side. - FLOAT16, FLOAT, DOUBLE, INT8, UINT8, INT16, UINT16, INT32, UINT32, INT64, UINT64, BOOL, COMPLEX32, COMPLEX64, COMPLEX128, BFLOAT16, HIFLOAT8, FLOAT8_E5M2, FLOAT8_E4M3FN, FLOAT4_E2M1, FLOAT4_E1M2 ND 0-8 √ dtype Attribute Specifies the target dtype to which the input tensor is converted. - const aclDataType - - - out Output Output parameter for the cast computation, which is an aclTensor on the Device side. The shape is the same as that of self. FLOAT16, FLOAT, DOUBLE, INT8, UINT8, INT16, UINT16, INT32, UINT32, INT64, UINT64, BOOL, COMPLEX32, COMPLEX64, COMPLEX128, BFLOAT16, HIFLOAT8, FLOAT8_E5M2, FLOAT8_E4M3FN, FLOAT4_E2M1, FLOAT4_E1M2, INT4 (non-contiguous tensors are not supported currently). ND 0-8 √ workspaceSize Output Returns the workspace size to be allocated on the Device side. - - - - - executor Output Returns the op executor, which contains the operator computation flow. - - - - - Atlas training products andAtlas inference products : BFLOAT16 and INT4 are not supported.Atlas A2 training products/Atlas A2 inference products ,Atlas A3 training products/Atlas A3 inference products : COMPLEX32, HIFLOAT8, FLOAT8_E5M2, FLOAT8_E4M3FN, FLOAT4_E2M1, FLOAT4_E1M2, and INT4 are not supported.
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 Code Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 Indicates that the input tensor or out is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 Indicates that the data type or data format of self is not within the supported range. The data format of self differs from that of out. The shape of self differs from that of out. The dtype parameter is not within the range of supported data formats for the output. When the data type of out is INT4, self is a non-contiguous tensor. ACLNN_ERR_INNER_TILING_ERROR 561002 The last axis of the shape of self is odd when the data type of out is INT4.
aclnnCast
Parameters:
Parameter Input/Output Description workspace Input Memory address of the workspace applied for on the Device side. workspaceSize Input Size of the workspace applied for on the Device side, obtained through the first-phase API aclnnCastGetWorkspaceSize. 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 Codes.
Constraints
Deterministic computation:
- aclnnCast defaults to a deterministic implementation.
For scenarios where the data type is converted from floating-point to integer:
If the input data contains NaN, NaN is converted to 0.
For scenarios where the input data type is BOOL, COMPLEX32, COMPLEX64, COMPLEX128, FLOAT4_E2M1, or FLOAT4_E1M2:
Non-contiguous input is not supported.
Atlas inference products ,Atlas training products ,Atlas A2 training products/Atlas A2 inference products ,Atlas A3 training products/Atlas A3 inference products :For scenarios where the data type is converted from int32 to int8:
Only accuracy without error is guaranteed for input data within the range of (-2048, 1920).
For scenarios where the data type is converted from float64/complex64/complex128 to uint8:
Only guarantees error-free precision when the input data is non-negative.
Atlas inference products :For conversion from float32 to int64 and from float32 to uint8:
Only guarantees error-free precision when the input data is within the range (-2147483648, 2147483583).
For conversion from int64 to float32:
Only the precision of input data within the range (-2147483648, 2147483647) is guaranteed to be error-free.
Ascend 950PR/Ascend 950DT :For scenarios where the output type is INT4: the last axis of the input shape being odd is not supported, and non-contiguous input is not supported.
For input and output types involving COMPLEX32, FLOAT4_E2M1, FLOAT4_E1M2, HIFLOAT8, FLOAT8_E5M2, FLOAT8_E4M3FN, or INT4, only the conversion paths in the following table are supported:
selfdata typeoutdata typeCOMPLEX32 COMPLEX64 COMPLEX32 FLOAT16 FLOAT16 COMPLEX32 FLOAT32/FLOAT16/BFLOAT16 FLOAT4_E2M1/FLOAT4_E1M2 FLOAT4_E2M1/FLOAT4_E1M2 FLOAT32/FLOAT16/BFLOAT16 FLOAT32/FLOAT16/BFLOAT16 HIFLOAT8/FLOAT8_E5M2/FLOAT8_E4M3FN HIFLOAT8/FLOAT8_E5M2/FLOAT8_E4M3FN FLOAT32/FLOAT16/BFLOAT16 HIFLOAT8/FLOAT8_E5M2/FLOAT8_E4M3FN FLOAT4_E2M1/FLOAT4_E1M2 FLOAT4_E2M1/FLOAT4_E1M2 HIFLOAT8/FLOAT8_E5M2/FLOAT8_E4M3FN INT32 INT4
Example
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_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)
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: perform 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-side 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);
// Call aclrtMemcpy to copy host-side data to the device-side 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 aclCreateTensor 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;
}
int main() {
// 1. (Boilerplate) Initialize the device/stream. See the ACL API documentation.
// Enter the deviceId based on your 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.
std::vector<int64_t> selfShape = {4, 2};
std::vector<int64_t> outShape = {4, 2};
void* selfDeviceAddr = nullptr;
void* outDeviceAddr = nullptr;
aclTensor* self = nullptr;
aclTensor* out = nullptr;
std::vector<float> selfHostData = {0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1};
std::vector<double> outHostData = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
// Create the self aclTensor.
ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the out aclTensor.
ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_DOUBLE, &out);
CHECK_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 aclnnCast.
ret = aclnnCastGetWorkspaceSize(self, aclDataType::ACL_DOUBLE, out, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCastGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
// Apply for device memory based on the workspaceSize calculated by the first-phase API.
void* workspaceAddr = nullptr;
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 aclnnCast.
ret = aclnnCast(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCast failed. ERROR: %d\n", ret); return ret);
// 4. (Boilerplate) Synchronize and 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 device memory to host memory. Modify based on the specific API definition.
auto size = GetShapeSize(outShape);
std::vector<double> resultData(size, 0);
ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
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: %f\n", i, resultData[i]);
}
// 6. Release the aclTensor. Modify based on the specific API definition.
aclDestroyTensor(self);
aclDestroyTensor(out);
// 7. Release device resources.
aclrtFree(selfDeviceAddr);
aclrtFree(outDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}