具有临时消除功能的 C++ OpenCL 矩阵库

Posted

技术标签:

【中文标题】具有临时消除功能的 C++ OpenCL 矩阵库【英文标题】:C++ OpenCL matrix library with temporary elimination 【发布时间】:2015-03-07 04:48:07 【问题描述】:

犰狳矩阵库写

犰狳采用延迟评估方法将多个操作合并为一个,并减少(或消除)对临时人员的需求。在适用的情况下,优化操作顺序。通过递归模板和模板元编程实现延迟评估和优化。

这意味着你可以编写类似的操作

arma::mat A, B;
arma::vec c, d;
...
d=(A % B)*c;

并且没有创建临时变量。 (注意 % 是犰狳中的元素乘积运算)

我希望能够以类似的风格为 OpenCL 应用程序编写代码。

我查看过的库是 VexCL、ViennaCL、Boost.Compute 和 clBLAS。 VexCL 和 Boost.Compute 甚至不提供基本的矩阵功能,例如乘法。 clBLAS 不能用作模板库,因此您需要手动调用这些操作。 ViennaCL 提供了我需要的所有操作,但它似乎无法将它们链接在一起。

例如

    d= linalg::prod(linalg::element_prod(A,B), c);

编译失败。

我认为使用 VexCL 可能会根据 Armadillo 决定的操作自动生成内核,但我看不出有任何方法可以直接进行。

有什么建议吗?

【问题讨论】:

【参考方案1】:

您可能想查看ArrayFire。

ArrayFire 是一个基于矩阵的库,带有一个 JIT 编译引擎,它允许您将操作组合到一个内核中。这大大减少了您在上面发布的基本元素明智操作的内核调用次数。例如您发布的代码可以写成:

array A = randu(5, 5);       // 5x5 Matrix
array B = randu(5, 5);       // 5x5 Matrix
array c = constant(1, 1, 5); // 1x5 Matrix

array d = (A % B) + tile(c, 5);

在本例中,模数和加法将在一个 OpenCL 内核中执行。不创建临时对象。我们还有单线程 CPU、CUDA 和 OpenCL 的后端。

披露:我是 ArrayFire 库的开发人员之一。

【讨论】:

arrayfire 是把计算分给所有 gpus&cps 还是需要明确的设备管理? arrayfire 是否支持 JITing 矩阵乘法与其他操作的结合?我原来的问题有一个错字,应该是矩阵乘法。 ArrayFire 不会 JIT 矩阵乘法。像矩阵乘法这样的操作通常作为独立内核会更高效。 ArrayFire 不会执行负载平衡,但您可以使用 af::setDevice 函数轻松地在多个设备上执行操作。除了简单的元素操作之外,几乎不可能从自动负载平衡中获得好的结果。最好让用户决定如何管理数据。【参考方案2】:

您示例中的操作可以用最近添加的tensordot() 操作用 VexCL 编写:

vex::vector<double> A(ctx, n * m), B(ctx, n * m);
vex::vector<double> c(ctx, n), d(ctx, n);

vex::slicer<1> s1(vex::extents[n]);    // shape of the vectors
vex::slicer<2> s2(vex::extents[n][m]); // shape of the matrices

using vex::_;
d = vex::tensordot(s2[_](A * B), s1[_](c), vex::axes_pairs(1, 0));

这将导致矩阵向量乘积的实现非常简单(因此可能不如供应商提供的 BLAS 内核有效)。但不会涉及临时程序,将启动单个内核。

一个警告:tensordot() 只能用于单设备上下文。

【讨论】:

以上是关于具有临时消除功能的 C++ OpenCL 矩阵库的主要内容,如果未能解决你的问题,请参考以下文章

C++实战之OpenCL矩阵相乘优化

C++实战之OpenCL矩阵相乘

带有目标相机的 C++ 3d 矢量/矩阵库的建议

为啥 OpenCL 没有矩阵数据类型?

从函数返回,具有动态字段的对象 c++

OpenCL C/C++ 动态绑定库(win32 等)