aclnnStridedSlice

📄 View Source Code

Applicable Products

ProductSupported
Ascend 950PR/Ascend 950DT√
Atlas A3 training products/Atlas A3 inference products×
Atlas A2 training products/Atlas A2 inference products×
Atlas 200I/500 A2 inference products×
Atlas inference products×
Atlas training products×

Function

  • Description: Extracts a sub-tensor from the input tensor based on the specified start position, end position, and stride.

  • Formula: In the specified dimension dimdim, extracts a sub-tensor outout from the input tensor selfself based on the specified start position beginbegin, end position endend, and stride stridesstrides.

    beginbegin and endend can take values outside [0,self.shape[dim]][0, self.shape[dim]]. After taking a value, it is converted to a valid value according to the following formula, assuming self.shape[dim] = N:

    begin={0,if  begin<−NN,if  begin>=N(begin+N)%N,otherwisebegin = \begin{cases} &0, & if\;begin < -N \\ &N, & if\;begin >= N\\ &(begin+N) \% N, & otherwise \end{cases} end={N,if  end>=Nbegin,else  if  (end+N)%N<begin(end+N)%N,otherwiseend = \begin{cases} &N, & if\; end >= N\\ &begin, & else\;if\; (end+N)\%N < begin \\ &(end+N)\%N, & otherwise\\ \end{cases}

    out.shapeout.shape differs from self.shapeself.shape only on the dim axis, and is consistent on other axes:

    out.shape[dim]=⌊end−begin+strides−1strides⌋out.shape[dim] = ⌊\frac{end - begin + strides - 1}{strides}⌋

    If mask parameters are present, the outshape is further computed according to the following rules: beginMaskbeginMask specifies that the beginbegin of the index dimension corresponding to the bitbit set to 1 is ignored, endMaskendMask specifies that the endend of the index dimension corresponding to the bitbit set to 1 is ignored, ellipsisMaskellipsisMask selects all subsequent dimensions starting from the index dimension corresponding to the bitbit set to 1, until a specified beginbegin is encountered, newAxisMasknewAxisMask specifies that a dimension with shapeshape 1 is added to the index dimension corresponding to the bitbit set to 1, shrinkAxisMaskshrinkAxisMask specifies that the index dimension corresponding to the bitbit set to 1 is forcibly reduced to 1.

Function Prototype

Each operator is divided into a two-phase API. The "aclnnStridedSliceGetWorkspaceSize" API must be called first to obtain the workspace size required for computation and the executor that encapsulates the operator computation flow. Then, the "aclnnStridedSlice" API is called to perform the computation.

aclnnStatus aclnnStridedSliceGetWorkspaceSize(
    const aclTensor   *self,
    const aclIntArray *begin,
    const aclIntArray *end,
    const aclIntArray *strides,
    int64_t           beginMask,
    int64_t           endMask,
    int64_t           ellipsisMask,
    int64_t           newAxisMask,
    int64_t           shrinkAxisMask,
    aclTensor         *out,
    uint64_t          *workspaceSize,
    aclOpExecutor     **executor)
aclnnStatus aclnnStridedSlice(
    void          *workspace,
    uint64_t       workspaceSize,
    aclOpExecutor *executor,
    aclrtStream    stream)

aclnnStridedSliceGetWorkspaceSize

  • Parameters:

    Parameter Input/Output Description Instruction Data Type Data Format Dimension (Shape) Non-contiguous Tensor
    self Input Input tensor. The data type of self must be consistent with that of out. INT8, UINT8, INT16, UINT16, INT32, UINT32, INT64, UINT64, FLOAT, FLOAT16, BF16, BOOL, COMPLEX32, COMPLEX64, HIFLOAT8, FLOAT8_E5M2, FLOAT8_E4M3FN ND 0-8 √
    begin Input Start value of each dimension. The array lengths of begin, end, and strides must be consistent. INT32, INT64 - - -
    end Input Specifies the end value of each dimension. The begin, end, and strides arrays must have consistent lengths. INT32, INT64 - - -
    strides Input The stride for each point in each dimension. The lengths of the begin, end, and strides arrays must be consistent, and the strides values cannot be 0. INT32, INT64 - - -
    beginMask Input Specifies that the begin value of the index dimension whose corresponding bit is 1 is ignored. - INT64 - - -
    endMask Input Specifies that the end of the index dimension corresponding to the bit set to 1 is ignored. - INT64 - - -
    ellipsisMask Input Selects all elements starting from the index dimension corresponding to the bit set to 1, until a specified begin is encountered. ellipsisMask can have only one bit set to 1. INT64 - - -
    newAxisMask Input Adds a dimension of size 1 to the index dimension corresponding to the bit set to 1. - INT64 - - -
    shrinkAxisMask Input Forcibly reduces the index dimension corresponding to bit 1 to 1. For the index with bit 1 in shrinkAxisMask, the corresponding strides must be greater than 0, i.e., positive. INT64 - - -
    out Output Output tensor. The data type of self and out must be consistent. INT8, UINT8, INT16, UINT16, INT32, UINT32, INT64, UINT64, FLOAT, FLOAT16, BF16, BOOL, COMPLEX32, COMPLEX64, HIFLOAT8, FLOAT8_E5M2, FLOAT8_E4M3FN ND - √
    workspaceSize Output Returns the workspace size to be applied for on the Device side. - - - - -
    executor Output Returns the operator executor, which includes 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 The self, begin, end, strides, or out passed in is a null pointer.
    ACLNN_ERR_PARAM_INVALID 161002 The data type of self or out is not within the supported range.
    The data types of self and out are inconsistent.
    The dimension of self exceeds 8.
    The lengths of begin, end, and strides are inconsistent.
    strides contains an element equal to 0.
    The data dimension of out differs from the dimension of infershape.
    The product model is not within the supported range.
    More than one bit in ellipsisMask is set to 1.
    The stride corresponding to the index with bit 1 in shrinkAxisMask is less than 0.

aclnnStridedSlice

  • Parameters:

    Parameter Input/Output Description
    workspace Input Device-side workspace memory address.
    workspaceSize Input Device-side workspace size, obtained from the first-phase API aclnnStridedSliceGetWorkspaceSize.
    executor Input Specifies the op executor, which includes the computation process of the operator.
    stream Input Specifies the stream that executes the task.
  • Return value:

    aclnnStatus: return code. For details, see aclnn Return Codes.

Constraints

  • Deterministic computation:

    • aclnnStridedSlice 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.

/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */
#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_strided_slice.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: 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);

    // 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 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 documentation.
    // 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. Custom construction is required based on the API.
    std::vector<int64_t> selfShape = {4, 3};
    std::vector<int64_t> outShape = {2, 2};
    void* selfDeviceAddr = nullptr;
    void* outDeviceAddr = nullptr;
    aclTensor* self = nullptr;
    aclIntArray* begin = nullptr;
    aclIntArray* end = nullptr;
    aclIntArray* strides = nullptr;
    aclTensor* out = nullptr;

    std::vector<float> selfHostData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
    std::vector<int64_t> beginData = {1, 1};
    std::vector<int64_t> endData = {3, 3};
    std::vector<int64_t> stridesData = {1, 1};
    std::vector<float> outHostData(4, 0);
    int64_t beginMask = 0;
    int64_t endMask = 0;
    int64_t ellipsisMask = 0;
    int64_t newAxisMask = 0;
    int64_t shrinkAxisMask = 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_FLOAT, &out);
    CHECK_RET(ret == ACL_SUCCESS, return ret);
    // Create the aclIntArray.
    begin = aclCreateIntArray(beginData.data(), 2);
    CHECK_RET(begin != nullptr, return ret);
    end = aclCreateIntArray(endData.data(), 2);
    CHECK_RET(end != nullptr, return ret);
    strides = aclCreateIntArray(stridesData.data(), 2);
    CHECK_RET(strides != nullptr, return ret);

    // 3. Call the CANN operator library API. Replace with the actual API name.
    uint64_t workspaceSize = 0;
    aclOpExecutor* executor;
    // Call the first-phase API of aclnnStridedSlice.
    ret = aclnnStridedSliceGetWorkspaceSize(
        self, begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask, out, &workspaceSize,
        &executor);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnStridedSliceGetWorkspaceSize 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 aclnnCast second-phase API.
    ret = aclnnStridedSlice(workspaceAddr, workspaceSize, executor, stream);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnStridedSlice 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 device memory to the host side. Modify based on the specific API definition.
    auto size = GetShapeSize(outShape);
    std::vector<float> 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 aclTensor. Modify based on the specific API definition.
    aclDestroyTensor(self);
    aclDestroyIntArray(begin);
    aclDestroyIntArray(end);
    aclDestroyIntArray(strides);
    aclDestroyTensor(out);

    // 7. Release device resources.
    aclrtFree(selfDeviceAddr);
    aclrtFree(outDeviceAddr);
    if (workspaceSize > 0) {
        aclrtFree(workspaceAddr);
    }
    aclrtDestroyStream(stream);
    aclrtResetDevice(deviceId);
    aclFinalize();

    return 0;
}