aclnnCtcLoss
Product Support
| Product | Supported |
|---|---|
| √ | |
| √ | |
| × | |
| √ | |
| √ |
Function
Description: Computes the connectionist temporal classification (CTC) loss.
Formula: Let denote the probability that the true character is at time step (typically, is an element of the output matrix after the softmax operation). Let denote the set of all sequences that can be formed from the character set . Each sequence in is called a path and denoted by . The distribution of is given by Equation (1):
Define a many-to-one mapping B: . The conditional probability of is the sum of the probabilities of all paths corresponding to under mapping B, as shown in Equation (2):
The task of finding the label that maximizes is referred to as decoding, as expressed in Equation (3):
When zeroInfinity is True:
Prototype
Each operator has two-phase API calls. First, aclnnCtcLossGetWorkspaceSize is called to obtain the workspace size required for computation and the executor that contains the operator computation flow. Then, aclnnCtcLoss is called to perform computation.
aclnnStatus aclnnCtcLossGetWorkspaceSize(
const aclTensor* logProbs,
const aclTensor* targets,
const aclIntArray* inputLengths,
const aclIntArray* targetLengths,
int64_t blank, bool zeroInfinity,
aclTensor* negLogLikelihoodOut,
aclTensor* logAlphaOut,
uint64_t* workspaceSize,
aclOpExecutor** executor)aclnnStatus aclnnCtcLoss(
void* workspace,
uint64_t workspaceSize,
aclOpExecutor* executor,
aclrtStream stream)aclnnCtcLossGetWorkspaceSize
Parameters
Name Input/Output Description Usage Notes Data Type Data Format Shape Non-contiguous Tensor logProbs Input Log probabilities of the output, corresponding to y in the formula. - FLOAT16, FLOAT, BFLOAT16 ND (T, N, C) or (T, C)
T: input length, N: batch size, C: number of classes (must be greater than 0, including the blank label).√ targets Input Target sequence labels, corresponding to π in the formula. If the shape is (N, S), S must be greater than or equal to the maximum value in targetLengths. If the shape is (SUM(targetLengths)), targets must be unpadded and concatenated in 1D. When logProbs is 2D, N equals 1. INT64, INT32, BOOL, FLOAT, FLOAT16 ND - √ inputLengths Input Actual lengths of the input sequences. T in the formula is an element in inputLengths. The array length is N. Each value in the array must be less than or equal to T. When logProbs is 2D, N equals 1. - - - - targetLengths Input Actual lengths of the target sequences. l in the formula is an element in targetLengths. The array length is N. When the shape of targets is (N, S), each value in the array must be less than or equal to S. When logProbs is 2D, N equals 1. - - - - blank Input Blank label index. The value must be in the range [0, C). - - - - zeroInfinity Input Whether to zero out infinite losses and associated gradients, corresponding to zeroInfinity in the formula. - - - - - negLogLikelihoodOut Output Output loss value, corresponding to h in the formula. The data type must be the same as that of logProbs. If logProbs is 3D, negLogLikelihoodOut is a tensor with shape (N). Otherwise, negLogLikelihoodOut is a 0D tensor. Same as logProbs. ND - √ logAlphaOut Output Log probability of possible input-to-target alignments, corresponding to p(l|x) in the formula. The data type must be the same as that of logProbs. When logProbs is 2D, N equals 1. Same as logProbs. ND - √ workspaceSize Output Size of the workspace to be allocated on the device. - - - - - executor Output Operator executor, containing the operator computation flow. - - - - - - For
Atlas inference series products andAtlas training series products , the data type cannot be FLOAT16 or BFLOAT16. - logAlphaOut:
- For
Atlas inference series products ,Atlas training series products ,Atlas A2 training products/Atlas A2 inference products , andAtlas A3 training series products/Atlas A3 inference series products , the shape is ().
- For
- For
Returns
aclnnStatus: status code. For details, see aclnn Return Codes.
The first-phase API implements input parameter verification. The following errors may be thrown.
Return Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 The passed logProbs, targets, inputLengths, targetLengths, negLogLikelihoodOut, or logAlphaOut is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data type of logProbs, targets, inputLengths, or targetLengths is not supported. The tensor shape of logProbs, targets, inputLengths, targetLengths, negLogLikelihoodOut, or logAlphaOut does not meet the corresponding requirements, or the length of the inputLengths or targetLengths array does not meet the requirements. blank is out of the valid value range.
aclnnCtcLoss
Parameters
Name Input/Output Description workspace Input Address of the workspace to be allocated on the device. workspaceSize Input Size of the workspace to be allocated on the device, which is obtained by calling the first-phase API aclnnCtcLossGetWorkspaceSize. executor Input Operator executor, containing the operator computation flow. stream Input Stream for executing the task. Returns
aclnnStatus: status code. For details, see aclnn Return Codes.
Constraints
Value range constraints
- The values in
targetsmust be in the range and must not include the value corresponding to blank, where is the last dimension oflogProbs, representing the number of classes. - The values in
input_lengthsmust be in the range , where is the zeroth dimension oflogProbs, representing the input length. - The values in
target_lengthsmust be greater than or equal to 1. - Each element in
target_lengthsmust be less than or equal to the corresponding elements ininput_lengths.
If the first three constraints are violated, out-of-bounds behavior may occur on CPU/GPU, which may cause the computed results of negLogLikelihoodOut and logAlphaOut to differ from the CPU/GPU reference. If the fourth constraint is violated, the computed result of logAlphaOut for the corresponding batch may differ from the CPU/GPU reference.
- The values in
Deterministic computation:
- aclnnCtcLoss defaults to a non-deterministic implementation. You can call aclrtCtxSetSysParamOpt to enable deterministic computation.
Example
For the
Atlas inference series products ,Atlas training series products ,Atlas A2 training products/Atlas A2 inference products , andAtlas A3 training series products/Atlas A3 inference series products , the sample code is as follows, which is for reference only. For details, see Compilation and Running Sample.#include <iostream> #include <vector> #include "acl/acl.h" #include "aclnnop/aclnn_ctc_loss.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) 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. 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 the data on the host to the memory on the device. 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 the 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 and stream. For details, see the ACL API manual. // Set the device ID (deviceId) based on the actual device. int32_t deviceId = 0; aclrtStream stream; auto ret = Init(deviceId, &stream); // Customize error handling based on your requirements. CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); // 2. Construct inputs and outputs based on API definitions. std::vector<int64_t> logProbsShape = {12, 4, 5}; std::vector<int64_t> targetsShape = {4, 7}; std::vector<int64_t> negLoglikelihoodOutShape = {4}; std::vector<int64_t> logAlphaOutShape = {4, 12, 16}; void* logProbsDeviceAddr = nullptr; void* targetsDeviceAddr = nullptr; void* negLoglikelihoodOutDeviceAddr = nullptr; void* logAlphaOutDeviceAddr = nullptr; aclTensor* logProbs = nullptr; aclTensor* targets = nullptr; aclIntArray* inputLengths = nullptr; aclIntArray* targetLengths = nullptr; aclTensor* negLoglikelihoodOut = nullptr; aclTensor* logAlphaOut = nullptr; std::vector<float> logProbsHostData = { -1.0894, -2.7162, -0.9764, -1.9126, -2.6162, -2.0684, -2.4871, -2.0866, -1.7205, -0.7187, -2.4423, -1.2017, -1.4653, -1.1821, -2.5942, -2.4670, -2.7257, -1.4135, -2.1042, -0.7248, -3.7759, -1.3742, -1.2549, -1.5807, -1.4562, -1.3826, -1.8995, -1.8527, -0.9493, -2.8895, -1.6316, -2.6603, -2.5014, -0.6992, -1.8609, -1.9269, -2.2350, -0.8073, -1.8906, -1.8947, -0.3468, -2.5855, -2.0723, -2.7147, -3.6668, -0.9541, -1.7258, -2.0693, -1.6378, -2.1531, -3.5386, -3.4830, -0.2532, -2.0557, -3.3261, -1.1480, -1.8080, -0.8244, -3.2414, -3.1909, -0.8866, -0.7540, -4.4312, -3.4634, -2.6000, -1.2785, -1.8347, -3.3122, -0.7620, -2.8349, -1.4975, -1.3865, -0.9645, -3.8171, -2.0939, -2.3536, -2.0773, -1.4981, -0.8372, -2.0938, -1.2186, -0.8285, -2.9399, -2.1159, -2.3620, -2.3139, -0.6503, -2.7249, -1.2340, -3.7927, -0.7143, -2.5084, -3.2826, -2.6651, -1.1334, -1.6965, -1.9728, -2.3849, -1.6052, -0.9554, -1.6384, -1.2596, -2.1680, -1.8476, -1.3866, -3.0455, -0.5737, -2.5339, -2.1118, -1.6681, -2.4675, -2.8842, -0.4329, -3.6266, -1.6925, -3.1023, -2.7696, -1.2755, -0.6470, -2.4143, -2.0107, -2.0912, -1.3053, -0.8557, -3.0683, -1.2872, -3.6523, -1.6703, -2.7596, -0.8063, -2.4633, -1.2959, -1.6153, -2.3072, -1.0705, -3.0543, -0.6473, -1.1650, -2.9025, -2.7710, -3.5519, -2.0400, -1.8667, -1.4289, -0.8050, -1.4602, -0.7452, -1.5754, -3.1624, -3.1247, -1.4677, -1.2725, -2.9575, -1.8883, -1.2513, -1.2164, -1.5894, -2.2217, -2.3714, -1.2110, -2.0843, -0.6515, -1.4252, -2.9402, -2.7964, -1.5261, -2.5471, -1.7167, -1.9846, -0.9488, -1.4847, -1.7093, -1.4095, -1.7293, -1.7675, -0.9203, -4.2299, -1.8740, -1.4076, -1.6671, -1.9052, -0.8330, -2.1839, -2.2459, -1.6193, -2.9108, -1.2114, -1.4616, -1.7297, -1.4330, -2.2656, -0.7878, -1.8533, -1.8711, -2.0349, -2.2457, -2.1395, -1.4509, -0.7538, -2.6381, -0.8078, -2.1054, -2.6703, -1.1108, -3.3867, -1.7774, -1.8426, -1.9473, -1.3293, -1.3273, -1.3490, -1.9842, -2.5357, -2.2161, -0.8800, -1.5412, -1.8003, -2.7603, -0.8606, -2.0066, -1.8342, -2.2741, -1.8348, -1.5833, -0.9877, -3.5196, -2.3361, -0.9124, -0.9307, -2.5531, -1.4862, -1.2153, -1.4453, -3.4462, -1.5625, -2.6455, -1.4153, -1.3079, -1.1568, -2.2897}; std::vector<int64_t> targetsHostData = { 1, 2, 1, 1, 2, 4, 1, 2, 2, 2, 2, 2, 2, 3, 4, 2, 1, 4, 3, 1, 4, 4, 1, 4, 2, 2, 2, 3}; std::vector<float> negLoglikelihoodOutHostData = {0, 0, 0, 0}; std::vector<float> logAlphaOutHostData = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // Create a logProbs aclTensor. ret = CreateAclTensor(logProbsHostData, logProbsShape, &logProbsDeviceAddr, aclDataType::ACL_FLOAT, &logProbs); CHECK_RET(ret == ACL_SUCCESS, return ret); // Create a targets aclTensor. ret = CreateAclTensor(targetsHostData, targetsShape, &targetsDeviceAddr, aclDataType::ACL_INT64, &targets); CHECK_RET(ret == ACL_SUCCESS, return ret); std::vector<int64_t> inputLengthsSizeData = {10,10,10,10}; inputLengths = aclCreateIntArray(inputLengthsSizeData.data(), 4); CHECK_RET(inputLengths != nullptr, return ACL_ERROR_BAD_ALLOC); std::vector<int64_t> targetLengthsSizeData = {2, 3, 1, 5}; targetLengths = aclCreateIntArray(targetLengthsSizeData.data(), 4); CHECK_RET(targetLengths != nullptr, return ACL_ERROR_BAD_ALLOC); // Create a negLoglikelihoodOut aclTensor. ret = CreateAclTensor(negLoglikelihoodOutHostData, negLoglikelihoodOutShape, &negLoglikelihoodOutDeviceAddr, aclDataType::ACL_FLOAT, &negLoglikelihoodOut); CHECK_RET(ret == ACL_SUCCESS, return ret); // Create a logAlphaOut aclTensor. ret = CreateAclTensor(logAlphaOutHostData, logAlphaOutShape, &logAlphaOutDeviceAddr, aclDataType::ACL_FLOAT, &logAlphaOut); CHECK_RET(ret == ACL_SUCCESS, return ret); // 3. Call the CANN operator library API. Modify the API as required. uint64_t workspaceSize = 0; aclOpExecutor* executor; // Call the first-phase API of aclnnCtcLoss. ret = aclnnCtcLossGetWorkspaceSize(logProbs, targets, inputLengths, targetLengths, 0, false, negLoglikelihoodOut, logAlphaOut, &workspaceSize, &executor); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCtcLossGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); // Allocate device memory based on workspaceSize computed 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 aclnnCtcLoss. ret = aclnnCtcLoss(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCtcLoss failed. ERROR: %d\n", ret); return ret); // 4. (Boilerplate) Synchronize the stream and wait for task completion. ret = aclrtSynchronizeStream(stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); // 5. Obtain the output negLoglikelihoodOut and copy the result from the device to the host. Modify the code based on the API definition. auto size = GetShapeSize(negLoglikelihoodOutShape); std::vector<float> resultData(size, 0); ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), negLoglikelihoodOutDeviceAddr, size * sizeof(float), 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("negLoglikelihoodOut result[%ld] is: %f\n", i, resultData[i]); } // 6. Obtain the output logAlphaOut and copy the result from the device to the host. Modify the code based on the API definition. auto size1 = GetShapeSize(logAlphaOutShape); std::vector<float> resultData1(size1, 0); ret = aclrtMemcpy(resultData1.data(), resultData1.size() * sizeof(resultData1[0]), logAlphaOutDeviceAddr, size1 * sizeof(float), 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 < size1; i++) { LOG_PRINT("logAlphaOut result[%ld] is: %f\n", i, resultData1[i]); } // 7. Destroy aclTensor and IntArray. Modify the code based on the API definition. aclDestroyTensor(logProbs); aclDestroyTensor(targets); aclDestroyIntArray(inputLengths); aclDestroyIntArray(targetLengths); aclDestroyTensor(negLoglikelihoodOut); aclDestroyTensor(logAlphaOut); // 8. Release device resources. Modify the code based on the API definition. aclrtFree(logProbsDeviceAddr); aclrtFree(targetsDeviceAddr); aclrtFree(negLoglikelihoodOutDeviceAddr); aclrtFree(logAlphaOutDeviceAddr); if (workspaceSize > 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }