多通道乘法 - sliding_mul - 2023.2 简体中文

AI 引擎内核与计算图编程指南 (UG1079)

Document ID
UG1079
Release Date
2023-12-04
Version
2023.2 简体中文

AI 引擎可提供硬件支持以加速某种类型的多通道乘法,这称为滑动乘法。它允许多个通道同时执行 MAC 运算,并将结果添加至累加器。它对于有限脉冲响应 (FIR) 滤波器实现尤为有效,但作用也不限于此。

这些特殊乘法结构或 API 被称为 aie::sliding_mul*。可接受系数和数据输入。aie::sliding_mul_sym* 的部分变体允许在执行乘法前以对称方式进行数据输入前加运算。这些类包括:

  • aie::sliding_mul_ops
  • aie::sliding_mul_x_ops
  • aie::sliding_mul_y_ops
  • aie::sliding_mul_xy_ops
  • aie::sliding_mul_sym_ops
  • aie::sliding_mul_sym_x_ops
  • aie::sliding_mul_sym_y_ops
  • aie::sliding_mul_sym_xy_ops
  • aie::sliding_mul_sym_uct_ops

如需了解有关这些 API 的更多信息,请参阅 AI 引擎 API 用户指南(UG1529)

例如,aie::sliding_mul_ops 类可提供参数化乘法,用于实现以下计算模式。

DSX = DataStepX
DSY = DataStepY
CS = CoeffStep
P = Points
L = Lanes
c_s = coeff_start
d_s = data_start 
out[0] = coeff[c_s] * data[d_s + 0] + coeff[c_s + CS] * data[d_s + DSX] + ... + coeff[c_s + (P-1) * CS] * data[d_s + (P-1) * DSX]
out[1] = coeff[c_s] * data[d_s + DSY] + coeff[c_s + CS] * data[d_s + DSY + DSX] + ... + coeff[c_s + (P-1) * CS] * data[d_s + DSY + (P-1) * DSX]
...
out[L-1] = coeff[c_s] * data[d_s + (L-1) * DSY] + coeff[c_s + CS] * data[d_s + (L-1) * DSY + DSX] + ... + coeff[c_s + (P-1) * CS] * data[d_s + (L-1) * DSY + (P-1) * DSX]
表 1. 模板参数
参数 描述
Lanes 输出元素数量。
Points 用于计算每个通道的数据元素数量。
CoeffStep 用于从 coeff 寄存器中选择元素的步骤。此步骤适用于某一通道内的元素选择。
DataStepX 用于从数据寄存器中选择元素的步骤。此步骤适用于某一通道内的元素选择。
DataStepY 用于从数据寄存器中选择元素的步骤。此步骤适用于跨通道进行的元素选择。
CoeffType 系数元素类型。
DataType 数据元素类型。
AccumTag 累加器标签,此标签指定所需的累加位。该类必须与系数和数据类型(实数/复数)的乘法结果兼容。

下图显示了如何使用 aie::sliding_mul_ops 类及其成员函数 mul 来执行滑动乘法。它还显示了每个参数与乘法的对应方式。

图 1. sliding_mul_ops 使用示例

除了 aie::sliding_mul* 类之外,AI 引擎 API 还提供了 aie::sliding_mul* 函数,用于执行滑动乘法,并提供了 aie::sliding_mac* 函数,用于执行滑动乘法和累加。这些函数只是出于方便而提供的帮助程序,在内部使用 aie::sliding_mul*_ops 类。其中包括:

  • aie::sliding_mul
  • aie::sliding_mac
  • aie::sliding_mul_sym
  • aie::sliding_mac_sym
  • aie::sliding_mul_antisym
  • aie::sliding_mac_antisym
  • aie::sliding_mul_sym_uct
  • aie::sliding_mac_sym_uct
  • aie::sliding_mul_antisym_uct
  • aie::sliding_mac_antisym_uct

以下示例执行的是非对称滑动乘法(模板原型包含在注释中以便于快速参考)。

/*template<unsigned Lanes, unsigned Points, int CoeffStep, 
  int DataStepX, int DataStepY, ElemBaseType CoeffType, 
  ElemBaseType DataType, 
  AccumElemBaseType AccumTag = detail::default_accum_tag_t<CoeffType, DataType>>
 */

/*struct aie::sliding_mul_ops< Lanes, Points, 
  CoeffStep, DataStepX, DataStepY, 
  CoeffType, DataType, AccumTag >
 */

