CUDA 函数不会使用 Numba 在 Python 上执行循环
CUDA Function Won't Execute For Loop on Python with Numba
我正在尝试 运行 GPU 上模拟的简单更新循环。基本上有一堆 "creatures" 由圆圈表示,在每个更新循环中它们将移动,然后将检查它们是否相交。
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])
math.cos 和 math.sin 中的 1.0 只是单个生物方向的占位符
我有一个周围循环执行循环次数。如果我尝试删除它并只留下移动生物的代码块,p_x、p_y 或速度都没有改变,即使我向它们添加一个常量。为什么不呢?
至少有两个问题:
您没有初始化 velocities
:
velocities = np.empty((max_num_creatures, 1), dtype=np.float32)
我们可以通过以下简单测试修复该问题:
velocities = np.ones((max_num_creatures, 1), dtype=np.float32)
这不是正确的数组形状:
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]
$
另请注意,目前您只启动一个线程的一个块,但我认为目前这与您的请求无关。
我正在尝试 运行 GPU 上模拟的简单更新循环。基本上有一堆 "creatures" 由圆圈表示,在每个更新循环中它们将移动,然后将检查它们是否相交。
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])
math.cos 和 math.sin 中的 1.0 只是单个生物方向的占位符 我有一个周围循环执行循环次数。如果我尝试删除它并只留下移动生物的代码块,p_x、p_y 或速度都没有改变,即使我向它们添加一个常量。为什么不呢?
至少有两个问题:
您没有初始化
velocities
:velocities = np.empty((max_num_creatures, 1), dtype=np.float32)
我们可以通过以下简单测试修复该问题:
velocities = np.ones((max_num_creatures, 1), dtype=np.float32)
这不是正确的数组形状:
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]
$
另请注意,目前您只启动一个线程的一个块,但我认为目前这与您的请求无关。