Matrix 使用CUDA/ARTH排列矩阵(和相应向量)的行

Matrix 使用CUDA/ARTH排列矩阵(和相应向量)的行,matrix,cuda,permutation,thrust,Matrix,Cuda,Permutation,Thrust,我希望对存储为交错数组(即,由行主C样式格式的向量支持)的矩阵行进行排列,并对相应向量的元素应用相同的排列 假设矩阵维数为RxC,相应的向量有R个元素 我目前的想法是生成一个R索引的排列,然后使用stress::stable\u sort\u by\u key排列向量,如图所示 然后我可以创建另一个置换向量,它将我之前创建的元素的每个元素重复C次 因此,如果R=4,C=3,且原始置换索引向量为[4,2,3,1],则矩阵的置换向量为[4,4,4,2,2,3,3,1,1]。 通过使用稳定排序,矩阵行

我希望对存储为交错数组(即,由行主C样式格式的向量支持)的矩阵行进行排列,并对相应向量的元素应用相同的排列

假设矩阵维数为RxC,相应的向量有R个元素

我目前的想法是生成一个R索引的排列,然后使用
stress::stable\u sort\u by\u key
排列向量,如图所示

然后我可以创建另一个置换向量,它将我之前创建的元素的每个元素重复C次

因此,如果R=4,C=3,且原始置换索引向量为[4,2,3,1],则矩阵的置换向量为[4,4,4,2,2,3,3,1,1]。 通过使用稳定排序,矩阵行中的元素不应被置换

我的问题是,是否有更好/更有效的方法,使用推力或普通CUDA

例如:

原始矩阵:

[ 1 1 1 1 ]
[ 2 2 2 2 ]
[ 3 3 3 3 ]
[ 4 4 4 4 ]
[ 5 5 5 5 ]
原始向量:

[1 2 3 4 5]
排列顺序:

[5 3 1 2 4]
置换矩阵:

[ 5 5 5 5 ]
[ 3 3 3 3 ]
[ 1 1 1 1 ]
[ 2 2 2 2 ]
[ 4 4 4 4 ]
置换向量:

[5 3 1 2 4]
我的用例是,对于每个示例,我都有一个特征矩阵和一个对应标签向量。我想对矩阵进行置换,并对向量应用相同的置换,就像SGD迭代之前的洗牌步骤一样。 我希望有连续的行并遍历它们的原因是,我计划使用cuBLAS gemv来执行矩阵向量运算,它假设矩阵在内存中以类似的方式排列(尽管是列主格式,这意味着我需要像这样调用它)

我的问题是,是否有更好/更有效的方法,使用推力

我相信有。置换向量提供了将输入矩阵的内容直接复制到置换矩阵所需的所有信息,而无需排序

一个有用的特性是
置换迭代器
。置换迭代器允许我们在任何操作中对输入元素的选择进行动态重新排序。如果我们提供适当的索引计算函子,我们可以将线性索引(通过
计数迭代器
)传递给索引函子,以便(通过
变换迭代器
)为复制操作中的任何元素创建适当的置换输入索引

以下是一个成功的例子:

$ cat t1061.cu
#include <thrust/iterator/permutation_iterator.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/iterator/transform_iterator.h>
#include <thrust/device_vector.h>
#include <thrust/copy.h>
#include <iostream>
#include <assert.h>

typedef int mytype;

struct copy_idx_func : public thrust::unary_function<unsigned, unsigned>
{
  size_t c;
  unsigned *p;
  copy_idx_func(const size_t _c, unsigned *_p) : c(_c),p(_p) {};
  __host__ __device__
  unsigned operator()(unsigned idx){
    unsigned myrow = idx/c;
    unsigned newrow = p[myrow]-1;
    unsigned mycol = idx%c;
    return newrow*c+mycol;
  }
};


