Skip to content

BilinearInterpolation(ISASI)

产品支持情况

  • Ascend 950PR/Ascend 950DT:支持
  • Atlas A3 训练系列产品/Atlas A3 推理系列产品:支持
  • Atlas A2 训练系列产品/Atlas A2 推理系列产品:支持
  • Atlas 200I/500 A2 推理产品:不支持
  • Atlas 推理系列产品AI Core:支持
  • Atlas 推理系列产品Vector Core:不支持
  • Atlas 训练系列产品:不支持

功能说明

头文件路径为:"basic_api/kernel_operator_vec_bilinearinterpolation_intf.h"

BilinearInterpolation属于双目矢量类计算接口,核心通过水平迭代+垂直迭代的双层循环完成乘累加运算,适用于非规则数据访问+权重乘加的向量运算场景(数据Gather+Multiply+Reduce)。

注:该接口是为了兼容旧款产品接口而添加的软仿接口。

具体计算流程参考下图:

图1 BilinearInterpolation计算流程示意图

结合上面的计算流程示意图,下面以一个具体示例,来介绍BilinearInterpolation整个计算过程。

假设计算场景的输入如下:

Text
src0 = [1, 2, 3, ..., 512],共计512个half数据;
src0Offset = [0, 32, 64, ..., 992],共计32个uint32数据;
src1 = [2, 3, 4, ..., 33],共计32个half数据;
hRepeat = 2;vRepeat = 2;mask = 128;vROffset = 128。

具体计算流程拆解分析如下:

  • 步骤1. 按DataBlock粒度,收集输入src0张量到临时Buffer。

    总共hRepeat * vRepeat次迭代,每个迭代从输入的src0Offset读取8个偏移值,每个偏移值指向src0的一个DataBlock起始地址。

    调用Gatherb接口,Gatherb接口接受输入张量(src0)、DataBlock偏移张量(src0Offset),根据src0Offset将输入张量src0按DataBlock(32Bytes)收集到临时张量(sharedTmpBuffer)中。

    该步骤处理过程如下:

    • 总迭代次数:hRepeat * vRepeat = 2 * 2 = 4;
    • 每次迭代处理的src0元素个数:8 * 32 / sizeof(half) = 128(8:DataBlock的数量;32:每个DataBlock的大小为32B);
    • 每次迭代收集结果
      • 迭代0:sharedTmpBuffer[0:127] = [1, 2, ..., 128];
      • 迭代1:sharedTmpBuffer[128:255] = [129, 130, ..., 256];
      • 迭代2:sharedTmpBuffer[256:383] = [257, 258, ..., 384];
      • 迭代3:sharedTmpBuffer[384:511] = [385, 386, ..., 512]。
  • 步骤2. 将输入的张量src1进行广播填充。

    调用Brcb接口,每次迭代从输入张量src1中取8个数,填充到结果张量sharedTmpBuffer的8个DataBlock中(每个DataBlock的大小为32B)。

    该步骤处理过程如下:

    • 步骤1收集的src0张量占用的空间大小 = 总迭代次数 * 每次迭代处理的元素个数 = 4 * 128 = 512。所以广播src1的元素从sharedTmpBuffer[512]开始存放;

    • Brcb指令迭代次数repeatTime = src1的数据长度 / 8 = 16 / 8 = 2次(Brcb指令每次迭代取8个数);

    • 将输入src1张量中的8个数据,填充到sharedTmpBuffer[512]位置起的8个DataBlock中去。输入是half数据类型,故每个元素复制32 / sizeof(half) = 16次。

      结果:sharedTmpBuffer[512:1024] = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, ..., 33, 33]。

  • 步骤3. 收集的src0张量与广播后的src1张量,调用Mul执行逐元素乘法,结果覆盖sharedTmpBuffer。

    迭代计算次数:hRepeat * vRepeat = 2 * 2 = 4。

    支持两种计算方式,由接口输入参数repeatMode控制(配置true或false)。

    • repeatMode=false 每次迭代,src0(数据存放位置为sharedTmpBuffer[0:511])读取8个DataBlock,每个DataBlock的每个值均与src1(数据存放位置为sharedTmpBuffer[512:1024])的单个数值相乘。

      • 整个处理过程如下:
        • 迭代0计算过程:第1个DataBlock(sharedTmpBuffer[0:15])到第8个DataBlock(sharedTmpBuffer[112:127]),均与src1的2相乘。

          即sharedTmpBuffer[0:127] = [1 * 2, ..., 128 * 2];

        • 迭代1计算过程:第1个DataBlock(sharedTmpBuffer[128:143])到第8个DataBlock(sharedTmpBuffer[240:255]),均与src1的3相乘。

          即sharedTmpBuffer[128:255] = [129 * 3, ..., 256 * 3];

        • 迭代2计算过程:第1个DataBlock(sharedTmpBuffer[256:271])到第8个DataBlock(sharedTmpBuffer[368:383]),均与src1的4相乘。

          即sharedTmpBuffer[256:383] = [257 * 4, ..., 384 * 4];

        • 迭代3计算过程:第1个DataBlock(sharedTmpBuffer[384:399])到第8个DataBlock(sharedTmpBuffer[496:511]),均与src1的5相乘。

          即sharedTmpBuffer[384:511] = [385 * 5, ..., 512 * 5]。

    • repeatMode=true 每次迭代,src0(数据存放位置为sharedTmpBuffer[0:511])读取8个DataBlock,每个DataBlock分别与src1(存放位置为sharedTmpBuffer[512:1024])的1个数值相乘,即src0的8个DataBlock分别对应src1的8个数值。

      • 整个处理过程如下:
        • 迭代0计算过程:第1个DataBlock(sharedTmpBuffer[0:15])与src1的2相乘,第2个DataBlock(sharedTmpBuffer[16:31])与src1的3相乘;...依次类推,第8个DataBlock(sharedTmpBuffer[112:127])与src1的9相乘。

          即sharedTmpBuffer[0:127] = [1 * 2, ..., 16 * 2, 17 * 3, ..., 128 * 9];

        • 迭代1计算过程:第1个DataBlock(sharedTmpBuffer[128:143])与src1的10相乘,第2个DataBlock(sharedTmpBuffer[144:159])与src1的11相乘;...依次类推,第8个DataBlock(sharedTmpBuffer[240:255])与src1的17相乘。

          即sharedTmpBuffer[128:255] = [129 * 10, ..., 144 * 10, 145 * 11, ..., 256 * 17];

        • 迭代2计算过程:第1个DataBlock(sharedTmpBuffer[256:271])与src1的18相乘,第2个DataBlock(sharedTmpBuffer[272:287])与src1的19相乘;...依次类推,第8个DataBlock(sharedTmpBuffer[368:383])与src1的25相乘。

          即sharedTmpBuffer[256:383] = [257 * 18, ..., 272 * 18, 273 * 19, ..., 384 * 25];

        • 迭代3计算过程:第1个DataBlock(sharedTmpBuffer[384:399])与src1的26相乘,第2个DataBlock(sharedTmpBuffer[400:415])与src1的27相乘;...依次类推,第8个DataBlock(sharedTmpBuffer[496:511])与src1的33相乘。

          即sharedTmpBuffer[384:511] = [385 * 26, ..., 390 * 26, 391 * 27, ..., 512 * 33]。

  • 步骤4. 水平迭代累加,输出到dst。

    调用Add接口完成以下处理:

    • dst[0:127] = sharedTmpBuffer[0:127] + sharedTmpBuffer[128:255];
    • dst[128:255] = sharedTmpBuffer[256:383] + sharedTmpBuffer[384:511]。

