图使用

在通过加速库进行开发时,请使用张量作为输入。

操作步骤

  1. 构造GraphParam对象。

    首先根据设计的图算子结构,分别计算出图输入Tensor(假设为x个),图输出Tensor(假设为y个)以及图中间Tensor(假设为z个)的个数,则图输入Tensor取值为[0, x - 1],图输出Tensor取值为[x, x + y - 1],图中间Tensor取值为[x + y, x + y + z - 1]。输入nodes中的每一个Node元素包含组成该图算子的一个operation的相关信息,根据用户定义的图结构,各个operation的输入、输出Tensor在整个图算子中可能充当图输入、输出或中间Tensor,用户需根据其所属的图Tensor类型,在合适的范围内取值。

    atb::GraphParam graphParam = { ... };

  2. 调用CreateOperation函数返回Operation对象。

    atb::Operation *operation = nullptr;
    atb::Status st = atb::CreateOperation(graphParam, &operation);

  3. 创建Context并设置Stream。

    atb::Context *context = nullptr;
    int ret = atb::CreateContext(&context);
    void *stream = nullptr;
    ret = aclrtCreateStream(&stream);
    context->SetExecuteStream(stream);

  4. 调用Operation对象的Setup函数,返回workspace大小。其中,VariantPack中传入的每个输入Tensor要求大于0且不超过256GB。

    atb::VariantPack variantPack = { ... };
    uint64_t workspaceSize = 0;
    operation->Setup(variantPack, workspaceSize, context);

  5. 根据workspace(workspace包含中间过程输出的Tensor)大小,申请NPU内存。

    void* workspace = nullptr;
    aclrtMalloc(&workspace, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);

  6. 调用Operation对象的Execute函数。

    operation->Execute(variantPack, workspace, workspaceSize, context);

  7. 销毁Context、Stream、workspace和Operation对象。

    int ret = DestroyContext(context);
    ret = aclrtDestroyStream(stream);
    ret = aclrtFree(workspace);
    st = DestroyOperation(operation);

典型样例说明

  1. 构造GraphParam对象。

    该图算子由operation1和operation2组成,其中0、1、2、3作为图输入Tensor,4、5、6作为图输出Tensor,7作为图中间Tensor。各Tensor的id取值应满足1中的说明。
    atb::GraphParam graphParam;
    graphParam.inTensorNum = 4;                  // 指定该图的输入Tensor数量
    graphParam.outTensorNum = 3;                 // 指定该图的输出Tensor数量
    graphParam.internalTensorNum = 1;            // 指定该图的中间Tensor数量
    graphParam.nodes.resize(2);                  // 指定该图中的节点数量,即包含的单算子数量
    graphParam.nodes[0].operation = operation1;  // 指定该图中的节点0的算子名称
    graphParam.nodes[0].inTensorIds = {0, 1, 2}; // 指定该图中的节点0需要的inTensor所对应的id
    graphParam.nodes[0].outTensorIds = {7, 4};   // 指定该图中的节点0输出的outTensor所对应的id
    graphParam.nodes[1].operation = operation2;  // 指定该图中的节点1的算子名称
    graphParam.nodes[1].inTensorIds = {3, 7}; // 指定该图中的节点1需要的inTensor所对应的id
    graphParam.nodes[1].outTensorIds = {5, 6};   // 指定该图中的节点1输出的outTensor所对应的id

  2. 调用CreateOperation函数返回Operation对象。

    atb::Operation *operation = nullptr;                    // 声明一个Operation类对象指针addOp
    atb::Status st = atb::CreateOperation(graphParam, &operation); // 传入步骤一中的参数和Operation类对象指针引用

  3. 创建Context并设置Stream。

    atb::Context *context = nullptr;         // Context主要负责对NPU中使用的Stream进行管理
    int ret = atb::CreateContext(&context);
    void *stream = nullptr;
    ret = aclrtCreateStream(&stream);
    context ->SetExecuteStream(stream);      // 设置指定Stream为Context中的executeStream

  4. 调用Operation对象的Setup函数,返回workspace大小。

    atb::VariantPack variantPack;               // 此处先声明VariantPack类对象,其中包含Tensor的信息,此处省略对其具体的构造过程
    uint64_t workspaceSize = 0;
    operation->Setup(variantPack, workspaceSize, context);// 传入variantPack和workspaceSize参数,setup函数中根据实际variantPack所需空间计算出workspaceSize大小并返回

  5. 根据workspace大小,申请NPU内存。

    void* workspace = nullptr;
    aclrtMalloc(&workspace, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); // AscendCL的NPU内存分配函数,根据步骤三中计算出来的workspaceSize以ACL_MEM_MALLOC_HUGE_FIRST方式对workspace分配NPU内存空间

  6. 调用Operation对象的Execute函数。

    operation ->Execute(variantPack, workspace, workspaceSize, context); // 进行具体的addOp的执行操作

  7. 销毁Context、Stream、workspace和Operation对象。

    int ret = DestroyContext(context); // 销毁context
    ret = aclrtDestroyStream(stream);  // 销毁stream
    ret = aclrtFree(workspace); // 销毁workspace
    st = DestroyOperation(operation); // 销毁operation