C++ CUDA矩阵的行/列操作
我对CUDA编程比较陌生。我已经理解了编程模型,并且已经编写了一些基本内核。我知道如何将内核应用于矩阵的每个元素(存储为1D数组),但现在我试图弄清楚如何将相同的操作应用于输入矩阵的相同行/列 假设我有一个C++ CUDA矩阵的行/列操作,c++,c,matrix,cuda,C++,C,Matrix,Cuda,我对CUDA编程比较陌生。我已经理解了编程模型,并且已经编写了一些基本内核。我知道如何将内核应用于矩阵的每个元素(存储为1D数组),但现在我试图弄清楚如何将相同的操作应用于输入矩阵的相同行/列 假设我有一个MxN矩阵和一个长度N的向量。我想求和(但可以是任何其他数学运算)矩阵每一行的向量。 该操作的序列号为: for(int c=0;c
MxN
矩阵和一个长度N
的向量。我想求和(但可以是任何其他数学运算)矩阵每一行的向量。
该操作的序列号为:
for(int c=0;c
现在,执行此操作的CUDA代码应该非常简单:我应该生成与元素一样多的CUDA线程,并应用此内核:
\uuuuu全局\uuuuuu无效内核(常量无符号整数大小、浮点*矩阵、常量浮点*向量)
{
//获取线程的当前元素索引
unsigned int idx=blockIdx.x*blockDim.x+threadIdx.x;
if(idx
它运行,但结果不正确。实际上,如果我在内核完成工作后转置矩阵,这是正确的。不幸的是,我不知道为什么它是这样工作的。你能帮我解决这个问题吗?提前谢谢
编辑#1
我使用以下方法启动内核:
int block_size=64;
整数网格大小=(M*N+块大小-1)/块大小;
核(M*N,矩阵,向量);
编辑#2
我按照@RobertCrovella的建议修复了CPU代码,从而解决了这个问题:
M[r*列+c]+=V[c];
它应该与的外部
相匹配,即在列上。问题中显示的内核可以在不作修改的情况下用于将向量求和到矩阵的每一行(假设为c型行主存储),但要受到某些限制。示威游行正在进行中
该方法的主要限制是,可处理的最大向量长度和矩阵宽度等于每个块的最大线程数,当前CUDA 7支持的GPU上的最大线程数为1024
我们只需稍微修改向量索引,并将行宽度(列数)作为参数传递给矩阵,就可以消除这一限制。通过这种修改,我们应该能够处理任意大小的矩阵(和向量)
编辑:根据讨论/评论,OP想知道如何处理行主存储或列主存储。以下示例使用模板内核选择行主存储或列主存储,还显示了一种可能的CUBLAS方法,用于使用以下命令向每个矩阵行操作添加向量:
$cat t712.cu
#包括
#包括
#定义第20行
#定义COLS 10
#定义nTPB 64
#定义行\u主0
#定义COL_专业1
模板
__全局无效向量矩阵行加(常数无符号整数高度,常数无符号整数宽度,T*矩阵,常数T*向量)
{
//获取线程的当前元素索引
unsigned int idx=blockIdx.x*blockDim.x+threadIdx.x;
如果(idx<高度*宽度)
{
//将当前元素与
如果(选择==行\主)
矩阵[idx]+=向量[idx%宽度];
其他//上校大校
矩阵[idx]+=向量[idx/高度];
}
}
int main(){
浮动*h_-mat、*d_-mat、*h_-vec、*d_-vec;
常量unsigned int msz=ROWS*COLS*sizeof(float);
常量unsigned int vsz=COLS*sizeof(float);
h_mat=(浮动*)malloc(msz);
h_vec=(浮点*)malloc(vsz);
库达马洛克(密西西比州迪奥马特市);
库达马洛克(和杜维茨,vsz);
对于(int i=0;iRobert Crovella已经回答了这个问题,并提供了使用显式CUDA内核和cuBLAS的示例
我发现,为了将来的参考,还可以展示一个关于如何使用CUDA推力执行行或列操作的示例。我特别关注两个问题:
将列向量求和到所有矩阵列
将行向量求和到所有矩阵行
stress::transform
的通用性使我们能够将下面的示例推广到除和(例如乘法、除法、减法等)之外的元素操作
#包括
#包括
#包括
#包括
#包括
#包括
使用命名空间推力::占位符;
/*************************************/
/*将线性索引转换为行索引*/
/*************************************/
模板
结构线性索引到行索引:公共推力::一元函数{
T Ncols;//--列数
__主机设备线性索引到行索引(T Ncols):Ncols(Ncols){
__主机设备操作符()(ti){return i/Ncols;}
};
/********/
/*主要*/
/********/
int main()
{
/**************************/
/*设置问题*/
/**************************/
常量int Nrows=10;//--行数
const int Ncols=3;//--列数
//---0到100之间的随机均匀整数分布
推力:默认随机发动机转速;
推力:均匀分布区1(01100);
//---1和4之间的随机均匀整数分布
推力:均匀分布区2(1,4);
//---矩阵分配和初始化
推力:设备矢量d矩阵(Nrows*Ncols);
对于(size_t i=0;i$ cat t712.cu
#include <iostream>
#include <cublas_v2.h>
#define ROWS 20
#define COLS 10
#define nTPB 64
#define ROW_MAJOR 0
#define COL_MAJOR 1
template <int select, typename T>
__global__ void vec_mat_row_add(const unsigned int height, const unsigned int width, T* matrix, const T* vector)
{
// get the current element index for the thread
unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < height*width)
{
// sum the current element with the
if (select == ROW_MAJOR)
matrix[idx] += vector[idx%width];
else // COL_MAJOR
matrix[idx] += vector[idx/height];
}
}
int main(){
float *h_mat, *d_mat, *h_vec, *d_vec;
const unsigned int msz = ROWS*COLS*sizeof(float);
const unsigned int vsz = COLS*sizeof(float);
h_mat = (float *)malloc(msz);
h_vec = (float *)malloc(vsz);
cudaMalloc(&d_mat, msz);
cudaMalloc(&d_vec, vsz);
for (int i=0; i<COLS; i++) h_vec[i] = i; // set vector to 0,1,2, ...
cudaMemcpy(d_vec, h_vec, vsz, cudaMemcpyHostToDevice);
// test row-major case
cudaMemset(d_mat, 0, msz); // set matrix to zero
vec_mat_row_add<ROW_MAJOR><<<(ROWS*COLS + nTPB -1)/nTPB, nTPB>>>(ROWS, COLS, d_mat, d_vec);
cudaMemcpy(h_mat, d_mat, msz, cudaMemcpyDeviceToHost);
std::cout << "Row-major result: " << std::endl;
for (int i = 0; i < ROWS; i++){
for (int j = 0; j < COLS; j++) std::cout << h_mat[i*COLS+j] << " ";
std::cout << std::endl;}
// test column-major case
cudaMemset(d_mat, 0, msz); // set matrix to zero
vec_mat_row_add<COL_MAJOR><<<(ROWS*COLS + nTPB -1)/nTPB, nTPB>>>(ROWS, COLS, d_mat, d_vec);
cudaMemcpy(h_mat, d_mat, msz, cudaMemcpyDeviceToHost);
std::cout << "Column-major result: " << std::endl;
for (int i = 0; i < ROWS; i++){
for (int j = 0; j < COLS; j++) std::cout << h_mat[j*ROWS+i] << " ";
std::cout << std::endl;}
// test CUBLAS, doing matrix-vector add using <T>ger
cudaMemset(d_mat, 0, msz); // set matrix to zero
float *d_ones, *h_ones;
h_ones = (float *)malloc(ROWS*sizeof(float));
for (int i =0; i<ROWS; i++) h_ones[i] = 1.0f;
cudaMalloc(&d_ones, ROWS*sizeof(float));
cudaMemcpy(d_ones, h_ones, ROWS*sizeof(float), cudaMemcpyHostToDevice);
cublasHandle_t ch;
cublasCreate(&ch);
float alpha = 1.0f;
cublasStatus_t stat = cublasSger(ch, ROWS, COLS, &alpha, d_ones, 1, d_vec, 1, d_mat, ROWS);
if (stat != CUBLAS_STATUS_SUCCESS) {std::cout << "CUBLAS error: " << (int)stat << std::endl; return 1;}
cudaMemcpy(h_mat, d_mat, msz, cudaMemcpyDeviceToHost);
std::cout << "CUBLAS Column-major result: " << std::endl;
for (int i = 0; i < ROWS; i++){
for (int j = 0; j < COLS; j++) std::cout << h_mat[j*ROWS+i] << " ";
std::cout << std::endl;}
return 0;
}
$ nvcc -o t712 t712.cu -lcublas
$ ./t712
Row-major result:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
Column-major result:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
CUBLAS Column-major result:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
$
#include <thrust/device_vector.h>
#include <thrust/reduce.h>
#include <thrust/random.h>
#include <thrust/sort.h>
#include <thrust/unique.h>
#include <thrust/equal.h>
using namespace thrust::placeholders;
/*************************************/
/* CONVERT LINEAR INDEX TO ROW INDEX */
/*************************************/
template <typename T>
struct linear_index_to_row_index : public thrust::unary_function<T,T> {
T Ncols; // --- Number of columns
__host__ __device__ linear_index_to_row_index(T Ncols) : Ncols(Ncols) {}
__host__ __device__ T operator()(T i) { return i / Ncols; }
};
/********/
/* MAIN */
/********/
int main()
{
/**************************/
/* SETTING UP THE PROBLEM */
/**************************/
const int Nrows = 10; // --- Number of rows
const int Ncols = 3; // --- Number of columns
// --- Random uniform integer distribution between 0 and 100
thrust::default_random_engine rng;
thrust::uniform_int_distribution<int> dist1(0, 100);
// --- Random uniform integer distribution between 1 and 4
thrust::uniform_int_distribution<int> dist2(1, 4);
// --- Matrix allocation and initialization
thrust::device_vector<float> d_matrix(Nrows * Ncols);
for (size_t i = 0; i < d_matrix.size(); i++) d_matrix[i] = (float)dist1(rng);
// --- Column vector allocation and initialization
thrust::device_vector<float> d_column(Nrows);
for (size_t i = 0; i < d_column.size(); i++) d_column[i] = (float)dist2(rng);
// --- Row vector allocation and initialization
thrust::device_vector<float> d_row(Ncols);
for (size_t i = 0; i < d_row.size(); i++) d_row[i] = (float)dist2(rng);
printf("\n\nOriginal matrix\n");
for(int i = 0; i < Nrows; i++) {
std::cout << "[ ";
for(int j = 0; j < Ncols; j++)
std::cout << d_matrix[i * Ncols + j] << " ";
std::cout << "]\n";
}
printf("\n\nColumn vector\n");
for(int i = 0; i < Nrows; i++) std::cout << d_column[i] << "\n";
printf("\n\nRow vector\n");
for(int i = 0; i < Ncols; i++) std::cout << d_row[i] << " ";
/*******************************************************/
/* ADDING THE SAME COLUMN VECTOR TO ALL MATRIX COLUMNS */
/*******************************************************/
thrust::device_vector<float> d_matrix2(d_matrix);
thrust::transform(d_matrix.begin(), d_matrix.end(),
thrust::make_permutation_iterator(
d_column.begin(),
thrust::make_transform_iterator(thrust::make_counting_iterator(0), linear_index_to_row_index<int>(Ncols))),
d_matrix2.begin(),
thrust::plus<float>());
printf("\n\nColumn + Matrix -> Result matrix\n");
for(int i = 0; i < Nrows; i++) {
std::cout << "[ ";
for(int j = 0; j < Ncols; j++)
std::cout << d_matrix2[i * Ncols + j] << " ";
std::cout << "]\n";
}
/*************************************************/
/* ADDING THE SAME ROW VECTOR TO ALL MATRIX ROWS */
/*************************************************/
thrust::device_vector<float> d_matrix3(d_matrix);
thrust::transform(thrust::make_permutation_iterator(
d_matrix.begin(),
thrust::make_transform_iterator(thrust::make_counting_iterator(0),(_1 % Nrows) * Ncols + _1 / Nrows)),
thrust::make_permutation_iterator(
d_matrix.begin(),
thrust::make_transform_iterator(thrust::make_counting_iterator(0),(_1 % Nrows) * Ncols + _1 / Nrows)) + Nrows * Ncols,
thrust::make_permutation_iterator(
d_row.begin(),
thrust::make_transform_iterator(thrust::make_counting_iterator(0), linear_index_to_row_index<int>(Nrows))),
thrust::make_permutation_iterator(
d_matrix3.begin(),
thrust::make_transform_iterator(thrust::make_counting_iterator(0),(_1 % Nrows) * Ncols + _1 / Nrows)),
thrust::plus<float>());
printf("\n\nRow + Matrix -> Result matrix\n");
for(int i = 0; i < Nrows; i++) {
std::cout << "[ ";
for(int j = 0; j < Ncols; j++)
std::cout << d_matrix3[i * Ncols + j] << " ";
std::cout << "]\n";
}
return 0;
}