【问题标题】:Eigen JacobiSVD cuda compile errorEigen JacobiSVD cuda 编译错误
【发布时间】:2018-04-11 17:58:24
【问题描述】:

关于在我的 cuda 函数中调用 JacobiSVD 时出现错误。

这是导致错误的代码部分。

Eigen::JacobiSVD<Eigen::Matrix3d> svd( cov_e, Eigen::ComputeThinU | Eigen::ComputeThinV);

这是错误信息。

CUDA_voxel_building.cu(43):错误:调用 __host__ 来自 __global__ 的函数(“Eigen::JacobiSVD, (int)2> ::JacobiSVD”) 不允许使用函数(“内核”)

我使用下面的命令来编译它。

nvcc -std=c++11 -D_MWAITXINTRIN_H_INCLUDED -D__STRICT_ANSI__ -ptx CUDA_voxel_building.cu

我在 ubuntu 16.04 上使用带有 eigen3 的代码 8.0。 似乎特征值分解等其他函数也给出了相同的错误。

有人知道解决方案吗?我在下面附上了我的代码。

//nvcc -ptx CUDA_voxel_building.cu
#include </usr/include/eigen3/Eigen/Core>
#include </usr/include/eigen3/Eigen/SVD>
/*
#include </usr/include/eigen3/Eigen/Sparse>

#include </usr/include/eigen3/Eigen/Dense>
#include </usr/include/eigen3/Eigen/Eigenvalues> 

*/





__global__ void kernel(double *p, double *breaks,double *ind,  double *mu, double *cov,  double *e,double *v, int *n, char *isgood,  int minpts, int maxgpu){
    bool debuginfo = false;
    int idx = threadIdx.x + blockIdx.x * blockDim.x;
    if(debuginfo)printf("Thread %d got pointer\n",idx);
    if( idx < maxgpu){


        int s_ind = breaks[idx];
        int e_ind = breaks[idx+1];
        int diff = e_ind-s_ind;

        if(diff >minpts){
            int cnt = 0;
            Eigen::MatrixXd local_p(3,diff) ;
            for(int k = s_ind;k<e_ind;k++){
                int temp_ind=ind[k];

                //Eigen::Matrix<double, 3, diff> local_p;   
                local_p(1,cnt) =  p[temp_ind*3];
                local_p(2,cnt) =  p[temp_ind*3+1];
                local_p(3,cnt) =  p[temp_ind*3+2];
                cnt++;
            }

            Eigen::Matrix3d centered = local_p.rowwise() - local_p.colwise().mean();
            Eigen::Matrix3d cov_e = (centered.adjoint() * centered) / double(local_p.rows() - 1);

            Eigen::JacobiSVD<Eigen::Matrix3d> svd( cov_e, Eigen::ComputeThinU | Eigen::ComputeThinV);
     /*         Eigen::Matrix3d Cp = svd.matrixU() * svd.singularValues().asDiagonal() * svd.matrixV().transpose();


            mu[idx]=p[ind[s_ind]*3];
            mu[idx+1]=p[ind[s_ind+1]*3];
            mu[idx+2]=p[ind[s_ind+2]*3];

            e[idx]=svd.singularValues()(0);
            e[idx+1]=svd.singularValues()(1);
            e[idx+2]=svd.singularValues()(2);

            n[idx] = diff;
            isgood[idx] = 1;

            for(int x = 0; x < 3; x++)
            {
                for(int y = 0; y < 3; y++)
                {
                    v[x+ 3*y +idx*9]=svd.matrixV()(x, y);
                    cov[x+ 3*y +idx*9]=cov_e(x, y);
                    //if(debuginfo)printf("%f ",R[x+ 3*y +i*9]);
                    if(debuginfo)printf("%f ",Rm(x, y));
                }
            }
*/

        } else {
            mu[idx]=0;
            mu[idx+1]=0;
            mu[idx+2]=0;

            e[idx]=0;
            e[idx+1]=0;
            e[idx+2]=0;

            n[idx] = 0;
            isgood[idx] = 0;

            for(int x = 0; x < 3; x++)
            {
                for(int y = 0; y < 3; y++)
                {
                    v[x+ 3*y +idx*9]=0;
                    cov[x+ 3*y +idx*9]=0;
                }
            }
        }




    }
}

