Расчет Numbapro Jit дает неверный результат

У меня есть кусок кода, который использует Numbapro для написания простого ядра, чтобы выстроить в квадрат содержимое двух массивов размером 41724, сложить их вместе и сохранить в другом массиве. Все массивы имеют одинаковый размер и являются float32. Код ниже:

import numpy as np
from numba import *
from numbapro import cuda

@cuda.jit('void(float32[:],float32[:],float32[:])')
def square_add(a,b,c):
    tx = cuda.threadIdx.x
    bx = cuda.blockIdx.x
    bw = cuda.blockDim.x

    i = tx + bx * bw

    #Since the length of a is 41724 and the total
    #threads is 41*1024 = 41984, this check is necessary
    if (i>len(a)):
            return
    else:
            c[i] = a[i]*a[i] + b[i]*b[i]


a = np.array(range(0,41724),dtype = np.float32)
b = np.array(range(41724,83448),dtype=np.float32)
c = np.zeros(shape=(1,41724),dtype=np.float32)

d_a = cuda.to_device(a)
d_b = cuda.to_device(b)
d_c = cuda.to_device(c,copy=False)

#Launch the kernel; Gridsize = (1,41),Blocksize=(1,1024)
square_add[(1,41),(1,1024)](d_a,d_b,d_c)

c = d_c.copy_to_host()
print c
print len(c[0])

Значения, которые я получаю, когда я печатаю результат операции (массив c), полностью отличаются от тех, которые я делаю точно так же в терминале Python. Я не знаю, что я делаю не так здесь.

1 ответ

Здесь есть две проблемы.

Во-первых, вы указываете размер блока и сетки для запуска ядра CUDA, что несовместимо со схемой индексации, которую вы выбрали для использования в ядре.

Это:

square_add[(1,41),(1,1024)](d_a,d_b,d_c)

запускает двумерную сетку, где все потоки имеют одинаковые размеры блоков и нитей в x и меняются только по y. Это подразумевает, что

tx = cuda.threadIdx.x
bx = cuda.blockIdx.x
bw = cuda.blockDim.x

i = tx + bx * bw

даст i=0 для каждой темы. Если вы измените запуск ядра на это:

square_add[(41,1),(1024,1)](d_a,d_b,d_c)

вы обнаружите, что в индексации будет работать правильно.

Второе, что c был объявлен как двумерный массив, но подпись функции ядра была объявлена ​​как одномерный массив. При некоторых обстоятельствах среда выполнения numbapro должна обнаружить это и вызвать ошибку.

Я смог заставить ваш пример работать правильно, вот так:

import numpy as np
from numba import *
from numbapro import cuda

@cuda.jit('void(float32[:],float32[:],float32[:,:])')
def square_add(a,b,c):
    tx = cuda.threadIdx.x
    bx = cuda.blockIdx.x
    bw = cuda.blockDim.x

    i = tx + bx * bw

    if (i<len(a)):
        c[0,i] = a[i]*a[i] + b[i]*b[i]

a = np.array(range(0,41724),dtype=np.float32)
b = np.array(range(41724,83448),dtype=np.float32)
c = np.zeros(shape=(1,41724),dtype=np.float32)

d_a = cuda.to_device(a)
d_b = cuda.to_device(b)
d_c = cuda.to_device(c, copy=False)

square_add[(41,1),(1024,1)](d_a,d_b,d_c)

c = d_c.copy_to_host()
print(c)
print(c.shape)

[Обратите внимание, что я использую Python 3, поэтому здесь используются операторы печати нового стиля]

$ ipython numbatest.py 
numbapro:1: ImportWarning: The numbapro package is deprecated in favour of the accelerate package. Please update your code to use equivalent functions from accelerate.
[[  1.74089216e+09   1.74097562e+09   1.74105907e+09 ...,   8.70371021e+09
    8.70396006e+09   8.70421094e+09]]
(1, 41724)
Другие вопросы по тегам