VexCL似乎是一个非常有吸引力的gpu编程库。
不幸的是,它是一个非常年轻的图书馆,那里的信息很少。 我一直在寻找如何执行矩阵向量乘法,但我发现的唯一矩阵表示是vex :: SpMat,它包含一个稀疏矩阵。
如果矩阵是密集的,那么稀疏表示通常对计算效率较低。
我所有的矩阵都很密集,我想知道如何在VexCL中有效地执行它。
答案 0 :(得分:10)
我是VexCL库的开发者。
我必须承认密集的线性代数操作不在我的优先级列表中。我认为很难以VexCL支持的各种设备(即OpenCL / CUDA)的性能可移植方式实现这些。这个任务最好留给供应商BLAS实现(但欢迎补丁!)。
您可能还想查看opensource ViennaCL库,它提供密集矩阵操作并支持OpenCL,CUDA和OpenMP后端。他们的autotuning framework允许他们获得与供应商调整的库接近的便携性能。
话虽如此,除了为VexCL中的密集矩阵 - 矢量产品提供定制内核之外,还有几个选项。首先,您可以根据矩阵向量乘积的定义使用直接实现:
using namespace vex;
Context ctx(Filter::Env && Filter::Count(1));
// The n x m matrix stored row-wise.
vector<double> A(ctx, n * m);
// The LHS and RHS vectors.
vector<double> x(ctx, m);
vector<double> y(ctx, n);
// Make an n x m matrix from vector x by replicating it along the first
// dimension (reshape), multiply it elementwise by A, and reduce the result
// along the second dimension.
// In other words, y_i = sum_j (A_ij * x_j)
y = reduce<SUM>(
extents[n][m], // Shape of the expression to reduce,
A * reshape(
x,
extents[n][m], // (We need an n x m matrix...
extents[1] // ... but we only have vector of size m).
), // the expression,
1 // and the dimension to reduce along.
);
使用C ++ 14,可以很容易地将其隐藏到函数调用中:
template <class M, class V>
auto prod(size_t n, size_t m, M &&A, V &&x) {
using namespace vex;
auto NxM = extents[n][m];
return reduce<SUM>(NxM, A * reshape(x, NxM, extents[1]), 1);
}
其次,您可以使用特定于供应商的库。例如,如果将CUDA后端与VexCL一起使用,则可以获得指向VexCL分配的内存区域的原始指针并调用cuBLAS gemv:
double one = 1;
double zero = 0;
cublasDgemv(
cublas_handle, CUBPLAS_OP_N, n, m,
&zero,
A(0).raw_ptr(), m,
x(0).raw_ptr(), 1
&one,
y(0).raw_ptr(), 1
);
第一种方法应该不如调用cuBLAS有效。它的优点是reduce()
调用的结果是一个向量表达式,原则上你可以将其中的几个组合成一个融合的计算内核。例如,您可以在单个内核调用中计算Ax + By
,sin(Ax) + cos(By)
或(A + B)(x - y)
或任何其他向量表达式:
z = prod(n, m, A, x) + prod(n, m, B, y);
z = sin(prod(n, m, A, x)) + cos(prod(n, m, B, y));
z = prod(n, m, A + B, x - y);
这可能比几个链接的cuBLAS调用更有效。我有examples因此,VexCL的表现优于cuBLAS 1.5倍。