函数原型

  • mask逐bit模式:

    C++
    template <typename T>
    __aicore__ inline void BilinearInterpolation(const LocalTensor<T> &dst, const LocalTensor<T> &src0,
        const LocalTensor<uint32_t> &src0Offset, const LocalTensor<T> &src1, uint64_t mask[], uint8_t hRepeat,
        bool repeatMode, uint16_t dstBlkStride, uint16_t vROffset, uint8_t vRepeat,
        const LocalTensor<uint8_t> &sharedTmpBuffer);
    
  • mask连续模式:

    C++
    template <typename T>
    __aicore__ inline void BilinearInterpolation(const LocalTensor<T> &dst, const LocalTensor<T> &src0,
        const LocalTensor<uint32_t> &src0Offset, const LocalTensor<T> &src1, uint64_t mask, uint8_t hRepeat,
        bool repeatMode, uint16_t dstBlkStride, uint16_t vROffset, uint8_t vRepeat,
        const LocalTensor<uint8_t> &sharedTmpBuffer);
    

参数说明

模板参数及接口参数说明

表1 模板参数说明

参数名描述
T操作数数据类型。

表2 参数说明

参数名输入/输出描述
dst输出目的操作数。
类型为LocalTensor,支持的TPosition为VECIN/VECCALC/VECOUT。
LocalTensor的起始地址需要32字节对齐。
src0、src1输入源操作数。
类型为LocalTensor,支持的TPosition为VECIN/VECCALC/VECOUT。
LocalTensor的起始地址需要32字节对齐。
两个源操作数的数据类型需要与目的操作数保持一致。
src0Offset输入源操作数。
类型为LocalTensor,支持的TPosition为VECIN/VECCALC/VECOUT。
LocalTensor的起始地址需要32字节对齐。
mask[]/mask输入mask用于控制每次迭代内参与计算的元素。详细设置参考掩码
hRepeat输入水平方向迭代次数,取值范围为[1, 255]。
repeatMode输入迭代模式:
• false:每次迭代src0读取的8个DataBlock中每个值均与src1的单个数值相乘。
• true:每次迭代src0的每个DataBlock分别与src1的1个数值相乘,即1次迭代共消耗src0的8个DataBlock和src1的8个element。
dstBlkStride输入单次迭代内,目的操作数不同DataBlock间地址步长,以32B为单位。
vROffset输入垂直迭代间,目的操作数地址偏移量,以元素为单位,取值范围为[128, 65535),vROffset * sizeof(T)需要保证32字节对齐。
vRepeat输入垂直方向迭代次数,取值范围为[1, 255]。
sharedTmpBuffer输入临时空间。具体空间说明请参考下面的sharedTmpBuffer空间说明

