aclnnFusedLinearOnlineMaxSum
Applicable Products
| Product | Supported |
|---|---|
| √ | |
| √ | |
| √ | |
| × | |
| × | |
| × |
Function
Description:
Functionally equivalent to Megatron's matmul and fused_vocab_parallel_cross_entropy implementation, supports vocabulary_size dimension card-splitting fusion of matmul and celoss. The intermediate process is split into aclnnFusedLinearOnlineMaxSum and aclnnFusedCrossEntropyLossWithMaxSum based on communication, and they need to be called sequentially to implement the complete functionality.
Formula:
Perform matrix multiplication of and to obtain:
Calculate the maximum value of each row of :
Calculate the difference between and :
Calculate the sum of each row of after exponential operation.
Compute the mask where is less than or is greater than
Compute
Compute
Compute
Where .
Function Prototype
Each operator is a two-phase API. You must first call the "aclnnFusedLinearOnlineMaxSumGetWorkspaceSize" API to obtain the workspace size required for computation and the executor that contains the operator computation process, and then call the "aclnnFusedLinearOnlineMaxSum" API to perform the computation.
aclnnStatus aclnnFusedLinearOnlineMaxSumGetWorkspaceSize(
const aclTensor* input,
const aclTensor* weight,
const aclTensor* target,
int64_t vocabStartIndex,
int64_t vocabEndIndex,
aclTensor* logitsMaxLocalOut,
aclTensor* sumExpLogitsLocalOut,
aclTensor* predictedLogitsLocalOut,
aclTensor* targetMaskOut,
aclTensor* maskedTargetOut,
aclTensor* vocabParallelLogitsOutOptional,
uint64_t* workspaceSize,
aclOpExecutor** executor)aclnnStatus aclnnFusedLinearOnlineMaxSum(
void* workspace,
uint64_t workspaceSize,
aclOpExecutor* executor,
aclrtStream stream)aclnnFusedLinearOnlineMaxSumGetWorkspaceSize
Parameters
Parameter Input/Output Description Instruction Data Type Data Format Dimension (Shape) Non-contiguous Tensor input Input Represents the left matrix of the matmul computation, i.e., input in the formula. - Supports empty tensors.
- input.size(1) must be less than or equal to 65534.
BFLOAT16, FLOAT16 ND 2 √ weight Input Represents the right matrix of the matmul computation, i.e., weight in the formula. - Empty tensors are supported.
- The data type is consistent with input.
- weight.size(0) must be greater than 0.
- weight.size(1) must be consistent with input.size(1).
BFLOAT16, FLOAT16 ND 2 √ target Input Indicates the target index, i.e., target in the formula. - Supports empty tensors.
- target.size(0) must be consistent with input.size(0).
INT32, INT64 ND 1 √ vocabStartIndex Input Indicates the start index assigned to the current card, i.e., vocabStartIndex in the formula. - The value range is [0, max(target) - 1].
INT64 - - - vocabEndIndex Input Indicates the end index assigned to the current card, i.e., vocabEndIndex in the formula. - Value range: [vocabStartIndex, min(vocabStartIndex + weight.size(0) - 1, max(target) - 1)].
INT64 - - - logitsMaxLocalOut Output Represents the maximum value of each row after the matmul computation, corresponding to logitsMaxLocalOut in the formula. - logitsMaxLocalOut.size(0) must be consistent with input.size(0).
FLOAT32 ND 1 √ sumExpLogitsLocalOut Output Represents the result of subtracting the maximum value of each row from the matmul computation result, applying exp, and then summing within each row. This corresponds to sumExpLogitsLocalOut in the formula. - sumExpLogitsLocalOut.size(0) must be consistent with input.size(0).
FLOAT32 ND 1 √ predictedLogitsLocalOut Output Represents the result of subtracting the maximum value of each row from the matmul computation result and then filtering through maskedTargetOut, i.e., predictedLogitsLocalOut in the formula. - predictedLogitsLocalOut.size(0) must be consistent with input.size(0).
FLOAT32 ND 1 √ targetMaskOut Output Represents the mask used to filter the vocabulary, i.e., targetMaskOut in the formula. - shape is [(input.size(0) + 7) / 8].
UINT8 ND 1 √ maskedTargetOut Output Represents the result of target filtered by targetMaskOut, i.e., maskedTargetOut in the formula. - The data type must be the same as that of target.
- maskedTargetOut.size(0) must be the same as input.size(0).
INT32, INT64 ND 1 √ vocabParallelLogitsOutOptional Output Represents the matmul computation result, an optional output corresponding to vocabParallelLogitsOutOptional in the formula. - The data type must be consistent with input.
- The shape is [input.size(0), weight.size(0)].
- When vocabParallelLogitsOutOptional is nullptr, the memory-saving branch is used; otherwise, the high-performance branch is used.
BFLOAT16, FLOAT16 ND 2 √ 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. - - - - - Return Value
aclnnStatus: return status. For details, see aclnn Return Code. The first-phase API performs input parameter validation and reports an error in the following scenarios:
Return Code Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 The input, weight, target, logitsMaxLocalOut, sumExpLogitsLocalOut, predictedLogitsLocalOut, targetMaskOut, or maskedTargetOut is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data types of input, weight, target, logitsMaxLocalOut, sumExpLogitsLocalOut, predictedLogitsLocalOut, targetMaskOut, and maskedTargetOut are not within the supported range. vocabParallelLogitsOutOptional is not empty and its data type is not within the supported range. The data formats of input, weight, target, logitsMaxLocalOut, sumExpLogitsLocalOut, predictedLogitsLocalOut, targetMaskOut, and maskedTargetOut are not within the supported range. vocabParallelLogitsOutOptional is not empty and its data format is not within the supported range. The shapes of input, weight, target, logitsMaxLocalOut, sumExpLogitsLocalOut, predictedLogitsLocalOut, targetMaskOut, and maskedTargetOut do not meet the constraints. vocabParallelLogitsOutOptional is not empty and its shape does not meet the constraints. The data types of input and weight are inconsistent. The data types of target and maskedTargetOut are inconsistent. vocabParallelLogitsOutOptional is not a null pointer and its data type is inconsistent with that of input. vocabStartIndex is less than 0. vocabEndIndex is less than vocabStartIndex.
aclnnFusedLinearOnlineMaxSum
Parameters
Parameter Input/Output Description workspace Input Workspace memory address applied for on the Device side. workspaceSize Input Workspace size applied for on the Device side, obtained from the first-phase API aclnnFusedLinearOnlineMaxSumGetWorkspaceSize. executor Input Operator executor, which contains the operator computation process. stream Input Specifies the stream that executes the task. Return Value
aclnnStatus: return code. For details, see aclnn Return Code.
Constraints
Deterministic description:
Atlas A2 training products/Atlas A2 inference products ,Atlas A3 training products/Atlas A3 inference products : aclnnFusedLinearOnlineMaxSum defaults to a deterministic implementation.
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/opdev/fp16_t.h"
#include "aclnnop/aclnn_fused_linear_online_max_sum.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 shape_size = 1;
for (auto i : shape) {
shape_size *= i;
}
return shape_size;
}
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 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 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 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;
}
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);
// Handle the check as needed.
CHECK_RET(ret == 0, 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 mSize = 128;
int64_t kSize = 64;
int64_t nSize = 256;
std::vector<int64_t> inputShape = {mSize, kSize};
std::vector<int64_t> weightShape = {nSize, kSize};
std::vector<int64_t> targetShape = {mSize};
std::vector<int64_t> logitsMaxLocalOutShape = {mSize};
std::vector<int64_t> sumExpLogitsLocalOutShape = {mSize};
std::vector<int64_t> predictedLogitsLocalOutShape = {mSize};
std::vector<int64_t> targetMaskOutShape = {(mSize + 7) / 8};
std::vector<int64_t> maskedTargetOutShape = {mSize};
std::vector<int64_t> vocabParallelLogitsOutOptionalShape = {mSize, nSize};
void* inputDeviceAddr = nullptr;
void* weightDeviceAddr = nullptr;
void* tatgetDeviceAddr = nullptr;
void* logitsMaxLocalOutDeviceAddr = nullptr;
void* sumExpLogitsLocalOutDeviceAddr = nullptr;
void* predictedLogitsLocalOutDeviceAddr = nullptr;
void* targetMaskOutDeviceAddr = nullptr;
void* maskedTargetOutDeviceAddr = nullptr;
void* vocabParallelLogitsOutOptionalDeviceAddr = nullptr;
aclTensor* input = nullptr;
aclTensor* weight = nullptr;
aclTensor* target = nullptr;
aclTensor* logitsMaxLocalOut = nullptr;
aclTensor* sumExpLogitsLocalOut = nullptr;
aclTensor* predictedLogitsLocalOut = nullptr;
aclTensor* targetMaskOut = nullptr;
aclTensor* maskedTargetOut = nullptr;
aclTensor* vocabParallelLogitsOutOptional = nullptr;
std::vector<op::fp16_t> inputHostData(mSize * kSize, 1.0);
std::vector<op::fp16_t> weightHostData(nSize * kSize, 1.0);
std::vector<int32_t> targetHostData(mSize, 1);
std::vector<float> logitsMaxLocalOutHostData(mSize, 0);
std::vector<float> sumExpLogitsLocalOutHostData(mSize, 0);
std::vector<float> predictedLogitsLocalOutHostData(mSize, 0);
std::vector<uint8_t> targetMaskOutHostData((mSize + 7) / 8, 0);
std::vector<int32_t> maskedTargetOutHostData(mSize, 0);
std::vector<op::fp16_t> vocabParallelLogitsOutOptionalHostData(mSize * nSize, 0);
int64_t vocabStartIndex = 0;
int64_t vocabEndIndex = 64;
// Create the input aclTensor.
ret = CreateAclTensor(inputHostData, inputShape, &inputDeviceAddr, aclDataType::ACL_FLOAT16, &input);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the weight aclTensor.
ret = CreateAclTensor(weightHostData, weightShape, &weightDeviceAddr, aclDataType::ACL_FLOAT16, &weight);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the target aclTensor.
ret = CreateAclTensor(targetHostData, targetShape, &tatgetDeviceAddr, aclDataType::ACL_INT32, &target);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the logitsMaxLocalOut aclTensor.
ret = CreateAclTensor(logitsMaxLocalOutHostData, logitsMaxLocalOutShape, &logitsMaxLocalOutDeviceAddr, aclDataType::ACL_FLOAT, &logitsMaxLocalOut);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the sumExpLogitsLocalOut aclTensor.
ret = CreateAclTensor(sumExpLogitsLocalOutHostData, sumExpLogitsLocalOutShape, &sumExpLogitsLocalOutDeviceAddr, aclDataType::ACL_FLOAT, &sumExpLogitsLocalOut);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the predictedLogitsLocalOut aclTensor.
ret = CreateAclTensor(predictedLogitsLocalOutHostData, predictedLogitsLocalOutShape, &predictedLogitsLocalOutDeviceAddr, aclDataType::ACL_FLOAT, &predictedLogitsLocalOut);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the targetMaskOut aclTensor.
ret = CreateAclTensor(targetMaskOutHostData, targetMaskOutShape, &targetMaskOutDeviceAddr, aclDataType::ACL_UINT8, &targetMaskOut);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the maskedTargetOut aclTensor.
ret = CreateAclTensor(maskedTargetOutHostData, maskedTargetOutShape, &maskedTargetOutDeviceAddr, aclDataType::ACL_INT32, &maskedTargetOut);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the vocabParallelLogitsOutOptional aclTensor.
ret = CreateAclTensor(vocabParallelLogitsOutOptionalHostData, vocabParallelLogitsOutOptionalShape, &vocabParallelLogitsOutOptionalDeviceAddr, aclDataType::ACL_FLOAT16, &vocabParallelLogitsOutOptional);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// 3. Call the CANN operator library API. Replace with the specific API.
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
// Call the first-phase API of aclnnFusedLinearOnlineMaxSum.
ret = aclnnFusedLinearOnlineMaxSumGetWorkspaceSize(input, weight, target, vocabStartIndex, vocabEndIndex, logitsMaxLocalOut, sumExpLogitsLocalOut, predictedLogitsLocalOut, targetMaskOut, maskedTargetOut, vocabParallelLogitsOutOptional, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnFusedLinearOnlineMaxSumGetWorkspaceSize 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 aclnnFusedLinearOnlineMaxSum.
ret = aclnnFusedLinearOnlineMaxSum(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnFusedLinearOnlineMaxSum 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 the device memory to the host memory. Modify based on the specific API definition.
auto size = GetShapeSize(logitsMaxLocalOutShape);
std::vector<float> logitsMaxLocalOutResultData(size, 0);
ret = aclrtMemcpy(logitsMaxLocalOutResultData.data(), logitsMaxLocalOutResultData.size() * sizeof(logitsMaxLocalOutResultData[0]), logitsMaxLocalOutDeviceAddr, size * sizeof(logitsMaxLocalOutResultData[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("logitsMaxLocalOut[%ld] is: %f\n", i, logitsMaxLocalOutResultData[i]);
}
size = GetShapeSize(sumExpLogitsLocalOutShape);
std::vector<float> sumExpLogitsLocalOutResultData(size, 0);
ret = aclrtMemcpy(sumExpLogitsLocalOutResultData.data(), sumExpLogitsLocalOutResultData.size() * sizeof(sumExpLogitsLocalOutResultData[0]), sumExpLogitsLocalOutDeviceAddr, size * sizeof(sumExpLogitsLocalOutResultData[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("sumExpLogitsLocalOut[%ld] is: %f\n", i, sumExpLogitsLocalOutResultData[i]);
}
size = GetShapeSize(predictedLogitsLocalOutShape);
std::vector<float> predictedLogitsLocalOutResultData(size, 0);
ret = aclrtMemcpy(predictedLogitsLocalOutResultData.data(), predictedLogitsLocalOutResultData.size() * sizeof(predictedLogitsLocalOutResultData[0]), predictedLogitsLocalOutDeviceAddr, size * sizeof(predictedLogitsLocalOutResultData[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("predictedLogitsLocalOut[%ld] is: %f\n", i, predictedLogitsLocalOutResultData[i]);
}
size = GetShapeSize(targetMaskOutShape);
std::vector<uint8_t> targetMaskOutResultData(size, 0);
ret = aclrtMemcpy(targetMaskOutResultData.data(), targetMaskOutResultData.size() * sizeof(targetMaskOutResultData[0]), targetMaskOutDeviceAddr, size * sizeof(targetMaskOutResultData[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("targetMaskOut[%ld] is: %hhu\n", i, targetMaskOutResultData[i]);
}
size = GetShapeSize(maskedTargetOutShape);
std::vector<int32_t> maskedTargetOutResultData(size, 0);
ret = aclrtMemcpy(maskedTargetOutResultData.data(), maskedTargetOutResultData.size() * sizeof(maskedTargetOutResultData[0]), maskedTargetOutDeviceAddr, size * sizeof(maskedTargetOutResultData[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("maskedTargetOut[%ld] is: %d\n", i, maskedTargetOutResultData[i]);
}
size = GetShapeSize(vocabParallelLogitsOutOptionalShape);
std::vector<op::fp16_t> vocabParallelLogitsOutOptionalResultData(size, 0);
ret = aclrtMemcpy(vocabParallelLogitsOutOptionalResultData.data(), vocabParallelLogitsOutOptionalResultData.size() * sizeof(vocabParallelLogitsOutOptionalResultData[0]), vocabParallelLogitsOutOptionalDeviceAddr, size * sizeof(vocabParallelLogitsOutOptionalResultData[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("vocabParallelLogitsOutOptional[%ld] is: %f\n", i, static_cast<float>(vocabParallelLogitsOutOptionalResultData[i]));
}
// 6. Release aclTensor and aclScalar. Modify based on the specific API definition.
aclDestroyTensor(input);
aclDestroyTensor(weight);
aclDestroyTensor(target);
aclDestroyTensor(logitsMaxLocalOut);
aclDestroyTensor(sumExpLogitsLocalOut);
aclDestroyTensor(predictedLogitsLocalOut);
aclDestroyTensor(targetMaskOut);
aclDestroyTensor(maskedTargetOut);
aclDestroyTensor(vocabParallelLogitsOutOptional);
// 7. Release device resources. Modify based on the specific API definition.
aclrtFree(inputDeviceAddr);
aclrtFree(weightDeviceAddr);
aclrtFree(tatgetDeviceAddr);
aclrtFree(logitsMaxLocalOutDeviceAddr);
aclrtFree(sumExpLogitsLocalOutDeviceAddr);
aclrtFree(predictedLogitsLocalOutDeviceAddr);
aclrtFree(targetMaskOutDeviceAddr);
aclrtFree(maskedTargetOutDeviceAddr);
aclrtFree(vocabParallelLogitsOutOptionalDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}