int main(){

  const mytype mat[]   = {1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5};
  const mytype vec[]   = {1,2,3,4,5};
  const unsigned per[] = {5,3,1,2,4};

  const size_t msize = sizeof(mat)/sizeof(mytype);
  const size_t vsize = sizeof(vec)/sizeof(mytype);
  const size_t psize = sizeof(per)/sizeof(unsigned);
  const size_t cols  = msize/vsize;
  // const size_t rows  = vsize;
  assert(msize%vsize == 0);
  assert(vsize == psize);

  thrust::device_vector<mytype>   d_m(mat, mat+msize);
  thrust::device_vector<mytype>   d_v(vec, vec+vsize);
  thrust::device_vector<unsigned> d_p(per, per+psize);
  thrust::device_vector<mytype>   d_rm(msize);
  thrust::device_vector<mytype>   d_rv(vsize);
  std::cout << "Initial Matrix:" << std::endl;
  thrust::copy_n(d_m.begin(), msize, std::ostream_iterator<mytype>(std::cout, ","));

  // permute the matrix
  thrust::copy_n(thrust::make_permutation_iterator(d_m.begin(), thrust::make_transform_iterator(thrust::counting_iterator<unsigned>(0), copy_idx_func(cols,thrust::raw_pointer_cast(d_p.data())))), msize, d_rm.begin());

  std::cout << std::endl << "Permuted Matrix:" << std::endl;
  thrust::copy_n(d_rm.begin(), msize, std::ostream_iterator<mytype>(std::cout, ","));
  std::cout << std::endl << "Initial Vector:" << std::endl;
  thrust::copy_n(d_v.begin(), vsize, std::ostream_iterator<mytype>(std::cout, ","));

  // permute the vector
  thrust::copy_n(thrust::make_permutation_iterator(d_v.begin(), thrust::make_transform_iterator(thrust::counting_iterator<unsigned>(0),  copy_idx_func(1,thrust::raw_pointer_cast(d_p.data())))), vsize, d_rv.begin());

  std::cout << std::endl << "Permuted Vector:" << std::endl;
  thrust::copy_n(d_rv.begin(), vsize, std::ostream_iterator<mytype>(std::cout, ","));
  std::cout << std::endl;
}

