C - 浮点矩阵和稀疏布尔值矩阵之间的可移植快速点积

C - portable fast dot product between a float matrix and a sparse boolean value matrix

我正在用 C 语言开发一个尖峰神经网络项目,其中尖峰是布尔值。现在我已经构建了一个自定义位矩阵类型来表示尖峰矩阵。

我经常需要位矩阵的点积和相同大小的单精度浮点数矩阵,所以我想知道我应该如何加快速度?

后面还需要做浮点矩阵和位矩阵的逐点乘法

我现在的计划只是循环遍历 with 和 if 语句以及 bitshift。我想加快速度。

float current = 0;
for (int i = 0; i < n_elem; i++, bit_vec >>= 1) {
    if (bit_vec & 1)
        current += weights[i];
}

我不一定需要使用位向量,它也可以用其他方式表示。我在这里看到了其他答案,但它们是特定于硬件的,我正在寻找可以移植的东西。

我也没有使用任何 BLAS 函数,主要是因为我从不对两个浮点数进行操作。我应该吗?

谢谢。

bit_vec >>= 1current += weights[i] 指令导致循环携带依赖性,这肯定会阻止编译器生成快速实现(并且也会阻止处理器有效地执行它)。 您可以通过展开循环 来解决这个问题。此外,大多数主流编译器不够智能,因此要优化条件 en 使用大多数体系结构上可用的 blend 指令条件分支很慢,尤其是当它们不容易预测时(这当然是你的情况)。您可以使用乘法 so 来帮助编译器生成更好的指令。这是结果:

    const unsigned int blockSize = 4;
    float current[blockSize] = {0.f};
    int i;

    for (i = 0; i < n_elem-blockSize+1; i+=blockSize, bit_vec >>= blockSize)
        for(int j = 0 ; j < blockSize ; ++j)
            current[j] += weights[i] * (bit_vec >> j);

    for (; i < n_elem; ++i, bit_vec >>= 1)
        if (bit_vec & 1)
            current[0] += weights[i];

    float sum = 0.f;
    for(int j = 0 ; j < blockSize ; ++j)
        sum += current[j];

假定 n_elem 相对较大,此代码应该更快。由于像 GCC 和 Clang 这样的编译器无法 auto-vectorize 它应该仍然远非高效。这很可悲,因为使用 SIMD 指令(如 SSE、AVX、Neon 等)会快好几倍。话虽这么说,这正是人们使用 non-portable 代码的原因:手动使用高效指令,因为编译器在 non-trivial 情况下通常无法做到这一点。