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

Matrix 实现CUDA向量对角化的最佳方法,matrix,cuda,Matrix,Cuda,我要做的是输入我的m x n矩阵,并行地,为矩阵的每一列构造n个平方对角矩阵,对每个平方对角矩阵执行一个运算,然后重新组合结果。我该怎么做 到目前为止,我从一个m×n矩阵开始;先前矩阵计算的结果,其中每个元素使用函数y=f(g(x))进行计算 这给了我一个包含n个列元素[f1,f2…fn]的矩阵,其中每个fn表示高度为m的列向量 从这里,我想区分矩阵中关于g(x)的每一列。微分fn(x)w.r.t.g(x)得到一个含有元素f’(x)的方阵。在约束条件下,该方阵简化为雅可比矩阵,每行元素沿方阵对角

我要做的是输入我的m x n矩阵,并行地,为矩阵的每一列构造n个平方对角矩阵,对每个平方对角矩阵执行一个运算,然后重新组合结果。我该怎么做

到目前为止,我从一个m×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 x 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];

}
\u cudaDiagonalizeTest>(d_A,matrix_size.uiWA,matrix_size.uiHA,d_C,matrix_size.uiWC,matrix_size.uiHC);
__全局无效CudDiagonalizeTest(浮点*A、整数wA、整数hA、浮点*C、整数wC、整数hC)
{
int ix、iy、idx;
ix=块IDX.x*块DIM.x+线程IDX.x;
iy=块IDX.y*块尺寸y+线程IDX.y;
idx=iy*wA+ix;
C[idx*(wC+1)]=A[idx];
}
我有点怀疑这是一种非常幼稚的解决方案,我想知道是否有人可以举一个例子,说明我如何使用

a) 减少

b) 推力

对于行大小较大的向量,我希望能够使用GPU的多线程功能将任务分块到小作业中,并在最后将每个结果与u syncthreads()结合起来

下图显示了所需的结果

我读过,但没有达到预期的效果

欢迎提供任何帮助或解释

谢谢


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

我创建了一个基于推力的简单示例。它使用列主顺序将矩阵存储在
推力::设备\u向量中。它应该可以很好地扩展到更大的行/列计数

另一种方法可以基于

此示例执行您想要的操作(根据输入向量填充对角线)。但是,根据您如何将结果矩阵进行到“区分”步骤,可能仍然值得研究稀疏存储(没有所有零项)是否可行,因为这将减少内存消耗并简化迭代

#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;
}

不使用推力的备选答案如下:

_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)];
}

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

我不确定我是否完全符合您的要求。你能提供一个输入和输出的样本吗?我看不出降价如何适用于这个问题。你真的确定你需要这样做吗?如果你有一个纯对角矩阵,存储和使用它的最好方法就是像你已经拥有的那样——作为对角数组。仅仅加载和存储零会消耗大量内存、大量内存带宽和大量触发器,通常没有什么好的理由受影响向量行的对角化只是更大操作中的一小步。我尝试的是并行地对m x n矩阵的每一行进行对角化,用这n个对角化的方矩阵执行计算(m x n矩阵中有n行,因此在对角化了每一行之后有n个对角化的方矩阵),然后将计算结果再次相加。所有这些都必须在内核中完成。有没有一种有效的方法可以做到这一点?你确定你的示例内核真的做到了吗?无论如何,让我再猜猜你的意思:你想把
A(x,y)
复制到
C(x,x+y)
,其中
M(x,y)
表示
M
x
第行和
y
第列的条目?(使用基于0的索引)和。。。也许用零填充
C
的其余部分?或者,您可能想将
A(x,y)
复制到
C(x,(x+y)mod N)
,其中
N
C
的列数。请参阅第二幅图以了解更清晰的图片。矩阵A是一个较小的5 x 4矩阵(5行4列)。矩阵B是一个较大的5 x 20矩阵(5行20列)。我想取矩阵A的4列中的每一列(每列都是高度为5的向量),并将其元素排列成对角线。每个对角线结构将产生一个5 x 5的矩阵,然后将其放入更大的5 x 20矩阵B中。我想使用CUDA并行执行此操作。请参考原始帖子底部的图片。有没有不使用推力的方法可以做到这一点?我找到了相应的答案,并将其作为备选答案发布。你的代码看起来很奇怪。您正在启动1D threadblocks和grid,因此
iy
将始终为0,而且您总共启动了25个线程,但您只有20个位置要填充。您是正确的。它实际上是一个5 x 5,而不是矩阵所示的5 x 4。而且,iy不一定要在那里。只是一句俏皮话
_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)];
}
0    5    10    15    
1    6    11    16    
2    7    12    17    
3    8    13    18    
4    9    14    19