1

我正在为 iPhone 实现基于切线距离的 OCR 解决方案,它严重依赖于大小为 253x7 的浮点矩阵的快速乘法。为了概念验证,我实现了自己的简单矩阵例程,如下所示:

Matrix operator*(const Matrix& matrix) const {
    if(cols != matrix.rows) throw "cant multiply!";

    Matrix result(rows, matrix.cols);
    for(int i = 0; i < result.rows; i++){
        for(int j = 0; j < result.cols; j++){
            T tmp = 0;
            for(int k = 0; k < cols; k++){
                tmp += at(i,k) * matrix.at(k,j);
            }
            result.at(i,j) = tmp;
        }
    }

    return result;
}

如您所见,它非常基本。在 PoC 表现良好之后,我决定通过合并Accelerate Framework的矩阵乘法(大概使用 SIMD 和其他花哨的东西来完成繁重的工作......)进一步推动性能限制:

Matrix operator*(const Matrix& m) const {
    if(cols != m.rows) throw "cant multiply!";

    Matrix result(rows,m.cols);

    cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, rows, m.cols, cols, 1, matrix, cols, m.matrix, m.cols, 1, result.matrix, result.cols);

    return result;
}

令人震惊(至少对我而言),上面的代码将矩阵相乘花费了两倍的时间!我尝试使用单精度而不是双精度,因为我怀疑它与 CPU 的字长有关(32 位浮点数与 32 位 ARM 上的 64 位双精度),但没有性能提升......

我究竟做错了什么?我的 253x7 矩阵是否太小而无法在幼稚的实现中显着提升性能?

4

2 回答 2

1

几个问题:

  1. 253 x 7 乘以多大的矩阵?如果你正在做,比如说,253x7 * 7x1,那么一个通用的乘法例程将把大部分时间花在修边代码上,而经过调整的库几乎没有什么能比一个简单的实现更快地做到这一点.

  2. 你在什么硬件上计时,什么 iOS 版本?特别是对于双精度,较旧的硬件和较旧的 iOS 版本在性能方面更受限制。例如,在 Cortex-A8 上,双精度算术是完全非流水线的,因此库几乎无法击败幼稚的实现。

如果另一个矩阵不是小得离谱,并且硬件是最新的,请提交一个错误(意外的低性能绝对是一个错误)。具有高纵横比的小矩阵很难在通用矩阵乘法中快速制作,但它仍然是一个很好的 bug。

如果硬件/iOS 版本较旧,您可能仍想使用 Accelerate,因为它应该在较新的硬件/软件上表现得更好。

如果另一个矩阵很小,那么可能没什么可做的。ARM 上没有双精度 SIMD,矩阵太小而无法从缓存阻塞中受益,矩阵的维度也太小而无法从循环展开中受益。


如果您先验地知道您的矩阵将恰好是 253x7 * 7x???,那么通过完全展开矩阵乘法的内部维度,您应该能够比简单的实现和任何通用库做得更好。

于 2013-04-02T22:02:48.710 回答
0

基本上,是的。“x7”部分可能太小而无法使 CBLAS 的开销值得。进行函数调用的成本,加上 CBLAS 函数为您提供的所有灵活性,需要一段时间才能弥补。每次您传递一个选项时,CblasNoTrans请记住其中有一个if()管理该选项的选项。cblas_dgemm特别是累加到 C 中,因此它必须读取前一个结果元素,应用乘法,然后在存储之前加法。这是很多额外的工作。

您可能想尝试 vDSP 功能而不是 CBLAS。vDSP_mmul有点简单,不会累积到结果中。我vDSP_*在小型数据集(几千个元素)上运气不错。

也就是说,我的经验是,幼稚的 C 实现通常可以在小型数据集上相当快。避免函数调用是一个巨大的好处。说到这一点,请确保您的at()呼叫是内联的。否则,您将在循环中浪费大量时间。您可以通过使用指针加法在矩阵中连续移动而不是乘法(通过 随机访问需要[])来加速 C 实现。在这么小的矩阵上,它可能值得,也可能不值得;您必须进行一些分析。查看汇编程序的输出很有启发性。

请记住,您绝对必须在设备上分析这些内容。模拟器中的性能无关紧要。不仅仅是模拟器更快;这是完全不同的。在模拟器上快得多的东西在设备上可能要慢得多。

于 2013-04-02T21:44:20.363 回答