如何在CUDA内核中使用Eigen

23
Eigen是一个C++的线性代数库,官网为http://eigen.tuxfamily.org。使用基本数据类型(如基本浮点数数组)很容易,只需将其复制到设备内存并将指针传递给CUDA核函数即可。但Eigen矩阵是复杂类型,因此如何将其复制到设备内存并让CUDA核函数进行读/写呢?

那么 https://developer.nvidia.com/cuBLAS 呢? - Marco A.
1
这是一个遗留项目,严重依赖于Eigen,最好不要替换它。 - Mickey Shine
1
更简单的方法可能是在进入设备之前切换到CUBLAS,如果eigen没有设计为在GPU上工作,则无法使用它(否则会出现可怕的错误/性能问题)。还要看一下统一内存,可以节省一些复制麻烦(或者如果您想要完全控制,可以自己操作)。 - Marco A.
1
有没有一种方法可以从Eigen获取原始数据指针,例如float *? - Mickey Shine
“Eigen矩阵是复杂类型”是什么意思?请注意,在此上下文中,复杂类型可以是std::complex<double>。您可以在Eigen中使用实矩阵...您的问题有些混乱:“使用基本数据类型(如基本浮点数组)很容易,并将其复制到设备内存并将指针传递给CUDA内核”,您是指Eigen易于使用普通类型还是CUDA? - luk32
显示剩余4条评论
4个回答

27
自从2016年11月(Eigen 3.3发布)以来,出现了一个新选项:在CUDA内核中直接使用Eigen-请参见此问题
来自链接问题的示例:
__global__ void cu_dot(Eigen::Vector3f *v1, Eigen::Vector3f *v2, double *out, size_t N)
{
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    if(idx < N)
    {
        out[idx] = v1[idx].dot(v2[idx]);
    }
    return;
}

将一个包含 Eigen::Vector3f 的数组复制到设备:

Eigen::Vector3f *host_vectors = new Eigen::Vector3f[N];
Eigen::Vector3f *dev_vectors;
cudaMalloc((void **)&dev_vectors, sizeof(Eigen::Vector3f)*N)
cudaMemcpy(dev_vectors, host_vectors, sizeof(Eigen::Vector3f)*N, cudaMemcpyHostToDevice)

11
如果你只是想通过原始C指针访问 Eigen::Matrix 的数据,那么你可以使用 .data() 函数。默认情况下,系数按列主序顺序顺序存储在内存中,如果您要求,则按行主序存储:

如果您只需要访问Eigen :: Matrix的数据,可以使用.data()函数来通过原始C指针访问。默认情况下,系数以列优先顺序依次存储在内存中,或者如果您请求,则以行优先顺序存储:

MatrixXd A(10,10);
double *A_data = A.data();

2
@MickeyShine:注意,在使用包含POD结构的STL向量时,这类似于使用CUDA时所做的操作。正如ggael所说,只需小心默认存储顺序即可。 - BenC

5
除了重写和改装代码之外,还有一个与研究项目的副产品一起编写的Eigen兼容库,在GPU上执行矩阵计算,并且您可以使用多个后端:https://github.com/rudaoshi/gpumatrix 我不能保证它是否有效,但如果它有效,则可能正是您要寻找的。
如果您想要更通用的解决方案,this thread似乎包含非常有用的信息。

似乎这是最简单的方法,使用这种方法或者普通的C数组。我点赞+1。 - Marco A.

3
有两种方法。
第一种是让Eigen在GPU上工作,这可能很难且性能不佳。如果在GPU上工作仅意味着编译并产生结果的话,至少是这样的。Eigen实际上是专门针对现代CPU进行手动优化的。在内部,Eigen使用自己的分配器和内存布局,这些可能不适用于CUDA。
第二种方法更容易实现且不会破坏旧的Eigen代码,并且可能是您的情况下唯一合适的方法。将底层矩阵切换到普通矩阵(即double**)并使用Eigen::Map。这样,您将拥有面向普通数据类型的Eigen接口,因此代码不应该出问题,并且可以像通常那样将矩阵发送到GPU作为正常的c数组。缺点是可能无法充分利用Eigen的潜力,但是如果将大部分工作转移到GPU上,则可以接受。
实际上,这有点颠倒了。您可以使Eigen在普通数组上工作,而不是使Eigen数组在CUDA上工作。

第二种可能是一种方法。谢谢大家。 - Mickey Shine

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