<span style="color:#ff0000;">准备条件:首先确认电脑具有nvidia的显卡,如果没有的话,是不能进行cuda编程的</span>
要想在matlab下运行cuda,毋庸置疑,我们至少需要matlab,cuda,visual studio三款软件,在这里,笔者使用的是matlab2014b,cuda6.5和visual studio 2013的版本,至于版本要求,一般是matlab的版本要大于visual studio的版本,而cuda的版本要通过nvidia的官网查看是否能兼容vs的版本。
安装顺序:笔者推荐为matlab—visual studio—cuda,一般把cuda放在vs后安装,是因为如果cuda在vs之前安装,可能会导致vs安装之后新建项目里不会出现nvidia的项目。
安装注意:把360等杀毒软件关闭,以防止会阻挡进程,另外,一定要安装完整版的,特别是visual studio,一定要安装带有相关环境的,否则在matlab中用到mex时,会提示找不到相关的环境。
安装细节:
1,安装matlab2014b,至于激活方法等网上均有例程;
2,安装visual studio 2013,傻瓜式安装;
3,从nvidia官网上下载cuda6.5,6.5版本已经集成了cuda中所有的组件,因此只要选择好系统的版本等,直接下载就好了,下载地址为:https://developer.nvidia.com/cuda-downloads,具体安装方法和图示可以参考:http://www.360doc.com/content/14/1012/09/19076531_416241911.shtml
4,cuda6.5安装完成后(建议直接用默认目录),要设置相关的环境变量,右键我的电脑,属性——高级系统系统设置—高级—环境变量,安装完毕后,可以看到系统中多了CUDA_PATH和CUDA_PATH_V6_0两个环境变量,接下来,还要在系统中添加以下几个环境变量(注意复制粘贴的时候一定不要粘上后面的空格,我为了它纠结了一天):
CUDA_SDK_PATH = C:\ProgramData\NVIDIA Corporation\CUDA Samples\v6.5
CUDA_LIB_PATH = %CUDA_PATH%\lib\x64
CUDA_BIN_PATH = %CUDA_PATH%\bin
CUDA_SDK_BIN_PATH = %CUDA_SDK_PATH%\bin\x64
CUDA_SDK_LIB_PATH = %CUDA_SDK_PATH%\common\lib\x64
然后,在系统变量 path 的末尾添加: ;%CUDA_LIB_PATH%;%CUDA_BIN_PATH%;%CUDA_SDK_LIB_PATH%;%CUDA_SDK_BIN_PATH%;
重启计算机,这时cuda就差不多配好了。
5,运行测试代码,我在安装cuda的时候,一直使用的默认目录,打开C:\ProgramData\NVIDIA Corporation\CUDA Samples\v6.5\1_Utilities\deviceQuery,打开deviceQuery_vs2013,测验一下,如果运行成功,说明配置好了。接着打开一个新建的项目,直接选择nvidia的cuda6.5,里面有一个示范代码,改变一下项目的属性设置(这里和你电脑nvidia显卡的型号有关),
6,这样的vs和cuda的接口就验证成功了,接着我们开始进行matlab和vs的接口。参考:http://blog.csdn.net/hongqiang200/article/details/6273406
(1) 编写基于CUDA的.cu程序;
(2) 下载nvmex_tool压缩包(http://www.cs.ucf.edu/~janaka/gpu/using_nvmex.htm),解压缩;
(3) 将解压缩后的nvmex.pl文件复制至Matlab安装文件夹下的Bin文件夹内,X:/Matlab/R2009a/Bin/;
(4) 将压缩后的nvmex_tool文件夹内的nvmex.m文件、nvmex_helper.m文件以及nvmexopts.bat文件放至你的.cu文件,使他们位于同一文件夹内。
(5) 将该文件夹设为Matlab当前工作目录
(6)在matlab要运行的.m文件里,前面输入:system('nvcc -c conv2d.cu -ccbin "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin"');
(7)接着在下面输入:
mex conv2dCuda.cpp conv2d.obj -lcudart -L"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v6.5\lib\x64"
总运行代码如下:(以卷积为例)
matlab的.m文件:
%makeInMatlab
clc, clear
system('nvcc -c conv2d.cu -ccbin "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin"');
fprintf('compile conv2d.cu, succeed!\n');
mex conv2dCuda.cpp conv2d.obj -lcudart -L"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v6.5\lib\x64"
fprintf('mex conv2dCuda.cpp, succeed!\n');
fprintf('testing...\n');
%%
N = int32(10000);
n_V = int32(32);
n_W = int32(8);
K = int32(16);
n_H = n_V - n_W + 1;
V = single(rand(N, n_V * n_V));
W = single(rand(K, n_W * n_W));
tic,
H = conv2dCuda(V', W', n_V, n_W, N, K);
H = H';
%H = reshape(H,[n_H*n_H, N])';
gpu_time = toc;
fprintf('GPU computing time: %f seconds\n', gpu_time);
tic,
H_cpu = single(zeros(N, n_H * n_H));
for i = 1:N,
Vi = reshape(V(i,:),[n_V, n_V]);
Hi = zeros(n_H, n_H);
for k = 1:K,
Wk = reshape(W(k,:),[n_W,n_W]);
Hi = Hi + conv2(Vi, Wk, 'valid');
%Hi = Hi + filter2(Wk, Vi, 'valid');
end
H_cpu(i,:) = Hi(:)';
end
cpu_time = toc;
fprintf('CPU computing time: %f seconds\n', cpu_time);
speed_up = cpu_time/gpu_time;
fprintf('%f times speed up!\n',speed_up);
err = abs(H-H_cpu);
epsilon = 3*1e-4;
err(err<epsilon) = 0;
fprintf('err = %.4f\n',sum(err(:)));
%%
% H(:,1:10)
% H_cpu(:,1:10)
cuda核里的.cu文件:
#include "conv2d.h"
#include <stdio.h>
#include "D:\Program Files\MATLAB\R2014b\extern\include\tmwtypes.h"
#include "D:\Program Files\MATLAB\R2014b\extern\include\mex.h"
#define TILE_WIDTH 16
__global__ void conv2d_valid_OnDevice(float *V, float *W, float *H, int n_V, int n_W, int n_H, int N, int n_F)
{
float temp;
int i,j,k,l;
for(i=0; i < n_V/TILE_WIDTH; i++){
for(j = 0; j < n_V/TILE_WIDTH; j++){
int idH_m = threadIdx.x + i*TILE_WIDTH;
int idH_n = threadIdx.y + j*TILE_WIDTH;
if(idH_m >= n_H || idH_n >= n_H)
continue;
temp = 0;
for(k=0; k<n_W; k++){
for(l=0; l<n_W; l++){
float v = V[blockIdx.x*n_V*n_V + (idH_m + k)*n_V + (idH_n + l)];
float w = W[blockIdx.y*n_W*n_W + (n_W-1-k)*n_W + (n_W-1-l)]; //因为是卷积,所以将w反排
temp += v*w;
}
}
atomicAdd(&H[blockIdx.x*n_H*n_H + idH_m*n_H + idH_n], temp);
}
}
}
void conv2d_valid(float *V, float *W, float *H, int n_V, int n_W, int n_H, int N, int n_F)
{
float *d_V, *d_W, *d_H;
size_t size_V = N * n_V * n_V * sizeof(float);
size_t size_W = n_F * n_W * n_W * sizeof(float);
size_t size_H = N * n_H * n_H * sizeof(float);
dim3 dimBlock(TILE_WIDTH,TILE_WIDTH);
dim3 dimGrid(N, n_F);
cudaMalloc((void**)&d_V, size_V);
cudaMalloc((void**)&d_W, size_W);
cudaMalloc((void**)&d_H, size_H);
cudaMemcpy(d_V, V, size_V, cudaMemcpyHostToDevice);
cudaMemcpy(d_W, W, size_W, cudaMemcpyHostToDevice);
cudaMemcpy(d_H, H, size_H, cudaMemcpyHostToDevice);
conv2d_valid_OnDevice<<<dimGrid, dimBlock>>>(d_V, d_W, d_H, n_V, n_W, n_H, N, n_F);
cudaMemcpy(H, d_H, size_H, cudaMemcpyDeviceToHost);
cudaFree(d_V);
cudaFree(d_W);
cudaFree(d_H);
}
void printArray(float *A, int numRows, int numCols)
{
int i,j;
for(i=0; i<numRows; i++){
for(j=0; j<numCols; j++){
printf("%.2f ",A[i*numCols+j]);
}
printf("\n");
}
}
// reset matrix:
// e.g. A=[1 2 3 4 5; 6 7 8 9 10]; => A=[1 3 5 7 9; 2 4 6 8 10];
void resetMatrix_byRow(float *A, int numRows, int numCols)
{
float *B = (float*)malloc(sizeof(float)*numRows*numCols);
int i,j;
for(i=0; i<numRows; i++){
for(j=0; j<numCols; j++){
B[i*numCols + j] = A[i*numCols + j];
}
}
int m_A,n_A,m_B,n_B;
for(i=0; i<numRows*numCols; i++){
m_A = i/numCols;
n_A = i%numCols;
m_B = i%numRows;
n_B = i/numRows;
A[m_A*numCols+n_A] = B[m_B*numCols+n_B];
}
free(B);
}
另外新建一个.cpp和.h文件,用来提供matlab数据和c/c++数据的转换分别为:
#ifndef __CONV2D_H__
#define __CONV2D_H__
extern void resetMatrix_byCol(float *A, int numRows, int numCols);
extern void resetMatrix_byRow(float *A, int numRows, int numCols);
extern void printArray(float *A, int numRows, int numCols);
extern void conv2d_valid(float *V, float *W, float *H, int n_V, int n_W, int n_H, int N, int n_F);
//extern void conv2d_full(float *V, float *W, float *H, int n_V, int n_W, int n_H);
#endif
#include "D:\Program Files\MATLAB\R2014b\extern\include\mex.h"
#include "conv2d.h"
#include <math.h>
// nlhs: 输出变量的个数(lefthand side,调用语句的左手面)
// plhs:输出的mxArray矩阵的头指针
// nrhs: 输入变量个数(righthand side,调用语句的右手面)
// prhs:输入的mxArray矩阵的头指针
// 如果有两个输入变量,那么prhs[0]指向第一个变量
// prhs[1]指向第二个变量
// Matlab的array使用mxArray类型来表示。
// plhs和hrhs都是指向mxArray类型的指针数组
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[])
{
// 判断输入参数个数是否满足条件
// if (nrhs != 2)
// mexErrMsgTxt("Invaidnumber of input arguments");
//
// if (nlhs != 1)
// mexErrMsgTxt("Invalidnumber of outputs");
//
// // 判断输入参数的类型是否满足条件
// if (!mxIsSingle(prhs[0])&& !mxIsSingle(prhs[1]))
// mexErrMsgTxt("inputvector data type must be single");
// mxGetData 获取数据阵列中的数据
float *V = (float*)mxGetData(prhs[0]);
float *W = (float*)mxGetData(prhs[1]);
int *p_nV = (int*)mxGetData(prhs[2]);
int *p_nW = (int*)mxGetData(prhs[3]);
int *p_N = (int*)mxGetData(prhs[4]);
int *p_K = (int*)mxGetData(prhs[5]);
int n_V = *p_nV;
int n_W = *p_nW;
int N = *p_N;
int K = *p_K;
int n_H = n_V - n_W + 1;
//printf("n_V = %d, n_W = %d, n_H = %d\n",n_V,n_W,n_H);
// 生成输出参数的mxArray结构体
int numRowsH = N; //这是C中矩阵的行,正好对应matlab矩阵的列!!!
int numColsH = n_H * n_H;
plhs[0] = mxCreateNumericMatrix(numColsH, numRowsH, mxSINGLE_CLASS, mxREAL);
// 获取输出参数的指针
float *H = (float*)mxGetData(plhs[0]);
// 初始化
int i,j;
for(i = 0; i<numRowsH; i++){
for(j=0; j<numColsH; j++){
H[i*numColsH + j] = 0;
}
}
// 调用子程序
conv2d_valid(V, W, H, n_V, n_W, n_H, N, K);
// 重排后使得存储方式与matlab一致
//resetMatrix_byRow(H, numRowsH, numColsH);
}
显示结果如下:
MEX completed successfully.
mex conv2dCuda.cpp, succeed!
testing...
GPU computing time: 2.242399 seconds
CPU computing time: 20.623921 seconds
9.197258 times speed up!
err = 0.0000
http://www.360doc.com/content/14/1012/09/19076531_416241911.shtml
http://blog.csdn.net/hongqiang200/article/details/6273406