numba cuda не дает правильного результата с + = (требуется сокращение gpu?) - PullRequest
0 голосов
/ 12 декабря 2018

Я использую numba cuda для вычисления функции.

Код просто складывает все значения в один результат, но numba cuda дает мне результат, отличный от numpy.

numba code

 import math
 def numba_example(number_of_maximum_loop,gs,ts,bs):
        from numba import cuda
        result = cuda.device_array([3,])

        @cuda.jit(device=True)

    def BesselJ0(x):
        return math.sqrt(2/math.pi/x)

    @cuda.jit
    def cuda_kernel(number_of_maximum_loop,result,gs,ts,bs):
        i = cuda.grid(1)
        if i < number_of_maximum_loop:
            result[0] += BesselJ0(i/100+gs)
            result[1] += BesselJ0(i/100+ts)
            result[2] += BesselJ0(i/100+bs)

    # Configure the blocks
    threadsperblock = 128
    blockspergrid = (number_of_maximum_loop + (threadsperblock - 1)) // threadsperblock

    # Start the kernel 
    cuda_kernel[blockspergrid, threadsperblock](number_of_maximum_loop,result,gs,ts,bs) 

    return result.copy_to_host()

numba_example(1000,20,20,20) 

output:

array([ 0.17770302,  0.34166728,  0.35132036])

код NUMPY

import math
def numpy_example(number_of_maximum_loop,gs,ts,bs):
    import numpy as np
    result = np.zeros([3,])

    def BesselJ0(x):
        return math.sqrt(2/math.pi/x)

    for i in range(number_of_maximum_loop):
        result[0] += BesselJ0(i/100+gs)
        result[1] += BesselJ0(i/100+ts)
        result[2] += BesselJ0(i/100+bs)

    return result

numpy_example(1000,20,20,20) 

вывод:

array([ 160.40546935,  160.40546935,  160.40546935])

Я не знаю, где я ошибаюсь.Я думаю, я мог бы использовать сокращение.Но кажется невозможным закончить его одним ядром cuda. ​​

1 Ответ

0 голосов
/ 12 декабря 2018

Да, правильное параллельное сокращение необходимо для суммирования данных из нескольких потоков графического процессора в одну переменную.

Вот один тривиальный пример того, как это можно сделать из одного ядра:

$ cat t23.py
import math
def numba_example(number_of_maximum_loop,gs,ts,bs):
    from numba import cuda
    result = cuda.device_array([3,])

    @cuda.jit(device=True)
    def BesselJ0(x):
        return math.sqrt(2/math.pi/x)

    @cuda.jit
    def cuda_kernel(number_of_maximum_loop,result,gs,ts,bs):
        i = cuda.grid(1)
        if i < number_of_maximum_loop:
            cuda.atomic.add(result, 0, BesselJ0(i/100+gs))
            cuda.atomic.add(result, 1, BesselJ0(i/100+ts))
            cuda.atomic.add(result, 2, BesselJ0(i/100+bs))

# Configure the blocks
    threadsperblock = 128
    blockspergrid = (number_of_maximum_loop + (threadsperblock - 1)) // threadsperblock

 # Start the kernel
    init = [0.0,0.0,0.0]
    result = cuda.to_device(init)
    cuda_kernel[blockspergrid, threadsperblock](number_of_maximum_loop,result,gs,ts,bs)

    return result.copy_to_host()

print(numba_example(1000,20,20,20))
$ python t23.py
[ 162.04299487  162.04299487  162.04299487]
$

Вы также можете сделать правильное уменьшение числа numba напрямую с помощью декоратора reduce, как описано здесь , хотя я не уверен, что таким способом в одном ядре можно сделать 3 сокращения.

Наконец, вы можете написать обычное параллельное сокращение cuda, используя numba cuda, как указано здесь .Не должно быть трудным, я думаю, расширить это для выполнения 3 сокращений в одном ядре.

Эти 3 различных метода, вероятно, будут иметь различия в производительности, конечно.

В целом, если выВы задаетесь вопросом о расхождении результатов между моим кодом выше и вашим кодом на python в вопросе, я не могу это объяснить.Когда я запускаю ваш код на python, я получаю результаты, соответствующие коду numba cuda в моем ответе:

$ cat t24.py
import math
def numpy_example(number_of_maximum_loop,gs,ts,bs):
    import numpy as np
    result = np.zeros([3,])

    def BesselJ0(x):
        return math.sqrt(2/math.pi/x)

    for i in range(number_of_maximum_loop):
        result[0] += BesselJ0(i/100+gs)
        result[1] += BesselJ0(i/100+ts)
        result[2] += BesselJ0(i/100+bs)

    return result

print(numpy_example(1000,20,20,20))
$ python t24.py
[ 162.04299487  162.04299487  162.04299487]
$
...