CUDA/CUBLAS矩阵矢量乘法
CUDA/CUBLAS Matrix-Vector Multiplication
我之前发布了一个关于CUDA中矩阵向量乘法和编写自己的内核的问题。在完成这项工作后,我决定按照一些用户(感谢@Robert Crovella)在SO上的建议,使用CUBLAS来实现我的问题,希望获得更高的性能(我的项目是性能驱动的)。
只是为了澄清:我想用1xN向量乘以NxN矩阵。
我已经看了下面粘贴的代码好几天了,我不明白为什么乘法会给我一个错误的结果。我担心我使用<vector>数组(这是使用这些数据类型的更大系统的一部分)。我并不打算使用这个线程作为调试工具,但我认为这对其他试图实现这一目标的用户也有帮助,因为我还没有在互联网上找到关于我的特定问题的特别全面的来源(以及cublas v2 API)。提前感谢!
#include <cuda.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <cublas_v2.h>
#include <time.h>
//#include "timenow.cu"
// error check macros
#define cudaCheckErrors(msg)
do {
cudaError_t __err = cudaGetLastError();
if (__err != cudaSuccess) {
fprintf(stderr, "Fatal error: %s (%s at %s:%d)n",
msg, cudaGetErrorString(__err),
__FILE__, __LINE__);
fprintf(stderr, "*** FAILED - ABORTINGn");
exit(1);
}
} while (0)
// for CUBLAS V2 API
#define cublasCheckErrors(fn)
do {
cublasStatus_t __err = fn;
if (__err != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "Fatal cublas error: %d (at %s:%d)n",
(int)(__err),
__FILE__, __LINE__);
fprintf(stderr, "*** FAILED - ABORTINGn");
exit(1);
}
} while (0)
// random data filler
void fillvector(float *data, int N){
for(int i=0; i<N; i++){
data[i] = float(rand() % 10);
}
}
//printer
void printer(bool printOut, float *data, int N){
if(printOut == true){
for(int i=0; i<N; i++){
printf("%2.1f ", data[i]);
}
printf("n");
}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
int main(){
bool printOut = true;
int N;
std::cout << "Enter N: " ;
std::cin >> N;
std::vector<float> x0;
x0.resize(N);
std::vector<float> p;
p.resize(N*N);
// matrix A
std::vector<float> A[N];
for(int i=0;i<N;i++){
A[i].resize(N);
fillvector(A[i].data(), N);
printer(printOut, A[i].data(), N);
}
printf("n");
fillvector(x0.data(), N);
printer(printOut, x0.data(), N);
printf("nStarting CUDA computation...");
///double startTime = timenow();
// device pointers
float *d_A, *d_p, *d_b, *d_x0, *d_v, *d_temp;
cudaMalloc((void**)&d_A, N*N*sizeof(float));
cudaMalloc((void**)&d_temp, N*sizeof(float));
cudaMalloc((void**)&d_x0, N*sizeof(float));
cudaCheckErrors("cuda malloc fail");
// might need to flatten A...
cublasSetVector(N, sizeof(float), &x0, 1, d_x0, 1);
//daMemcpy(d_x0, &x0, N*sizeof(float), cudaMemcpyHostToDevice);
cublasSetMatrix(N, N, sizeof(float), &A, N, d_A, N);
cudaCheckErrors("cuda memcpy of A or x0 fail");
float *temp;
temp = (float *)malloc(N*sizeof(temp));
cublasHandle_t handle;
cublasCheckErrors(cublasCreate(&handle));
float alpha = 1.0f;
float beta = 0.0f;
cublasCheckErrors(cublasSgemv(handle, CUBLAS_OP_N, N, N, &alpha, d_A, N, d_x0, 1, &beta, d_temp, 1));
cublasGetVector(N, sizeof(float), &temp, 1, d_temp, 1);
//cudaMemcpy(temp, d_temp, N*sizeof(float), cudaMemcpyDeviceToHost);
cudaCheckErrors("returning to host failed");
printf("n");
printer(printOut, temp, N);
/*alpha = -1.0;
cublasSaxpy(handle, N, &alpha, d_temp, 1, d_v, 1);
cublasGetVector(N, sizeof(float) * N, d_v, 1, &v, 1);
printf("n");
for(int i=0; i<N; i++){
printf("%2.1f ",v[i]);
}*/
printf("nFinished CUDA computations...");
//double endTime = timenow();
//double timeDiff = endTime - startTime;
//printf("nRuntime: %2.3f seconds n", timeDiff);
cudaFree(d_temp);
cudaFree(d_A);
cudaFree(d_p);
cudaFree(d_x0);
return 0;
}
-
我们不会这样引用向量的第一个元素:
cublasSetVector(N, sizeof(float), &x0, 1, d_x0,
相反,你应该这样做:
cublasSetVector(N, sizeof(float), &(x0[0]), 1, d_x0, 1);
同样,对于引用A
:的SetMatrix
调用
cublasSetMatrix(N, N, sizeof(float), &(A[0]), N, d_A, N);
您的
GetVector
呼叫有2个错误:cublasGetVector(N, sizeof(float), &temp, 1, d_temp, 1);
您的temp
和d_temp
参数颠倒了(您正在从设备复制到主机),并且不应该使用temp
的地址:它已经是一个指针了。这样做:
cublasGetVector(N, sizeof(float), d_temp, 1, temp, 1);
您没有对所有的cublas调用进行正确的错误检查,例如get/set矩阵/向量调用。使用与其他cublas调用相同的方法。
您正在将
A
创建为向量数组。这对cublasSetMatrix
不起作用。相反,我们需要创建A
作为一个平面向量,其大小(N*N)足以存储整个矩阵。最后,cublas期望它使用的矩阵以列主顺序存储。如果按行主顺序传递C样式数组,则应在
cublasSgemv
:中使用该矩阵的转置cublasCheckErrors(cublasSgemv(handle, CUBLAS_OP_T, N, N, &alpha, d_A, N, d_x0, 1, &beta, d_temp, 1));
以下代码修复了这些不同的问题:
$ cat t235.cu
#include <cuda.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <cublas_v2.h>
#include <time.h>
//#include "timenow.cu"
// error check macros
#define cudaCheckErrors(msg)
do {
cudaError_t __err = cudaGetLastError();
if (__err != cudaSuccess) {
fprintf(stderr, "Fatal error: %s (%s at %s:%d)n",
msg, cudaGetErrorString(__err),
__FILE__, __LINE__);
fprintf(stderr, "*** FAILED - ABORTINGn");
exit(1);
}
} while (0)
// for CUBLAS V2 API
#define cublasCheckErrors(fn)
do {
cublasStatus_t __err = fn;
if (__err != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "Fatal cublas error: %d (at %s:%d)n",
(int)(__err),
__FILE__, __LINE__);
fprintf(stderr, "*** FAILED - ABORTINGn");
exit(1);
}
} while (0)
// random data filler
void fillvector(float *data, int N){
for(int i=0; i<N; i++){
data[i] = float(rand() % 10);
}
}
//printer
void printer(bool printOut, float *data, int N){
if(printOut == true){
for(int i=0; i<N; i++){
printf("%2.1f ", data[i]);
}
printf("n");
}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
int main(){
bool printOut = true;
int N;
std::cout << "Enter N: " ;
std::cin >> N;
std::vector<float> x0;
x0.resize(N);
std::vector<float> p;
p.resize(N*N);
// matrix A
std::vector<float> A(N*N);
fillvector(A.data(), N*N);
for (int i=0; i< N; i++){
printer(printOut, &(A[(i*N)]), N);
printf("n");}
fillvector(x0.data(), N);
printer(printOut, x0.data(), N);
printf("nStarting CUDA computation...");
///double startTime = timenow();
// device pointers
float *d_A, *d_x0, *d_temp;
cudaMalloc((void**)&d_A, N*N*sizeof(float));
cudaMalloc((void**)&d_temp, N*sizeof(float));
cudaMalloc((void**)&d_x0, N*sizeof(float));
cudaCheckErrors("cuda malloc fail");
// might need to flatten A...
cublasCheckErrors(cublasSetVector(N, sizeof(float), &(x0[0]), 1, d_x0, 1));
//daMemcpy(d_x0, &x0, N*sizeof(float), cudaMemcpyHostToDevice);
cublasCheckErrors(cublasSetMatrix(N, N, sizeof(float), &(A[0]), N, d_A, N));
//cudaCheckErrors("cuda memcpy of A or x0 fail");
float *temp;
temp = (float *)malloc(N*sizeof(temp));
cublasHandle_t handle;
cublasCheckErrors(cublasCreate(&handle));
float alpha = 1.0f;
float beta = 0.0f;
cublasCheckErrors(cublasSgemv(handle, CUBLAS_OP_T, N, N, &alpha, d_A, N, d_x0, 1, &beta, d_temp, 1));
cublasCheckErrors(cublasGetVector(N, sizeof(float), d_temp, 1, temp, 1));
//cudaMemcpy(temp, d_temp, N*sizeof(float), cudaMemcpyDeviceToHost);
//cudaCheckErrors("returning to host failed");
printf("n");
printer(printOut, temp, N);
/*alpha = -1.0;
cublasSaxpy(handle, N, &alpha, d_temp, 1, d_v, 1);
cublasGetVector(N, sizeof(float) * N, d_v, 1, &v, 1);
printf("n");
for(int i=0; i<N; i++){
printf("%2.1f ",v[i]);
}*/
printf("nFinished CUDA computations...n");
//double endTime = timenow();
//double timeDiff = endTime - startTime;
//printf("nRuntime: %2.3f seconds n", timeDiff);
cudaFree(d_temp);
cudaFree(d_A);
//cudaFree(d_p);
cudaFree(d_x0);
return 0;
}
$ nvcc -arch=sm_20 -O3 -o t235 t235.cu -lcublas
$ ./t235
Enter N: 5
3.0 6.0 7.0 5.0 3.0
5.0 6.0 2.0 9.0 1.0
2.0 7.0 0.0 9.0 3.0
6.0 0.0 6.0 2.0 6.0
1.0 8.0 7.0 9.0 2.0
0.0 2.0 3.0 7.0 5.0
Starting CUDA computation...
83.0 86.0 92.0 62.0 110.0
Finished CUDA computations...
$
相关文章:
- 编译时未启用intel oneApi CUDA支持
- 在cuda线程之间共享大量常量数据
- 为什么即使使用-cudart-static进行编译,库用户仍然需要链接到cuda运行时
- Cuda C++:设备上的Malloc类,并用来自主机的数据填充它
- CUDA内核和数学函数的显式命名空间
- CUDA:统一内存和指针地址的更改
- 调试 CUDA MMU 故障
- 使用 CUDA 和纹理进行图像减法
- 将 2D 推力::d evice_vector 复矩阵传递给 CUDA 内核函数
- 编译 CUDA 与数学函数的叮当
- 为什么 CUDA 不会导致C++代码加速?
- 如何防止 CUDA-GDB 中的<优化输出>值
- 通过Python Distutils(用于Python C扩展)使用可重定位的设备代码编译CUDA代码
- CUDA三角函数中的数学保证
- 是否可以从 CUDA 10.1 内核调用 cuBLAS 或 cuBLASLt 函数?
- CUDA 未知错误后 cuBLAS 调用
- 使用特定输入的cuda/cublas简单内核中的数值错误
- CUDA内核2x2 ZgemmBatched:比CuBLAS快5倍.它能跑得更快吗
- CUDA/CUBLAS:访问数组中的元素
- CUDA/CUBLAS矩阵矢量乘法