【问题讨论】:

  • 没有解决办法。您不能只从内核内部调用随机主机代码。除非有专门编写的设备代码库(我强烈怀疑在这种情况下没有)。那么你试图做的事情是不可能的。
  • 谢谢,talonmies。我知道我不能从内核内部调用主机代码,但据我所知 cuda 8.0 支持 Eigen。而且我已经在我的一些内核函数中使用了 Eigen。我认为我的问题仅与 JacobiSVD 和 Eigen 中的其他特定功能有关。你还说问题只是因为在内核中调用了host函数吗?
  • Eigen 中的一些简单函数和容器类型已扩展为在 GPU 上工作。 AFAIK,大多数图书馆都没有。至于CUDA 8“支持特征”,这意味着您可以使用nvcc编译主机特征代码而不会炸毁C​​UDA前端,这曾经是这种情况。
  • @talonmies 这个问题非常具有本征特征,IMO 并不是您链接到的问题的副本。例如,我认为 Eigen::SelfAdjointEigenSolver 适用于 cuda(具有固定大小的矩阵)。在这里使用它更有意义,因为cov_e 是自伴随的
  • @chtz:好的,现在这是一个开放的特征问题。试试吧。

标签: eigen nvcc


【解决方案1】:

首先,Ubuntu 16.04提供了Eigen 3.3-beta1,其实不推荐使用。我建议升级到更新的版本。此外,要包含 Eigen,请编写(例如):

#include <Eigen/Eigenvalues>

并使用-I /usr/include/eigen3(如果您使用操作系统提供的版本)进行编译,或者更好的是-I /path/to/local/eigen-version

然后,正如 talonmies 所指出的,你不能从内核调用主机函数,(我现在不确定,为什么 JacobiSVD 没有被标记为设备函数),但在你的情况下它会做很多无论如何,使用Eigen::SelfAdjointEigenSolver 更有意义。由于您要分解的矩阵是固定大小的 3x3,因此您实际上应该使用优化的 computeDirect 方法:

Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eig; // default constructor
eig.computeDirect(cov_e); // works for 2x2 and 3x3 matrices, does not require loops

似乎computeDirect 甚至可以在 Ubuntu 提供的测试版上运行(我仍然建议更新)。

一些不相关的注释:

  1. 以下是错误的,因为您应该从索引 0 开始:

    local_p(1,cnt) =  p[temp_ind*3];
    local_p(2,cnt) =  p[temp_ind*3+1];
    local_p(3,cnt) =  p[temp_ind*3+2];
    

    另外,你可以写成一行:

    local_p.col(cnt) = Eigen::Vector3d::Map(p+temp_ind*3);
    
  2. 这条线不适合(除非diff==3):

    Eigen::Matrix3d centered = local_p.rowwise() - local_p.colwise().mean();
    

    您的意思可能是(local_p 实际上是 3xn 而不是 nx3

    Eigen::Matrix<double, 3, Eigen::Dynamic> centered = local_p.colwise() - local_p.rowwise().mean();
    

    在计算 cov_e 时,您需要 .adjoint() 第二个因素,而不是第一个。

  3. 您可以通过直接将Eigen::Matrix3d sum2Eigen::Vector3d sumsum2 += v*v.adjoint()sum +=v 累加并计算来避免'大'矩阵local_pcentered

    Eigen::Vector3d mu = sum / diff;
    Eigen::Matrix3d cov_e = (sum2 - mu*mu.adjoint()*diff)/(diff-1);
    

【讨论】:

  • 嗨,伙计!谢谢你的好建议。不幸的是,在我尝试安装不同版本的 cuda(7.5、8.0)后,我的 nvcc 无法找到 gcc。一旦我先解决了这个问题,我会告诉 SelfAdjointEigenSolver 是否有效。
  • 按照您的建议,我已经安装了最新的 Eigen 并使用该选项进行了编译。幸运的是,computeDirect 在 cuda 代码中完美运行,尽管 JacobiSVD 仍被标记为主机函数。我非常感谢您对编码风格和正确使用功能的友好建议。这对我真的很有帮助。谢谢!
猜你喜欢
  • 2012-09-29
  • 1970-01-01
  • 1970-01-01
  • 2011-02-21
  • 2015-11-18
  • 2016-12-16
  • 1970-01-01
  • 2015-09-26
  • 1970-01-01
相关资源
最近更新 更多