Функция CUDA не будет выполняться для цикла на Python с Numba - PullRequest
0 голосов
/ 31 августа 2018

Я пытаюсь запустить простой цикл обновления симуляции на GPU. По сути, существует группа «существ», представленных кружками, которые в каждом цикле обновления будут перемещаться, а затем будет проверяться, пересекаются ли какие-либо из них.

import numpy as np
import math
from numba import cuda


@cuda.jit('void(float32[:], float32[:], float32[:], uint8[:], float32[:], float32[:], float32, uint32, uint32)')
def update(p_x, p_y, radii, types, velocities, max_velocities, acceleration, num_creatures, cycles):
    for c in range(cycles):
        for i in range(num_creatures):
            velocities[i] = velocities[i] + acceleration
            if velocities[i] > max_velocities[i]:
                velocities[i] = max_velocities[i]
            p_x[i] = p_x[i] + (math.cos(1.0) * velocities[i])
            p_y[i] = p_y[i] + (math.sin(1.0) * velocities[i])
        for i in range(num_creatures):
            for j in range(i, num_creatures):
                delta_x = p_x[j] - p_x[i]
                delta_y = p_y[j] - p_y[i]
                distance_squared = (delta_x * delta_x) + (delta_y * delta_y)
                sum_of_radii = radii[types[i]] + radii[types[i]]
                if distance_squared < sum_of_radii * sum_of_radii:
                    pass


acceleration = .1
creature_radius = 10
spacing = 20
food_radius = 3

max_num_creatures = 1500
num_creatures = 0
max_num_food = 500
num_food = 0
max_num_entities = max_num_creatures + max_num_food
num_entities = 0
cycles = 1


p_x = np.empty((max_num_entities, 1), dtype=np.float32)
p_y = np.empty((max_num_entities, 1), dtype=np.float32)
radii = np.array([creature_radius, creature_radius, food_radius], dtype=np.float32)
types = np.empty((max_num_entities, 1), dtype=np.uint8)

velocities = np.empty((max_num_creatures, 1), dtype=np.float32)
max_velocities = np.empty((max_num_creatures, 1), dtype=np.float32)
# types:
# male - 0
# female - 1
# food - 2
for x in range(1, 800 // spacing):
    for y in range(1, 600 // spacing):
        if num_creatures % 2 == 0:
            types[num_creatures] = 0
        else:
            types[num_creatures] = 1
        p_x[num_creatures] = x * spacing
        p_y[num_creatures] = y * spacing
        max_velocities[num_creatures] = 5
        num_creatures += 1


device_p_x = cuda.to_device(p_x)
device_p_y = cuda.to_device(p_y)
device_radii = cuda.to_device(radii)
device_types = cuda.to_device(types)
device_velocities = cuda.to_device(velocities)
device_max_velocities = cuda.to_device(max_velocities)
update(device_p_x, device_p_y, device_radii, device_types, device_velocities, device_max_velocities,
        acceleration, num_creatures, cycles)
print(device_p_x.copy_to_host()[0])

1.0 в math.cos и math.sin - просто заполнитель для указаний отдельных существ. У меня есть цикл, выполняемый циклов количество раз. Если я попытаюсь удалить его и оставить только блок кода, перемещающий существ, ни p_x, p_y или скорости не изменились, даже если я добавлю к ним константу. Почему нет?

1 Ответ

0 голосов
/ 01 сентября 2018

Есть как минимум две проблемы:

  1. Вы не инициализируете velocities:

    velocities = np.empty((max_num_creatures, 1), dtype=np.float32)
    

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

    velocities = np.ones((max_num_creatures, 1), dtype=np.float32)
    
  2. Это неправильная форма массива:

    p_x = np.empty((max_num_entities, 1), dtype=np.float32)
                   ^^^^^^^^^^^^^^^^^^^^^
    

    в соответствии с вашей подписью ядра:

    @cuda.jit('void(float32[:], float32[:], float32[:], uint8[:], float32[:], float32[:], float32, uint32, uint32)')
                    ^^^^^^^^^^
    

    мы можем исправить это с помощью:

    p_x = np.empty(max_num_entities, dtype=np.float32)
    

    и аналогично для p_y, types, velocities и max_velocities. (Я полагаю, что некоторые изменения могут быть в порядке и для radii, но не совсем понятно, что вы собираетесь с этим, так как кажется, что вы хотите многомерный массив, но обращаетесь к нему в ядре как одномерный массив, AFAICT. Кроме того, этот раздел кода вашего ядра ничего не делает, поэтому он более или менее не имеет значения для рассматриваемой проблемы).

Когда я делаю эти изменения, я получаю то, что кажется разумным:

$ cat t9.py
import numpy as np
import math
from numba import cuda


@cuda.jit('void(float32[:], float32[:], float32[:], uint8[:], float32[:], float32[:], float32, uint32, uint32)')
def update(p_x, p_y, radii, types, velocities, max_velocities, acceleration, num_creatures, cycles):
    for c in range(cycles):
        for i in range(num_creatures):
            velocities[i] = velocities[i] + acceleration
            if velocities[i] > max_velocities[i]:
                velocities[i] = max_velocities[i]
            p_x[i] = p_x[i] + (math.cos(1.0) * velocities[i])
            p_y[i] = p_y[i] + (math.sin(1.0) * velocities[i])
        for i in range(num_creatures):
            for j in range(i, num_creatures):
                delta_x = p_x[j] - p_x[i]
                delta_y = p_y[j] - p_y[i]
                distance_squared = (delta_x * delta_x) + (delta_y * delta_y)
                sum_of_radii = radii[types[i]] + radii[types[i]]
                if distance_squared < sum_of_radii * sum_of_radii:
                    pass


acceleration = .1
creature_radius = 10
spacing = 20
food_radius = 3

max_num_creatures = 1500
num_creatures = 0
max_num_food = 500
num_food = 0
max_num_entities = max_num_creatures + max_num_food
num_entities = 0
cycles = 1


p_x = np.empty(max_num_entities, dtype=np.float32)
p_y = np.empty(max_num_entities, dtype=np.float32)
radii = np.array([creature_radius, creature_radius, food_radius], dtype=np.float32)
types = np.empty(max_num_entities, dtype=np.uint8)

velocities = np.ones(max_num_creatures, dtype=np.float32)
max_velocities = np.empty(max_num_creatures, dtype=np.float32)
# types:
# male - 0
# female - 1
# food - 2
for x in range(1, 800 // spacing):
    for y in range(1, 600 // spacing):
        if num_creatures % 2 == 0:
            types[num_creatures] = 0
        else:
            types[num_creatures] = 1
        p_x[num_creatures] = x * spacing
        p_y[num_creatures] = y * spacing
        max_velocities[num_creatures] = 5
        num_creatures += 1


device_p_x = cuda.to_device(p_x)
device_p_y = cuda.to_device(p_y)
device_radii = cuda.to_device(radii)
device_types = cuda.to_device(types)
device_velocities = cuda.to_device(velocities)
device_max_velocities = cuda.to_device(max_velocities)
update(device_p_x, device_p_y, device_radii, device_types, device_velocities, device_max_velocities,
        acceleration, num_creatures, cycles)
print(device_p_x.copy_to_host())
$ python t9.py
[  2.05943317e+01   2.05943317e+01   2.05943317e+01 ...,   3.64769361e-11
   1.52645868e-19   1.80563260e+28]
$

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

...