Cascade Lake Intel处理器中有新的AVX-512 VNNI指令,可以在处理器上加速神经网络的推理。我将它们集成到Simd Library中以加速Synet (我的神经网络推理小框架),并获得了显着的性能提升。
实际上,我只使用了一个指令_mm512_dpbusd_epi32 (vpdpbusd),它允许执行8位带符号和无符号整数的乘法,然后将它们累加到32位整数累加器中。
这将是伟大的执行模拟优化霓虹灯(ARM平台)。
所以有一个问题:
有没有类似霓虹灯指令来模拟vpdpbusd?如果没有模拟,那么模拟指令的最佳方式是什么?
下面有一个标量实现(为了更好地理解函数必须做什么):
inline void pdpbusd(int32x4_t& sum, uint8x16_t input, int8x16_t weight)
{
for (size_t i = 0; i < 4; ++i)
for (size_t j = 0; j < 4; ++j)
sum[i] += int32_t(input[i * 4 + j]) * int32_t(weight[i * 4 + j]);
}发布于 2020-03-10 20:38:28
最直接的实现需要3条指令:vmovl.s8、vmovl.u8将带符号和无符号的8位值扩展到16位,然后是vmlal.s16,进行带符号加长的16位乘法,累加到32位寄存器中。由于vmlal.s16仅处理4个元素,因此您需要第二个vmlal.s16来乘以和累加以下4个元素-因此4个元素对应4条指令。
对于aarch64语法,对应的指令为sxtl、uxtl和smlal。
编辑:如果输出元素应该水平聚合,则不能使用融合的乘法-累加指令vmlal。然后,解决方案是vmovl.s8和vmovl.u8,然后是vmul.i16 (用于8个输入元素)、vpaddl.s16 (用于水平聚合两个元素),然后是另一个vpadd.i32以水平地获得4个元素的总和。因此,对于8个输入元素有5条指令,或者对于完整的128位向量有10条指令,然后是最后一条vadd.s32,将最终结果累加到累加器。在AArch64上,相当于vpadd.i32的addp可以处理128位向量,所以它少了一条指令。
如果你使用的是instrinsics,它的实现可能是这样的:
int32x4_t vpdpbusd(int32x4_t sum, uint8x16_t input, int8x16_t weight) {
int16x8_t i1 = vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(input)));
int16x8_t i2 = vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(input)));
int16x8_t w1 = vmovl_s8(vget_low_s8(weight));
int16x8_t w2 = vmovl_s8(vget_high_s8(weight));
int16x8_t p1 = vmulq_s16(i1, w1);
int16x8_t p2 = vmulq_s16(i2, w2);
int32x4_t s1 = vpaddlq_s16(p1);
int32x4_t s2 = vpaddlq_s16(p2);
#if defined(__aarch64__)
int32x4_t s3 = vpaddq_s32(s1, s2);
#else
int32x4_t s3 = vcombine_s32(
vpadd_s32(vget_low_s32(s1), vget_high_s32(s1)),
vpadd_s32(vget_low_s32(s2), vget_high_s32(s2))
);
#endif
sum = vaddq_s32(sum, s3);
return sum;
}https://stackoverflow.com/questions/60617674
复制相似问题