Swift中使用Accelerate框架进行矩阵乘法的32位与64位的区别

3
我正在使用Accelerate框架在Swift中进行矩阵乘法。我使用了vDSP_mmulD,在iPhone6,6 plus和iPad Air模拟器(所有64位架构设备)上运行良好,但在任何32位架构设备上都无法工作。 似乎32位架构不识别vDSP_mmulD,程序无法构建。错误消息显示为“未解析的标识符‘vDSP_mmulD’”。有其他人看到过这个错误吗?请告诉我您的想法。我正在使用Xcode 6.1。 谢谢。

我没有使用过Accelerate框架,但是在我的看法中,在花费太多精力在32位上之前,你应该重新考虑一下。苹果正在要求开发者专注于64位。https://developer.apple.com/news/?id=10202014a - chunkyguy
@chunkyguy,他们鼓励使用64位构建来避免在64位设备上加载32位库。然而,32位设备仍然存在,编写与各种架构兼容的代码是推荐的。 - Bartek Chlebek
如果你复制/粘贴了那个错误信息,你的问题是在vSDP_mmulD的开头交换了几个字母。 - Nate Cook
@NateCook。那是我的笔误。在64位上运行良好,但在32位设备上程序无法构建。 - Dman
3个回答

4
简单的解决方案:使用 cblas_dgemm 代替(也是Accelerate的一部分)。 在所有系统上,它至少与vDSP_mmulD一样快,并且在某些系统上要快得多(在iOS 8和Yosemite中,vDSP_mmulD 实际上只是 cblas_dgemm 的包装器),并且它应该可以在这里正常工作。
我怀疑您的构建在32位模拟器上失败了。在i386上,vDSP_mmulD实际上是围绕mmulD的宏,而Swift不完全支持C语言宏。
注意:我怀疑您可能正在使用3x3或4x4矩阵,在这种情况下,没有一个Accelerate例程真正符合您的要求(它们针对更大的矩阵);您需要内联向量序列,如<simd / matrix.h>中定义的序列。不幸的是,Swift不支持SIMD向量,因此这不是一个选项。此时,您最好的选择可能是简单地编写逐元素计算,并报告错误以请求Swift支持<simd / simd.h>接口。

你听起来更像是知道你在说什么的人 :) - Nate Cook
我正在计算1x9和9x1矩阵的乘积。感谢您的提示,我将尝试使用cblas_dgemm函数。 - Dman
尝试了简单的方法(逐元素计算)。程序严重减速。我需要执行1620 [1x9]x[9x1]矩阵乘法才能得到结果。我想现在只有使用cblas_dgemm才有可能实现。我正在网上寻找,但并没有找到太多帮助。我将继续努力使其正常工作。目前当我使用cblas_gemm时出现的错误是“无法使用增量列表调用'subscript'...”请让我知道您对此的想法。谢谢。 - Dman
1x9x9x1 实际上是一个点积。你可能会发现使用 cblas_ddot 更容易。 - Stephen Canon
我有一个大小为[18x18]的矩阵A。我需要对这个矩阵进行平方运算,然后再次平方。这个过程需要重复5次,因此我需要A的32次方。我找不到可以完成这个操作的命令,所以我正在计算每行和每列的点积1680(18x18x5)次,以获得我需要的结果。如果存在一个A的n次方命令,计算速度可以进一步提高。 - Dman
显示剩余2条评论

1
这些都是推测,因为我现在没有32位设备进行测试,并且找不到任何支持此说法的文档,但也许加速器在两种不同的架构上可以使用不同的浮点类型 - 在32位架构上使用Float,在64位架构上使用DoublevDSP_mmulD末尾的D代表Double,因此您需要能够在代码中使用32位架构上的Float版本:vDSP_mmul
您可以使用#if...#else...#endif预处理块来切换使用哪些方法(有关信息请参见本页面底部)。绕过Swift的严格静态类型的一个技巧是在文件顶部放置类似于这样的预处理块:
#if arch(x86_64) || arch(arm64)
    typealias M_Float = Double
    let M_vDSP_mmul = vDSP_mmulD
    // add Double versions of other Accelerate functions you need
#else
    typealias M_Float = Float
    let M_vDSP_mmul = vDSP_mmul
    // add Float versions of other Accelerate functions you need
#endif

而不是必须选择是否使用FloatDouble,或在您的代码中始终使用哪种方法,您可以只使用M_Float和您的M_...版本的Accelerate函数:
var number: M_Float = 0    // Double on 64-bit, Float on 32-bit
M_vDSP_mmul(...)           // correct version either way

希望这有所帮助!

0
我发现了这个 Swift集合库。它提供了一个使用Accelerate的矩阵结构和乘法运算符。对我很有用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接