// template<VectorOrOp VecCoeff, VectorOrOp VecData>

/*static constexpr accum_type mul (const VecCoeff &coeff, unsigned coeff_start, 
  const VecData &data, unsigned data_start)
*/

aie::vector<int16,16> va;
aie::vector<int16,64> vb0,vb1;
aie::accum<acc48,8>  acc = aie::sliding_mul_ops<8, 8, 1, 1, 1, int16, int16, acc48>::mul(va, 0, vb0, 0);
acc = aie::sliding_mul_ops<8, 8, 1, 1, 1, int16, int16, acc48>::mac(acc, va, 8, vb1, 0);
*outIter++=acc.to_vector<int32>(15);

/*template<unsigned Lanes, unsigned Points, int CoeffStep = 1, 
  int DataStepX = 1, int DataStepY = DataStepX, 
  AccumElemBaseType AccumTag = accauto, 
  VectorOrOp VecCoeff = void, VectorOrOp VecData = void>
 */

/*auto sliding_mul (const VecCoeff &coeff, unsigned coeff_start, 
  const VecData &data, unsigned data_start)
 */

aie::vector<int32,32> data_buff;
aie::vector<int32,8> coeff_buff;
aie::accum<acc80,8> acc_buff = aie::sliding_mul<8, 8>(coeff_buff, 0, data_buff, 0);

以下提供的是对称滑动乘法示例。

/*template<unsigned Lanes, unsigned Points, 
  int CoeffStep, int DataStepX, int DataStepY, 
  ElemBaseType CoeffType, ElemBaseType DataType, 
  AccumElemBaseType AccumTag = detail::default_accum_tag_t<CoeffType, DataType>>
 */

/*struct aie::sliding_mul_sym_ops<Lanes, Points, CoeffStep, 
  DataStepX, DataStepY, CoeffType, DataType, AccumTag > 
 */

// template<VectorOrOp VecCoeff, VectorOrOp VecData>

/*static constexpr accum_type mul_sym (const VecCoeff &coeff, 
  unsigned coeff_start, const VecData &data, unsigned data_start)
 */

aie::vector<cint16,16> data_buff;
aie::vector<int16,8> coeff_buff;
auto acc_buff = aie::sliding_mul_sym_ops<4, 16, 1, 1, 1, int16, cint16, cacc48>::mul_sym(coeff_buff, 0, data_buff, 0);

/*template<unsigned Lanes, unsigned Points, int CoeffStep = 1, 
  int DataStepX = 1, int DataStepY = DataStepX,
  AccumElemBaseType AccumTag = accauto, VectorOrOp VecCoeff = void, 
  VectorOrOp VecData = void>
 */

/*auto sliding_mul_sym (const VecCoeff &coeff, unsigned coeff_start, 
  const VecData &data, unsigned data_start)
 */

auto acc_buff2 = aie::sliding_mul_sym<4, 16, 1, 1, 1>(coeff_buff, 0, data_buff, 0);

/*template<unsigned Lanes, unsigned Points, int CoeffStep = 1, 
  int DataStepX = 1, int DataStepY = DataStepX, 
  AccumElemBaseType AccumTag = accauto, 
  VectorOrOp VecCoeff = void, VectorOrOp VecData = void>
 */

/*auto sliding_mul_sym (const VecCoeff &coeff, unsigned coeff_start, 
  const VecData &ldata, unsigned ldata_start, const VecData &rdata, unsigned rdata_start)
 */

aie::vector<cint16,16> ldata,rdata;
aie::vector<int16,8> coeff;

// symmetric sliding_mul using two data registers
auto acc = aie::sliding_mul_sym<4, 8, 1, 1, 1>(coeff, 0, ldata, 0, rdata, 8);
注释: 滑动乘法中的所有寄存器都必须被视作为循环寄存器。达到末尾后必须返回开始位置。

下图显示了先前对称示例的计算方式。

图 2. sliding_mul_sym_ops 使用示例
图 3. 含两个数据寄存器的 sliding_mul_sym 函数

使用 sliding_mul 时的注意事项

限制包括但不限于:

  • 数据宽度 <=1024 位,系数宽度 <=256 位
  • Lanes * Points >= 每个周期内该类型的 MAC 数
  • int8 在 sliding_mul_sym_opssliding_mul_sym_uct_ops 中不予支持。