计算一个大的 haversine 距离矩阵
Calculating a large haversine distance matrix
运行 OOM 试图计算地理坐标列表上的半正弦距离矩阵。我可以访问适合距离矩阵的 GPU,但我找不到任何具有为 GPU 实现的半正弦距离矩阵的库。寻找为此编写 CUDA 内核的建议。
阅读 numba 的 cuda 库和 NVIDIA Rapids 后,我能够创建以下 Python 函数:
from numba import cuda
import math
@cuda.jit
def gpu_haversine_distance_matrix(lon, lat, dm):
i,j = cuda.grid(2)
if i < lon.shape[0] == dm.shape[0] and j < lat.shape[0] == dm.shape[1]:
if i == j:
dm[i][j] = 0
else:
if i < j:
longit_a = math.radians(lon[i])
latit_a = math.radians(lat[i])
longit_b = math.radians(lon[j])
latit_b = math.radians(lat[j])
else:
longit_a = math.radians(lon[j])
latit_a = math.radians(lat[j])
longit_b = math.radians(lon[i])
latit_b = math.radians(lat[i])
dist_longit_add = longit_b - longit_a
dist_latit_sub = latit_b - latit_a
dist_latit_add = latit_b + latit_a
pre_comp = math.sin(dist_latit_sub/2)**2
area = pre_comp + ((1 - pre_comp - math.sin(dist_latit_add/2)**2) * math.sin(dist_longit_add/2)**2)
central_angle = 2 * math.asin(math.sqrt(area))
radius = 3958
dm[i][j] = math.fabs(central_angle * radius)
co_loc_cdf = cudf.from_pandas(co_loc) # pandas dataframe containing longitude and latitude column
dm_global_mem = cuda.device_array((co_loc_cdf.shape[0], co_loc_cdf.shape[0]))
threadsperblock = (16, 16)
blockspergrid_x = math.ceil(co_loc_cdf.shape[0] / threadsperblock[0])
blockspergrid_y = math.ceil(co_loc_cdf.shape[0] / threadsperblock[0])
blockspergrid = (blockspergrid_x, blockspergrid_y)
haversine_gpu_distance_matrix[blockspergrid, threadsperblock](co_loc_cdf['longitude'], co_loc_cdf['latitude'], dm_global_mem)
这 return 是 GPU 内存中的半正弦距离矩阵。距离单位以英里为单位,但如果需要,可以将 radius
值调整为 return 米。仍然希望了解如何最好地决定每个块的线程数和每个网格的块数。
运行 OOM 试图计算地理坐标列表上的半正弦距离矩阵。我可以访问适合距离矩阵的 GPU,但我找不到任何具有为 GPU 实现的半正弦距离矩阵的库。寻找为此编写 CUDA 内核的建议。
阅读 numba 的 cuda 库和 NVIDIA Rapids 后,我能够创建以下 Python 函数:
from numba import cuda
import math
@cuda.jit
def gpu_haversine_distance_matrix(lon, lat, dm):
i,j = cuda.grid(2)
if i < lon.shape[0] == dm.shape[0] and j < lat.shape[0] == dm.shape[1]:
if i == j:
dm[i][j] = 0
else:
if i < j:
longit_a = math.radians(lon[i])
latit_a = math.radians(lat[i])
longit_b = math.radians(lon[j])
latit_b = math.radians(lat[j])
else:
longit_a = math.radians(lon[j])
latit_a = math.radians(lat[j])
longit_b = math.radians(lon[i])
latit_b = math.radians(lat[i])
dist_longit_add = longit_b - longit_a
dist_latit_sub = latit_b - latit_a
dist_latit_add = latit_b + latit_a
pre_comp = math.sin(dist_latit_sub/2)**2
area = pre_comp + ((1 - pre_comp - math.sin(dist_latit_add/2)**2) * math.sin(dist_longit_add/2)**2)
central_angle = 2 * math.asin(math.sqrt(area))
radius = 3958
dm[i][j] = math.fabs(central_angle * radius)
co_loc_cdf = cudf.from_pandas(co_loc) # pandas dataframe containing longitude and latitude column
dm_global_mem = cuda.device_array((co_loc_cdf.shape[0], co_loc_cdf.shape[0]))
threadsperblock = (16, 16)
blockspergrid_x = math.ceil(co_loc_cdf.shape[0] / threadsperblock[0])
blockspergrid_y = math.ceil(co_loc_cdf.shape[0] / threadsperblock[0])
blockspergrid = (blockspergrid_x, blockspergrid_y)
haversine_gpu_distance_matrix[blockspergrid, threadsperblock](co_loc_cdf['longitude'], co_loc_cdf['latitude'], dm_global_mem)
这 return 是 GPU 内存中的半正弦距离矩阵。距离单位以英里为单位,但如果需要,可以将 radius
值调整为 return 米。仍然希望了解如何最好地决定每个块的线程数和每个网格的块数。