$ nvcc -o t1061 t1061.cu
$ ./t1061
Initial Matrix:
1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5,
Permuted Matrix:
5,5,5,5,5,3,3,3,3,3,1,1,1,1,1,2,2,2,2,2,4,4,4,4,4,
Initial Vector:
1,2,3,4,5,
Permuted Vector:
5,3,1,2,4,
$
$cat t1061.cu
#包括
#包括
#包括
#包括
#包括
#包括
#包括
typedef int-mytype;
结构复制函数:公共推力::一元函数
{
尺寸c;
无符号*p;
copy_idx_func(const size_t_c,unsigned*_p):c(_c),p(_p){};
__主机设备__
无符号运算符()(无符号idx){
无符号myrow=idx/c;
无符号newrow=p[myrow]-1;
无符号mycl=idx%c;
返回newrow*c+mycl;
}
};
int main(){
常数mytype mat[]={1,1,1,1,2,2,2,3,3,3,3,4,4,4,5,5,5};
const mytype vec[]={1,2,3,4,5};
常量无符号per[]={5,3,1,2,4};
const size_t msize=sizeof(mat)/sizeof(mytype);
const size\u t vsize=sizeof(vec)/sizeof(mytype);
const size\u t psize=sizeof(per)/sizeof(未签名);
const size\u t cols=msize/vsize;
//const size\u t rows=vsize;
断言(msize%vsize==0);
断言(vsize==psize);
推力:设备矢量d_m(mat,mat+msize);
推力:设备向量d_v(vec,vec+vsize);
推力:装置矢量d_p(per,per+psize);
推力:设备向量d_rm(msize);
推力:装置矢量d_rv(vsize);
标准::cout
我的问题是,是否有更好/更有效的方法,使用推力

我相信有。排列向量提供了所有需要的信息,可以直接将输入矩阵的内容复制到排列矩阵,而无需排序

这方面的一个有用功能是
置换迭代器
。置换迭代器允许我们动态地对输入元素的选择重新排序,以便在任何操作中使用。如果我们提供适当的索引计算函子,我们可以将线性索引(通过
计数迭代器
)传递给索引函子,以创建(通过
transform\u迭代器
)复制操作中任何元素的适当置换输入索引

以下是一个成功的例子:

$ cat t1061.cu
#include <thrust/iterator/permutation_iterator.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/iterator/transform_iterator.h>
#include <thrust/device_vector.h>
#include <thrust/copy.h>
#include <iostream>
#include <assert.h>

typedef int mytype;

struct copy_idx_func : public thrust::unary_function<unsigned, unsigned>
{
  size_t c;
  unsigned *p;
  copy_idx_func(const size_t _c, unsigned *_p) : c(_c),p(_p) {};
  __host__ __device__
  unsigned operator()(unsigned idx){
    unsigned myrow = idx/c;
    unsigned newrow = p[myrow]-1;
    unsigned mycol = idx%c;
    return newrow*c+mycol;
  }
};


int main(){

  const mytype mat[]   = {1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5};
  const mytype vec[]   = {1,2,3,4,5};
  const unsigned per[] = {5,3,1,2,4};

  const size_t msize = sizeof(mat)/sizeof(mytype);
  const size_t vsize = sizeof(vec)/sizeof(mytype);
  const size_t psize = sizeof(per)/sizeof(unsigned);
  const size_t cols  = msize/vsize;
  // const size_t rows  = vsize;
  assert(msize%vsize == 0);
  assert(vsize == psize);

  thrust::device_vector<mytype>   d_m(mat, mat+msize);
  thrust::device_vector<mytype>   d_v(vec, vec+vsize);
  thrust::device_vector<unsigned> d_p(per, per+psize);
  thrust::device_vector<mytype>   d_rm(msize);
  thrust::device_vector<mytype>   d_rv(vsize);
  std::cout << "Initial Matrix:" << std::endl;
  thrust::copy_n(d_m.begin(), msize, std::ostream_iterator<mytype>(std::cout, ","));

  // permute the matrix
  thrust::copy_n(thrust::make_permutation_iterator(d_m.begin(), thrust::make_transform_iterator(thrust::counting_iterator<unsigned>(0), copy_idx_func(cols,thrust::raw_pointer_cast(d_p.data())))), msize, d_rm.begin());

  std::cout << std::endl << "Permuted Matrix:" << std::endl;
  thrust::copy_n(d_rm.begin(), msize, std::ostream_iterator<mytype>(std::cout, ","));
  std::cout << std::endl << "Initial Vector:" << std::endl;
  thrust::copy_n(d_v.begin(), vsize, std::ostream_iterator<mytype>(std::cout, ","));

  // permute the vector
  thrust::copy_n(thrust::make_permutation_iterator(d_v.begin(), thrust::make_transform_iterator(thrust::counting_iterator<unsigned>(0),  copy_idx_func(1,thrust::raw_pointer_cast(d_p.data())))), vsize, d_rv.begin());

  std::cout << std::endl << "Permuted Vector:" << std::endl;
  thrust::copy_n(d_rv.begin(), vsize, std::ostream_iterator<mytype>(std::cout, ","));
  std::cout << std::endl;
}

$ nvcc -o t1061 t1061.cu
$ ./t1061
Initial Matrix:
1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5,
Permuted Matrix:
5,5,5,5,5,3,3,3,3,3,1,1,1,1,1,2,2,2,2,2,4,4,4,4,4,
Initial Vector:
1,2,3,4,5,
Permuted Vector:
5,3,1,2,4,
$
$cat t1061.cu
#包括
#包括
#包括
#包括
#包括
#包括
#包括
typedef int-mytype;
结构复制函数:公共推力::一元函数
{
尺寸c;
无符号*p;
copy_idx_func(const size_t_c,unsigned*_p):c(_c),p(_p){};
__主机设备__
无符号运算符()(无符号idx){
无符号myrow=idx/c;
无符号newrow=p[myrow]-1;
无符号mycl=idx%c;
返回newrow*c+mycl;
}
};
int main(){
常数mytype mat[]={1,1,1,1,2,2,2,3,3,3,3,4,4,4,5,5,5};
const mytype vec[]={1,2,3,4,5};
常量无符号per[]={5,3,1,2,4};
const size_t msize=sizeof(mat)/sizeof(mytype);
const size\u t vsize=sizeof(vec)/sizeof(mytype);
const size\u t psize=sizeof(per)/sizeof(未签名);
const size\u t cols=msize/vsize;
//const size\u t rows=vsize;
断言(msize%vsize==0);
断言(vsize==psize);
推力:设备矢量d_m(mat,mat+msize);
推力:设备向量d_v(vec,vec+vsize);
推力:装置矢量d_p(per,per+psize);
推力:设备向量d_rm(msize);
推力:装置矢量d_rv(vsize);

std::能否请您添加一个小但完整的示例,说明您想要实现的目标?什么是输入矩阵,您想要的输出是什么?排列后您想要做什么?由于对全局内存的读/写非常昂贵,如果您只是移动数据,那么很难从CUDA中获益。如果矩阵非常大(1000列)您可能会得到一些改进,但不会给人留下深刻印象。如果您使用的是推力,我建议您根本不要排列或排序矩阵。使用