我想制作一个简单的平铺卷积码。它来自Coursera的讲座:异构并行编程。本讲座提供了一个简单的卷积代码和tiling方法,但代码并不完整。因此,我填写代码中的空白,下面是结果。
此代码的目标是计算卷积。
输入尺寸:(24×24),
内核大小:(9乘9),
输出维度:(16乘16)。
另外,在主要内容中,我将计算时间检查代码与CPU版本进行比较。
问题是,每当我运行此代码时,结果都不同。我试着找了几天这个问题,但每次试验都没有用。我也在互联网blog中找到了类似的代码,但它与我的问题相同。我不知道为什么结果每次都不同。有人说这是由于比赛条件,但我找不到任何相关信息。
以下是卷积的示例结果(16乘16大小)。
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 0 0 0 0 0 0
81 81 81 81 81 81 81 81 81 81 0 0 0 0 0 0
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
0 0 0 0 0 0 0 0 0 0 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81
81 81 81 81 81 81 81 81 81 81 0 0 0 0 0 0
81 81 81 81 81 81 81 81 81 81 0 0 0 0 0 0
81 81 81 81 81 81 81 81 81 81 0 0 0 0 0 0
81 81 81 81 81 81 81 81 81 81 0 0 0 0 0 0
81 81 81 81 81 81 81 81 81 81 0 0 0 0 0 0
81 81 81 81 81 81 81 81 81 81 0 0 0 0 0 0
我的设备是CUDA Driver = CUDART,CUDA Driver Version = 7.5,CUDA Runtime Version = 7.5,NumDevs = 1,Device0 = GeForce GT 630。 我使用的是Ubuntu 14.04。
提前致谢!
#include<stdio.h>
#include<cuda.h>
#include<time.h>
#define O_TILE_WIDTH 10
#define MASK_WIDTH 9
#define I_TILE_WIDTH (O_TILE_WIDTH+MASK_WIDTH-1)
__global__ void Convolution2DBasicKernel(float *out, float *in, int in_height, int in_width, const float *__restrict__ mask, int output_dim)
{
int tx=threadIdx.x;
int ty=threadIdx.y;
int row_o=blockIdx.y*O_TILE_WIDTH+ty;
int col_o=blockIdx.x*O_TILE_WIDTH+tx;
int row_i=row_o;
int col_i=col_o;
__syncthreads();
__shared__ float Ns[I_TILE_WIDTH][I_TILE_WIDTH];
///////////////////////////////////////////////////////////
//////////////////// reading input data ///////////////////
if( (row_i>=0)&&(row_i<in_height)&&(col_i>=0)&&(col_i<in_width) )
{
Ns[ty][tx]=in[row_i*in_width + col_i];
}
else
{
Ns[ty][tx]=0.0f;
}
__syncthreads();
///////////////////////////////////////////////////////////
//////////////////// calculating convol ///////////////////
float output=0.0f;
if( (tx<O_TILE_WIDTH)&&(ty<O_TILE_WIDTH) )
{
for(int i=0; i<MASK_WIDTH; i++)
{
for(int j=0; j<MASK_WIDTH; j++)
{
output += Ns[ty+i][tx+j]*mask[i*MASK_WIDTH+j];
}
}
}
__syncthreads();
if( (row_o<output_dim)&&(col_o<output_dim) )
{
out[row_o*output_dim+col_o]=output;//in_width
}
__syncthreads();
}
int main() {
int input_dim=24;
int kernel_dim=9;
int output_dim=16;
float *input = new float[input_dim*input_dim];
float *kernel = new float[kernel_dim*kernel_dim];
float *output = new float[output_dim*output_dim];
float *d_input;
float *d_kernel;
float *d_output;
cudaMalloc(&d_input, sizeof(float)*input_dim*input_dim);
cudaMalloc(&d_kernel, sizeof(float)*kernel_dim*kernel_dim);
cudaMalloc(&d_output, sizeof(float)*output_dim*output_dim);
for(int i=0; i<input_dim*input_dim; i++)
{
input[i]=1.0;
}
for(int i=0; i<kernel_dim*kernel_dim; i++)
{
kernel[i]=1.0;
}
cudaMemcpy(d_input, input, sizeof(float)*input_dim*input_dim, cudaMemcpyHostToDevice);
cudaMemcpy(d_kernel, kernel, sizeof(float)*kernel_dim*kernel_dim, cudaMemcpyHostToDevice);
dim3 dimBlock (I_TILE_WIDTH, I_TILE_WIDTH, 1);
dim3 dimGrid ((output_dim-1)/O_TILE_WIDTH+1, (output_dim-1)/O_TILE_WIDTH+1, 1);
clock_t begin, end;
double time_spent;
begin = clock();
for(int iteration=0; iteration<1; iteration++)//100000
{
Convolution2DBasicKernel<<<dimGrid, dimBlock>>>(d_output, d_input, input_dim, input_dim, d_kernel, output_dim);
}
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("time: %f\n", time_spent);
cudaMemcpy(output, d_output, sizeof(float)*output_dim*output_dim, cudaMemcpyDeviceToHost);
for(int y=0; y<output_dim; y++)
{
for(int x=0; x<output_dim; x++)
printf("%d\t", int(output[y*16+x]));
printf("\n");
}
}
答案 0 :(得分:1)
这是竞争条件。
这是一个例子。
您将每块启动18x18个线程和2x2块。
示例:
ThreadA
threadIdx.x = 10
threadIdx.y = 0
blockIdx.x = 0
blockIdx.y = 0
ThreadB
threadIdx.x = 0
threadIdx.y = 0
blockIdx.x = 1
blockIdx.y = 0
在你计算内核时:
int tx=threadIdx.x
int ty=threadIdx.y
int row_o=blockIdx.y*O_TILE_WIDTH+ty
int col_o=blockIdx.x*O_TILE_WIDTH+tx
using O_TILE_WIDTH = 10
ThreadA
row_o = 0*10+10 = 10
col_o = 0
ThreadB
row_o = 1*10+0 = 10
col_o = 0
这意味着两个线程将在内存中的相同位置输出结果,但计算方式不同。
答案 1 :(得分:0)
您的共享内存访问权限已超出范围。
假设您确信自己的计划或多或少是正确的,那么您需要确保自己不会超出界限:
if( (tx<O_TILE_WIDTH)&&(ty<O_TILE_WIDTH) ) {
for(int i=0; i<MASK_WIDTH; i++) {
if(ty +i < O_TILE_WIDTH) { // Changed here
for(int j=0; j<MASK_WIDTH; j++) {
if(tx +j < O_TILE_WIDTH) { // Changed here
output += Ns[ty+i][tx+j]*mask[i*MASK_WIDTH+j];
}
}
}
}
}