sharedTmpBuffer空间说明

  • 针对Ascend 950PR/Ascend 950DT,不需要分配临时空间。
  • 针对Atlas A3 训练系列产品/Atlas A3 推理系列产品,需要保证至少分配了src0.GetSize() * 32 + src1.GetSize() * 32字节的空间。
  • 针对Atlas A2 训练系列产品/Atlas A2 推理系列产品,需要保证至少分配了src0.GetSize() * 32 + src1.GetSize() * 32字节的空间。
  • 针对Atlas 推理系列产品AI Core,需要保证至少分配了src0OffsetLocal.GetSize() * sizeof(uint32_t)字节的空间。

数据类型

支持的数据类型为:half。

返回值说明

约束说明

  • 操作数地址对齐要求请参见通用地址对齐约束
  • src0、src1、src0Offset之间不允许地址重叠,且两个垂直repeat的目的地址之间不允许地址重叠。
  • 参数vROffset的取值范围为[128, 65535)。
  • 水平方向迭代次数,取值范围为[1, 255]。
  • 垂直方向迭代次数,取值范围为[1, 255]。
  • 输入的临时空间sharedTmpBuffer,空间大小要求请参考sharedTmpBuffer空间说明
  • 参数src0Offset的取值要求如下:
    • 取值应保证src0元素类型位宽对齐。
    • 偏移地址后需要32字节对齐。
    • 偏移地址后不能超出UB大小数据的范围。
    • 地址偏移的取值范围:不能超出uint32_t的范围。
  • 当参数repeatMode配置为true时,需确保src1的有效数据长度*16 ≥ src0的数据长度。

调用示例

  • 接口样例-mask连续模式

    C++
    AscendC::LocalTensor<half> dstLocal, src0Local, src1Local; // repeatMode = false,src1Local的数据长度为16即可
    AscendC::LocalTensor<uint32_t> src0OffsetLocal;
    AscendC::LocalTensor<uint8_t> tmpLocal;
    uint64_t mask = 128;        // mask连续模式
    uint8_t hRepeat = 2;        // 水平迭代2次
    bool repeatMode = false;    // 迭代模式
    uint16_t dstBlkStride = 1;  // 单次迭代内数据连续写入
    uint16_t vROffset = 128;    // 相邻迭代间数据连续写入
    uint8_t vRepeat = 2;        // 垂直迭代2次
    AscendC::BilinearInterpolation(dstLocal, src0Local, src0OffsetLocal, src1Local, mask, hRepeat, repeatMode,
                dstBlkStride, vROffset, vRepeat, tmpLocal);
    
  • 接口样例-mask逐bit模式

    C++
    AscendC::LocalTensor<half> dstLocal, src0Local, src1Local;
    AscendC::LocalTensor<uint32_t> src0OffsetLocal;
    AscendC::LocalTensor<uint8_t> tmpLocal;
    uint64_t mask[2] = { UINT64_MAX, UINT64_MAX }; // mask逐bit模式
    uint8_t hRepeat = 2;        // 水平迭代2次
    bool repeatMode = false;    // 迭代模式
    uint16_t dstBlkStride = 1;  // 单次迭代内数据连续写入
    uint16_t vROffset = 128;    // 相邻迭代间数据连续写入
    uint8_t vRepeat = 2;        // 垂直迭代2次
    AscendC::BilinearInterpolation(dstLocal, src0Local, src0OffsetLocal, src1Local, mask, hRepeat, repeatMode,
                dstBlkStride, vROffset, vRepeat, tmpLocal);
    

结果示例如下:

Text
输入数据(src0Local,half): [1,2,3,...,512]
输入数据(src1Local,half): [2,3,4,...,17]
输入数据(src0OffsetLocal,uint32_t): [0,32,64,...,992]
输出数据(dstLocal,half): [389, 394, 399, 404, ...,4096]

免责声明:本站内容由 asc-devkit 仓 master 分支自动编译生成,属于持续开发版本,可能存在缺陷,仅供预览与参考。如需稳定及商用资料,请查阅官方 昇腾社区