通用说明和约束
通用地址对齐约束
AI Core上的存储单元用于存储矢量计算、矩阵计算的源操作数和目的操作数,各类存储单元的对齐要求如所示,因此C API操作数的起始地址对齐要求应与这些存储单元的对齐要求保持一致。需要注意的是,如果接口中已明确说明操作数起始地址对齐要求,则以具体API中的说明为准。
表 1 不同存储单元的对齐要求
通用地址重叠约束
使用高维切分计算接口时,为了节省地址空间,开发者可以申请一块内存,供源操作数与目的操作数同时使用(即地址重叠)。使用时需要注意以下约束:
- 单次迭代内:源操作数与目的操作数必须100%完全重叠,不支持部分重叠。
- 多次迭代间:不支持前序迭代的目的操作数与后序迭代的源操作数重叠。例如,第N次迭代的目的操作数是第N+1次的源操作数(如下图所示)。在这种情况下,第N次迭代可能会改写覆盖源操作数的数值,导致无法得到预期结果。特别地,对于部分双目计算类的API(asc_add,asc_sub,asc_mul等),当数据类型为half、int32_t、float时,支持前序迭代的目的操作数与后序迭代的源操作数重叠:仅针对目的操作数和第二个源操作数重叠的情况,且src1RepStride或者dstRepStride必须为0。
图 1 地址重叠示例(不支持)
[object Object]
如何使用高维切分计算API
[object Object]
使用高维切分计算API可充分发挥硬件优势,支持开发者控制指令的迭代执行和操作数的地址间隔,功能更加灵活。
矢量计算通过Vector计算单元完成,矢量计算的源操作数和目的操作数均通过Unified Buffer(UB)来进行存储。Vector计算单元每个迭代会从UB中取出8个DataBlock(每个DataBlock数据块内部地址连续,长度32Byte),进行计算,并写入对应的8个DataBlock中。下图为单次迭代内的8个DataBlock进行Exp计算的示意图。
图1 单次迭代内的8个DataBlock进行Exp计算示意图
- 矢量计算API支持开发者通过repeatTime来配置迭代次数,从而控制指令的多次迭代执行。假设repeatTime设置为2,矢量计算单元会进行2个迭代的计算,可计算出2 * 8(每个迭代8个DataBlock) * 32Byte(每个DataBlock 32Byte) = 512Byte的结果。如果数据类型为half,则计算了256个元素。下图展示了2次迭代Exp计算的示意图。由于硬件限制,repeatTime不能超过255。[object Object]
- 针对同一个迭代中的数据,可以通过mask参数进行掩码操作来控制实际参与计算的个数。下图为进行Abs计算时通过mask逐比特模式按位控制哪些元素参与计算的示意图,1表示参与计算,0表示不参与计算。[object Object]
- 矢量计算单元还支持带间隔的向量计算,通过dataBlockStride(单次迭代内不同DataBlock间地址步长)和repeatStride(相邻迭代间相同DataBlock的地址步长)来进行配置。
dataBlockStride [object Object] 如果需要控制单次迭代内,数据处理的步长,可以通过设置同一迭代内不同DataBlock的地址步长dataBlockStride来实现。下图给出了单次迭代内非连续场景的示意图,示例中源操作数的dataBlockStride配置为2,表示单次迭代内不同DataBlock间地址步长(起始地址之间的间隔)为2个DataBlock。[object Object] 图4 单次迭代内非连续场景的示意图
repeatStride
当repeatTime大于1,需要多次迭代完成矢量计算时,您可以根据不同的使用场景合理设置相邻迭代间相同DataBlock的地址步长repeatStride的值。[object Object]
下图给出了多次迭代间非连续场景的示意图,示例中源操作数和目的操作数的repeatStride均配置为9,表示相邻迭代间相同DataBlock起始地址之间的间隔为9个DataBlock。相同DataBlock是指DataBlock在迭代内的位置相同,比如下图中的src1和src9处于相邻迭代,在迭代内都是第一个DataBlock的位置,其间隔即为repeatStride的数值。 [object Object]
图5 多次迭代间非连续场景的示意图
下文中给出了dataBlockStride、repeatStride、mask的详细配置说明和示例。
dataBlockStride
dataBlockStride是指同一迭代内不同DataBlock的地址步长。
- 连续计算,dataBlockStride设置为1,对同一迭代内的8个DataBlock数据连续进行处理。
- 非连续计算,dataBlockStride值大于1(如取2),同一迭代内不同DataBlock之间在读取数据时出现一个DataBlock的间隔,如下图所示。 [object Object]
图6 dataBlockStride不同取值举例
repeatStride
repeatStride是指相邻迭代间相同DataBlock的地址步长。
连续计算场景: 假设定义一个Tensor供目的操作数和源操作数同时使用(即地址重叠),repeatStride取值为8。此时,矢量计算单元第一次迭代读取连续8个DataBlock,第二轮迭代读取下一个连续的8个DataBlock,通过多次迭代即可完成所有输入数据的计算。
非连续计算场景: repeatStride取值大于8(如取10)时,则相邻迭代间矢量计算单元读取的数据在地址上不连续,出现2个DataBlock的间隔。
反复计算场景: repeatStride取值为0时,矢量计算单元会对首个连续的8个DataBlock进行反复读取和计算。
部分重复计算: repeatStride取值大于0且小于8时,相邻迭代间部分数据会被矢量计算单元重复读取和计算,此种情形一般场景不涉及。
掩码操作
mask用于控制每次迭代内参与计算的元素。可以按位控制哪些元素参与计算,bit位的值为1表示参与计算,0表示不参与。 mask实际取值范围和操作数的数据类型有关。当操作数为16位时,mask包含2个uint64_t数据,mask0、mask1∈[0, 2^64-1]并且不同时为0;当操作数为32位时,mask包含1个uint64_t数据,mask0∈(0, 2^64-1];当操作数为64位时,mask包含1个uint64_t数据,mask0∈(0, 2^32-1]。 [object Object]
具体样例如下:
结果示例如下:
mask过程如下:[object Object]
mask={6148914691236517205, 6148914691236517205}(注:6148914691236517205表示64位二进制数0b010101....01,mask按照低位到高位的顺序排布)
结果示例如下:
mask过程如下:[object Object]
mask={6148914691236517205, 0}(注:6148914691236517205表示64位二进制数0b010101....01)
以数组方式申请内存
编译器支持以数组方式申请内存。但需注意以下约束:
- 当前仅支持[object Object]Atlas A3 训练系列产品/Atlas A3 推理系列产品[object Object]和[object Object]Atlas A2 训练系列产品/Atlas A2 推理系列产品[object Object]产品。
- 数组方式的申请方式,和asc_get_phy_buf_addr API接口不能混用。否则可能导致地址重叠。
- 不支持多维数组和嵌套的数组。
- 封装到数据结构中时,不支持隐式构造。
- 不支持动态数组。
基本使用方式如下: