В настоящее время я работаю над ускорением некоторой числовой обработки путем ее разгрузки в графический процессор. У меня есть демонстрационный код ниже (реальный код будет более сложным). Я беру массив NP и подсчитываю, сколько значений попадает в диапазон.
Аппаратное обеспечение, я использую n и AMD 3600X (6-ядерный 12-ниточный) и RTX 2060 Super (2176 ядер cuda).
Пример кода:
import time
import numpy as np
from numba import cuda
from numba import jit
width = 1024
height = 1024
size = width * height
print(f'Number of records {size}')
array_of_random = np.random.rand(size)
output_array = np.zeros(size, dtype=bool)
device_array = cuda.to_device(array_of_random)
device_output_array = cuda.device_array_like(output_array)
def count_array_standard(array, pivot_point, local_output_array):
for i in range(array.shape[0]):
if (pivot_point - 0.05) < array[i] < (pivot_point + 0.05):
local_output_array[i] = True
else:
local_output_array[i] = False
@jit('(f8,b1[:])')
def count_array_jit(pivot_point, local_output_array):
global array_of_random
for i in range(len(array_of_random)):
if (pivot_point - 0.05) < array_of_random[i] < (pivot_point + 0.05):
local_output_array[i] = True
else:
local_output_array[i] = False
@cuda.jit()
def count_array_cuda(local_device_array, pivot_point, local_device_output_array):
tx = cuda.threadIdx.x
ty = cuda.blockIdx.x
bw = cuda.blockDim.x
pos = tx + ty * bw
for i in range(pos, pos + bw):
if i<local_device_output_array.size:
if (pivot_point - 0.05) < local_device_array[i] < (pivot_point + 0.05):
local_device_output_array[i] = True
else:
local_device_output_array[i] = False
print("")
print("Standard")
for x in range(3):
start = time.perf_counter()
count_array_standard(array_of_random, 0.5, output_array)
result = np.sum(output_array)
print(f'Run: {x} Result: {result} Time: {time.perf_counter() - start}')
print("")
print("Jit")
for x in range(3):
start = time.perf_counter()
count_array_jit(0.5, output_array)
result = np.sum(output_array)
print(f'Run: {x} Result: {result} Time: {time.perf_counter() - start}')
print("")
print("Cuda Jit")
threads_per_block = 16
blocks_per_grid = (array_of_random.size + (threads_per_block - 1)) // threads_per_block
for x in range(3):
start = time.perf_counter()
count_array_cuda[blocks_per_grid, threads_per_block](device_array, .5, device_output_array)
result = np.sum(device_output_array.copy_to_host())
print(f'Run: {x} Result: {result} Time: {time.perf_counter() - start}')
Дает мне набор результатов:
Number of records 1048576
Standard
Run: 0 Result: 104778 Time: 0.35327580000000003
Run: 1 Result: 104778 Time: 0.3521047999999999
Run: 2 Result: 104778 Time: 0.35452510000000004
Jit
Run: 0 Result: 104778 Time: 0.0020474000000001435
Run: 1 Result: 104778 Time: 0.001856599999999986
Run: 2 Result: 104778 Time: 0.0018399000000000054
Cuda Jit
Run: 0 Result: 104778 Time: 0.10867309999999986
Run: 1 Result: 104778 Time: 0.0023599000000000814
Run: 2 Result: 104778 Time: 0.002314700000000114
Базовый jit и cuda jit numba работают быстрее, чем стандартный код, и я ожидаю, чтоПервоначальный прогон джитов занимает немного больше времени, последующие прогоны быстрее с джитом, чем с куда. Я также вижу оптимальные результаты для cuda при использовании около 16 потоков, где я ожидал, что потребуется большее количество потоков.
Поскольку я новичок в кодировании cuda, мне интересно, пропустил ли я что-то простое. Любое руководство с благодарностью получено.