2017-11-13 11 views
1

나는 cuda와 pycuda에 대해 매우 새로운 기술이다. 동일한 배열을 n 번 단순히 "반복"함으로써 배열 (1xd)의 행렬 (차원 nxd)을 만드는 커널이 필요합니다. 예를 들어, n = 4 및 d = 3이라고 가정하면 배열 [1 2 3] 인 경우 내 커널의 결과가 같아야간단한 pycuda 커널의 이상한 행동

[1 2 3 
1 2 3 
1 2 3 
1 2 3] 

(4x3의 행렬). 나는이 코드를 실행하면, 지금

kernel_code_template = """ 
__global__ void TileKernel(float *in, float *out) 
{ 
    // Each thread computes one element of out 
    int y = blockIdx.y * blockDim.y + threadIdx.y; 
    int x = blockIdx.x * blockDim.x + threadIdx.x; 

    if (y > %(n)s || x > %(d)s) return; 

    out[y * %(d)s + x] = in[x]; 
} 
""" 

d = 64 
n = 512 

blockSizex = 16 
blockSizey = 16 
gridSizex = (d + blockSizex - 1)/blockSizex 
gridSizey = (n + blockSizey - 1)/blockSizey 

# get the kernel code from the template 
kernel_code = kernel_code_template % { 
    'd': d, 
    'n': n 
    } 
mod = SourceModule(kernel_code) 
TileKernel = mod.get_function("TileKernel") 

vec_cpu = np.arange(d).astype(np.float32) # just as an example 
vec_gpu = gpuarray.to_gpu(vec_cpu) 
out_gpu = gpuarray.empty((n, d), np.float32) 

TileKernel.prepare("PP") 
TileKernel.prepared_call((gridSizex, gridSizey), (blockSizex, blockSizey, 1), vec_gpu.gpudata, out_gpu.gpudata) 

out_cpu = out_gpu.get() 

:

기본적으로,

나는 아래의 코드를 작성했습니다 (N, 1) (배열) numpy.tile을하고 같은입니다 d는 2의 거듭 제곱 = 16입니다. 올바른 결과를 얻습니다. (numpy.tile (vec_cpu, (n, 1))); 하지만 d를 다른 것으로 설정하면 (예를 들어 88이라고 가정 해 봅시다) 출력 매트릭스의 모든 요소에 첫 번째 열을 제외하고 올바른 값이 있습니다. 일부 항목은 올바르지 만 다른 항목은 다른 값을가집니다. 모든 잘못된 요소에 대해 동일하지만 모든 실행마다 다르다. 그리고 잘못된 값을 가진 첫 번째 열의 항목은 매 달리 다르다. 예 :

[0 1 2 
0 1 2 
6 1 2 
0 1 2 
6 1 2 
...] 

, 사전에 감사를 난 정말이 문제의 원인을 알아낼 수는 없지만, 어쩌면

어떤 도움을 이해할 수있을 것이다 ... 단지 내가 부족 간단 뭔가 !

+1

코드로 테스트 한 모든 예는 올바르게 작동하는 것 같습니다 (예 : d = 88, n = 567). np.allclose (np.tile (vec_cpu, (n, 1)), out_cpu) . 귀하의 질문에 맞지 않는 * 정확한 * 사례를 편집 할 수 있습니까? – talonmies

+0

이 오류를 재현하는 방법을 정확히 알았습니다. 먼저 d = 88, n = 32로 스크립트를 실행합니다. 정상적으로 작동합니다. 그럼 내가 d를 128로 바꾼다. 똑같은 n, 여전히 잘 동작한다. 그런 다음 d를 88로 변경하고 동일한 n을 입력하면 첫 번째 열에서 오류가 발생합니다! – Odysseo

답변

0

커널 코드 내에서 경계 검사가 잘못되었습니다. 이

if (y > n || x > d) return; 
out[y * d + x] = in[x]; 

가 있어야한다 : 더 나은 여전히 ​​

if (y >= n || x >= d) return; 
out[y * d + x] = in[x]; 

또는 :

if ((y < n) && (x < d)) 
    out[y * d + x] = in[x]; 

배열의 모든 배열 유효한 색인 0 < x < d0 < y < n에 놓여있다. x=d을 허용하면 출력 배열의 다음 행에있는 첫 번째 항목을 알 수없는 값으로 덮어 쓸 수 있으므로 정의되지 않은 동작이 발생합니다. 이것은 때때로 결과가 정확하고 다른 경우가 아닌 이유를 설명합니다.