【问题标题】:Cuda: least square solving , poor in speedCuda:最小二乘求解,速度差
【发布时间】:2014-04-12 15:12:06
【问题描述】:

最近,我用 Cuda 写了一个算法,叫做“正交匹配追踪”。在我丑陋的 Cuda 代码中,整个迭代需要 60 秒,而 Eigen lib 只需 3 秒......

在我的代码中,矩阵 A 是 [640,1024] 并且 y 是 [640,1] ,在每一步中我从 A 中选择一些向量来组成一个名为 A_temp [640,itera] 的新矩阵,iter=1:500 .我在 cpu 中新建了一个数组 MaxDex_Host[] 来告诉选择哪一列。

我想使用最小二乘法从 A_temp*x_temp=y 获取 x_temp[itera,1],我使用 cula API 'culaDeviceSgels' 和 cublas 矩阵向量乘法 API。

所以 culaDeviceSgels 会调用 500 次,我认为这会比 Eigen lib 的 QR.Sovler 更快。

我检查了 Nisight 性能分析,我发现 custreamdestory 需要很长时间。我在迭代之前初始化 cublas 并在得到结果后破坏它。所以我想知道 custreamdestory 是什么,与 cublasdestory 不同?

主要问题是 memcpy 和函数 'gemm_kernel1x1val' 。我认为这个函数来自'culaDeviceSgels'

while(itera

        MaxDex_Host[itera]=pos;
    itera++; 
    float* A_temp_cpu=new float[M*itera]; // matrix all in col-major
    for (int j=0;j<itera;j++) // to  get A_temp [M,itera] , the MaxDex_Host[] shows the positon of which column of A to chose , 
    {
        for (int i=0;i<M;i++) //M=640 , and A is 640*1024 ,itera is add 1 each step
        {
            A_temp_cpu[j*M+i]=A[MaxDex_Host[j]*M+i];
        }
    }
          // I must allocate one more array because culaDeviceSgels will decompose the one input Array ,  and I want to use A_temp after least-square solving.
    float* A_temp_gpu;
    float* A_temp2_gpu;  
    cudaMalloc((void**)&A_temp_gpu,Size_float*M*itera);
    cudaMalloc((void**)&A_temp2_gpu,Size_float*M*itera);
    cudaMemcpy(A_temp_gpu,A_temp_cpu,Size_float*M*itera,cudaMemcpyHostToDevice);
    cudaMemcpy(A_temp2_gpu,A_temp_gpu,Size_float*M*itera,cudaMemcpyDeviceToDevice);
    culaDeviceSgels('N',M,itera,1,A_temp_gpu,M,y_Gpu_temp,M);// the x_temp I want is in y_Gpu_temp's return value ,  stored in the y_Gpu_temp[0]——y_Gpu_temp[itera-1]
     float* x_temp;
    cudaMalloc((void**)&x_temp,Size_float*itera);
    cudaMemcpy(x_temp,y_Gpu_temp,Size_float*itera,cudaMemcpyDeviceToDevice);

cuda的内存管理好像太复杂了,有没有其他方便的方法来解决最小二乘法?

【问题讨论】:

    标签: c++ matrix cuda cublas


    【解决方案1】:

    我认为custreamdestorygemm_kernel1x1val 是由您正在使用的API 在内部调用的,因此与它们没有太大关系。

    为了改进您的代码,我建议您执行以下操作。

    1. 您可以通过保留矩阵A 的设备副本来摆脱A_temp_cpu。然后您可以通过内核分配将A 的行复制到A_temp_gpuA_temp2_gpu 的行中。这将避免执行前两个cudaMemcpys。
    2. 您可以使用itera 的最大可能值而不是iterawhile 循环之外预分配A_temp_gpuA_temp2_gpu。这将避免循环内的前两个cudaMallocs。这同样适用于x_temp
    3. 据我所知,culaDeviceSgels 可以求解线性方程组。我认为你也可以只使用 cuBLAS API 来做同样的事情。例如,您可以先通过cublasDgetrfBatched() 执行LU 分解,然后使用cublasStrsv() 两次来求解两个出现的线性系统。您可能希望看看这个解决方案是否会导致更快的算法。

    【讨论】:

    • 谢谢。 MaxDex_Host 数组在主机上。如果我希望内核分配将 A 的行复制到 A_temp ,我应该将 MaxDex_Host 数组分配给设备吗?
    • 是的,您应该将MaxDex_Host 数组移动到设备上,以便能够执行您需要的行排列。
    • 我终于得到了 1.5 秒的总计算时间,谢谢
    • 哦,如果我想将整个gpu数组复制到另一个gpu数组,使用cudaMemcpyDeviceToDevice还是写一个内核?
    • @Zziggurats 我会说一个内核。 cudaMemcpyDeviceToDevice 可能很昂贵,分配内核可能更可取,请参阅CUDA Device To Device transfer expensive
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-16
    • 2013-08-06
    • 2019-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多