实现CUDA矢量对角化的最佳方法

时间:2015-05-31 13:00:44

标签: matrix cuda

我想要做的是输入我的m×n矩阵,并行地,为矩阵的每列构造n个方形对角矩阵,对每个方形对角矩阵执行操作,然后重新组合结果。我该怎么做呢?

到目前为止,我开始使用m x n矩阵;前一个矩阵计算的结果,其中每个元素使用函数y = f(g(x))计算。

这给了我一个包含n个列元素[f1,f2 ... fn]的矩阵,其中每个fn代表一个高度为m的列向量。

从这里开始,我想区分矩阵的每一列与g(x)。区分fn(x)w.r.t。 g(x)产生具有元素f'(x)的方阵。在约束条件下,这个方形矩阵减少为雅可比矩阵,每行的元素沿着方阵的对角线,等于fn,所有其他元素等于零。

因此,有必要为每个矢量行fn。

构造对角线

为此,我采用定义为A(hA x 1)的目标向量,该目标向量是从较大的A(m×n)矩阵中提取的。然后我准备了一个定义为C(hA x hA)的归零矩阵,用于保持对角线。

目的是将矢量A对角化为方形矩阵,A的每个元素都位于C的对角线上,其他一切都为零。

使用一些预先构建的例程可能有更有效的方法来实现这一点而不构建一个全新的内核,但请注意,出于这些目的,这种方法是必要的。

这里显示了完成此任务的内核代码(可行):

_cudaDiagonalizeTest << <5, 1 >> >(d_A, matrix_size.uiWA, matrix_size.uiHA, d_C, matrix_size.uiWC, matrix_size.uiHC);

__global__ void _cudaDiagonalizeTest(float *A, int wA, int hA, float *C, int wC, int hC)
{
    int ix, iy, idx;

    ix = blockIdx.x * blockDim.x + threadIdx.x;
    iy = blockIdx.y * blockDim.y + threadIdx.y;

    idx = iy * wA + ix;

    C[idx * (wC + 1)] = A[idx];

}

我有点怀疑这是一个非常天真的解决方案,并且想知道是否有人可以举例说明我如何能够使用

a)减少

b)推力

对于大行大小的向量,我希望能够使用GPU的多线程功能将任务分成小作业,并将每个结果与__syncthreads()结合起来。

下图显示了所需的结果。

我已阅读NVIDIA's article on reduction,但无法达到预期效果。

非常欢迎任何帮助或解释。

enter image description here 感谢。

enter image description here

矩阵A是具有4列的目标。我想获取每一列,并将其元素作为对角线复制到矩阵B中,遍历每一列。

2 个答案:

答案 0 :(得分:2)

我创建了一个基于推力的简单示例。它使用列主要顺序将矩阵存储在thrust::device_vector中。它应该适用于更大的行/列数。

另一种方法可能基于thrust strided_range example

此示例执行您想要的操作(根据输入向量填充对角线)。但是,取决于您如何继续使用生成的矩阵来区分&#34;区分&#34;如果可能存在稀疏存储(没有所有零条目),则可能仍然值得研究,因为这将减少内存消耗并简化迭代。

#include <thrust/device_vector.h>
#include <thrust/scatter.h>
#include <thrust/sequence.h>
#include <thrust/iterator/transform_iterator.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/functional.h>
#include <iostream>


template<typename V>
void print_matrix(const V& mat, int rows, int cols)
{
   for(int i = 0; i < rows; ++i)
   {
     for(int j = 0; j < cols; ++j)
     {
      std::cout << mat[i + j*rows] << "\t";
     }
     std::cout << std::endl;
   }
}

struct diag_index : public thrust::unary_function<int,int>
{
  diag_index(int rows) : rows(rows){}

  __host__ __device__
  int operator()(const int index) const
  {
      return (index*rows + (index%rows));
  }

  const int rows;
};

int main()
{
  const int rows = 5; 
  const int cols = 4;

  // allocate memory and fill with demo data
  // we use column-major order
  thrust::device_vector<int> A(rows*cols);
  thrust::sequence(A.begin(), A.end());

  thrust::device_vector<int> B(rows*rows*cols, 0);

  // fill diagonal matrix
  thrust::scatter(A.begin(), A.end(), thrust::make_transform_iterator(thrust::make_counting_iterator(0),diag_index(rows)), B.begin());

  print_matrix(A, rows, cols);
  std::cout << std::endl;
  print_matrix(B, rows, rows*cols);
  return 0;
}

此示例将输出:

0    5    10    15    
1    6    11    16    
2    7    12    17    
3    8    13    18    
4    9    14    19    

0    0    0    0    0    5    0    0    0    0    10    0    0    0    0    15    0    0    0    0    
0    1    0    0    0    0    6    0    0    0    0    11    0    0    0    0    16    0    0    0    
0    0    2    0    0    0    0    7    0    0    0    0    12    0    0    0    0    17    0    0    
0    0    0    3    0    0    0    0    8    0    0    0    0    13    0    0    0    0    18    0    
0    0    0    0    4    0    0    0    0    9    0    0    0    0    14    0    0    0    0    19    

答案 1 :(得分:-1)

不使用推力的替代答案如下:

_cudaMatrixTest << <5, 5 >> >(d_A, matrix_size.uiWA, matrix_size.uiHA, d_C, matrix_size.uiWC, matrix_size.uiHC);

__global__ void _cudaMatrixTest(float *A, int wA, int hA, float *C, int wC, int hC)
{
    int ix, iy, idx;

    ix = blockIdx.x * blockDim.x + threadIdx.x;
    iy = blockIdx.y * blockDim.y + threadIdx.y;

    idx = iy * wA + ix;

    C[idx * wC + (idx % wC)] = A[threadIdx.x * wA + (ix / wC)];
}

其中d_A是

0    5    10    15    
1    6    11    16    
2    7    12    17    
3    8    13    18    
4    9    14    19    

这两个答案都是可行的解决方案。问题是,哪个更好/更快?