aclnnHansEncode
Applicable Products
| Product | Supported |
|---|---|
| × | |
| √ | |
| √ | |
| × | |
| × | |
| × |
Function
Performs PDF statistics on the byte where the exponent bits of the inputTensor reside (optional), and performs lossless compression based on the PDF distribution. The compressed result can be stored in the device HBM or offloaded to the host side.
Function Prototype
Each operator is divided into a two-phase API. The "aclnnHansEncodeGetWorkspaceSize" API must be called first to obtain the workspace size required for computation and the executor that encapsulates the operator computation flow. Then, the "aclnnHansEncode" API is called to perform the computation.
aclnnStatus aclnnHansEncodeGetWorkspaceSize(const aclTensor *inputTensor, aclTensor *pdfRef, bool statistic, bool reshuff, const aclTensor *mantissaOut, const aclTensor *fixedOut, const aclTensor *varOut, uint64_t *workspaceSize, aclOpExecutor **executor);aclnnStatus aclnnHansEncode(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)
aclnnHansEncodeGetWorkspaceSize
Parameters:
inputTensor(aclTensor*, computation input): Represents the input tensor to be compressed, which is an aclTensor on the Device side. Data types supported include FLOAT16, BFLOAT16, and FLOAT32. The data element size must be a multiple of 64 and greater than or equal to 32768. Supports Non-contiguous Tensor. The Data Format supports ND.
pdfRef(aclTensor*, computation input/computation output): Represents the probability density distribution of the byte where the exponent bits of inputTensor reside, which is an aclTensor on the Device side. The data type supports INT32. The shape must be (1, 256). Supports Non-contiguous Tensor. The Data Format supports ND.
statistic(bool, computation input): Whether to perform PDF statistics.
reshuff(bool, computation input): Whether to perform memory reorganization on the encoded results of each core.
mantissaOut(aclTensor*, computation output): Indicates the output mantissa part, which is an aclTensor on the Device side. The data type supports FLOAT16, BFLOAT16, and FLOAT32, and must be consistent with inputTensor. Supports Non-contiguous Tensor. The Data Format supports ND.
fixedOut(aclTensor*, computation output): Indicates the first segment of compressed output, which is an aclTensor on the Device side. The data type supports FLOAT16, BFLOAT16, and FLOAT32, and must be consistent with inputTensor. Supports Non-contiguous Tensor. The Data Format supports ND.
varOut(aclTensor*, computation output): Indicates the output beyond fixedOut after compression, which is an aclTensor on the Device side. The data type supports FLOAT16, BFLOAT16, and FLOAT32, and must be consistent with inputTensor. Supports Non-contiguous Tensor. The Data Format supports ND.
workspaceSize(uint64_t*, output parameter): Returns the workspace size to be allocated on the Device side.
executor(aclOpExecutor**, output parameter): Returns the op executor, which contains the operator computation flow.
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 inputTensor, pdf, mantissaOut, fixedOut, and varOut are null pointers. ACLNN_ERR_PARAM_INVALID 161002 The pdf length is incorrect or the mantissa length is incorrect. The cumulative encoding space is set too small, posing an overflow risk during compression. The following formula must be satisfied: (size(fixedOut) + size(mantissaOut)) >= (len(inputTensor) + len(inputTensor) / 64 + 8448 * processCoreDim). The size(fixedOut) is less than 512 bytes and cannot store the compression metadata. The number of input elements is not a multiple of 64 or is less than 32768. The data types of inputTensor, pdf, and outputMantissaTensorOut are not supported.
aclnnHansEncode
Parameters:
Parameter Input/Output Description workspace Input Specifies the workspace memory address applied on the Device side. workspaceSize Input Specifies the workspace size applied on the Device side, obtained by the first-phase API aclnnHansEncodeGetWorkspaceSize. executor Input Operator executor that 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
None.
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 "aclnn_hans_encode.h"
#include "aclnn_hans_decode.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 for AscendCL 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 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);
// Compute 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 AscendCL API list.
// Fill in 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<float> inputHost(65536, 0);
std::vector<float> mantissaHost(49152, 0);
std::vector<float> fixedHost(16384, 0);
std::vector<float> varHost(16384, 0);
std::vector<int32_t> pdfHost(256, 0);
std::vector<float> recoverHost(65536, 0);
bool statistic = true;
bool reshuff = false;
int64_t outHostAddr = -1;
int64_t outHostLength = 0;
void* inputAddr = nullptr;
void* outMantissaAddr = nullptr;
void* outFixedAddr = nullptr;
void* outVarAddr = nullptr;
void* pdfAddr = nullptr;
void* recoverAddr = nullptr;
aclTensor* input = nullptr;
aclTensor* outMantissa = nullptr;
aclTensor* outFixed = nullptr;
aclTensor* pdf = nullptr;
aclTensor* outVar = nullptr;
aclTensor* recover = nullptr;
// Create the output aclTensor.
ret = CreateAclTensor(inputHost, {1, 65536}, &inputAddr, aclDataType::ACL_FLOAT, &input);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(mantissaHost, {1, 49152}, &outMantissaAddr, aclDataType::ACL_FLOAT, &outMantissa);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(fixedHost, {1, 16384}, &outFixedAddr, aclDataType::ACL_FLOAT, &outFixed);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(varHost, {1, 16384}, &outVarAddr, aclDataType::ACL_FLOAT, &outVar);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(pdfHost, {1, 256}, &pdfAddr, aclDataType::ACL_INT32, &pdf);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(recoverHost, {1, 65536}, &recoverAddr, aclDataType::ACL_FLOAT, &recover);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// 3. Call the CANN operator library API. Replace it with the specific API name.
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
// Call the first-phase API of aclnnHansEncode.
ret = aclnnHansEncodeGetWorkspaceSize(input, pdf, statistic, reshuff, outMantissa, outFixed, outVar, &workspaceSize,
&executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnHansEncodeGetWorkspaceSize 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 aclnnHansEncode.
ret = aclnnHansEncode(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnHansEncode 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 memory. Modify based on the specific API definition.
auto size = 16384 * sizeof(float);
std::vector<float> resultData(16384, 0);
ret = aclrtMemcpy(resultData.data(), size, outFixedAddr, size, 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 < 128; i++) {
int32_t intVal = *reinterpret_cast<int32_t*>(&resultData[i]);
LOG_PRINT("result header[%ld] is: %d\n", i, intVal);
}
uint64_t workspaceSizeDecode = 0;
aclOpExecutor* executorDecode;
// Call the first-phase API of aclnnHansDecode.
ret = aclnnHansDecodeGetWorkspaceSize(outMantissa, outFixed, outVar, pdf, reshuff, recover, &workspaceSizeDecode,
&executorDecode);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnHansDecodeGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
// Apply for device memory based on the workspaceSize calculated by the first-phase API.
void* workspaceAddrDecode = nullptr;
if (workspaceSizeDecode > 0) {
ret = aclrtMalloc(&workspaceAddrDecode, workspaceSizeDecode, 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 aclnnHansEncode.
ret = aclnnHansDecode(workspaceAddrDecode, workspaceSizeDecode, executorDecode, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnHansDecode failed. ERROR: %d\n", ret); return ret);
ret = aclrtSynchronizeStream(stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
std::vector<float> recoverData(65536, 0);
ret = aclrtMemcpy(recoverData.data(), 65536 * sizeof(recoverData[0]), recoverAddr, 65536 * sizeof(recoverData[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 < 256; i++) {
LOG_PRINT("reco[%ld] is: %f org is: %f\n", i, recoverData[i], inputHost[i]);
}
// 6. Release aclTensor. Modify based on the specific API definition.
aclDestroyTensor(input);
aclDestroyTensor(outMantissa);
aclDestroyTensor(outFixed);
aclDestroyTensor(outVar);
aclDestroyTensor(pdf);
aclDestroyTensor(recover);
// 7. Release device resources. Modify based on the specific API definition.
aclrtFree(inputAddr);
aclrtFree(outMantissaAddr);
aclrtFree(outFixedAddr);
aclrtFree(outVarAddr);
aclrtFree(pdfAddr);
aclrtFree(recoverAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
if (workspaceSizeDecode > 0) {
aclrtFree(workspaceAddrDecode);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}