Skip to content

Commit feb13b2

Browse files
authored
Merge pull request #246 from Hardcode84/numba-mlir-kmeans
Add numba-mlir kmeans benchmarks
2 parents c5ff998 + b554156 commit feb13b2

File tree

2 files changed

+225
-0
lines changed

2 files changed

+225
-0
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# SPDX-FileCopyrightText: 2022 - 2023 Intel Corporation
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
from math import sqrt
6+
7+
import numba_mlir.kernel as nb
8+
9+
atomic_add = nb.atomic.add
10+
11+
12+
@nb.kernel
13+
def groupByCluster(arrayP, arrayPcluster, arrayC, num_points, num_centroids):
14+
idx = nb.get_global_id(0)
15+
# if idx < num_points: # why it was removed??
16+
minor_distance = -1
17+
for i in range(num_centroids):
18+
dx = arrayP[idx, 0] - arrayC[i, 0]
19+
dy = arrayP[idx, 1] - arrayC[i, 1]
20+
my_distance = sqrt(dx * dx + dy * dy)
21+
if minor_distance > my_distance or minor_distance == -1:
22+
minor_distance = my_distance
23+
arrayPcluster[idx] = i
24+
25+
26+
@nb.kernel
27+
def calCentroidsSum1(arrayCsum, arrayCnumpoint):
28+
i = nb.get_global_id(0)
29+
arrayCsum[i, 0] = 0
30+
arrayCsum[i, 1] = 0
31+
arrayCnumpoint[i] = 0
32+
33+
34+
@nb.kernel
35+
def calCentroidsSum2(arrayP, arrayPcluster, arrayCsum, arrayCnumpoint):
36+
i = nb.get_global_id(0)
37+
ci = arrayPcluster[i]
38+
atomic_add(arrayCsum, (ci, 0), arrayP[i, 0])
39+
atomic_add(arrayCsum, (ci, 1), arrayP[i, 1])
40+
atomic_add(arrayCnumpoint, ci, 1)
41+
42+
43+
@nb.kernel
44+
def updateCentroids(arrayC, arrayCsum, arrayCnumpoint, num_centroids):
45+
i = nb.get_global_id(0)
46+
arrayC[i, 0] = arrayCsum[i, 0] / arrayCnumpoint[i]
47+
arrayC[i, 1] = arrayCsum[i, 1] / arrayCnumpoint[i]
48+
49+
50+
@nb.kernel
51+
def copy_arrayC(arrayC, arrayP):
52+
i = nb.get_global_id(0)
53+
arrayC[i, 0] = arrayP[i, 0]
54+
arrayC[i, 1] = arrayP[i, 1]
55+
56+
57+
def kmeans_kernel(
58+
arrayP,
59+
arrayPcluster,
60+
arrayC,
61+
arrayCsum,
62+
arrayCnumpoint,
63+
niters,
64+
num_points,
65+
num_centroids,
66+
):
67+
copy_arrayC[num_centroids, ()](arrayC, arrayP)
68+
69+
for i in range(niters):
70+
groupByCluster[num_points, ()](
71+
arrayP, arrayPcluster, arrayC, num_points, num_centroids
72+
)
73+
74+
calCentroidsSum1[num_centroids, ()](arrayCsum, arrayCnumpoint)
75+
76+
calCentroidsSum2[num_points, ()](
77+
arrayP, arrayPcluster, arrayCsum, arrayCnumpoint
78+
)
79+
80+
updateCentroids[num_centroids, ()](
81+
arrayC, arrayCsum, arrayCnumpoint, num_centroids
82+
)
83+
84+
return arrayC, arrayCsum, arrayCnumpoint
85+
86+
87+
def kmeans(
88+
arrayP,
89+
arrayPclusters,
90+
arrayC,
91+
arrayCsum,
92+
arrayCnumpoint,
93+
niters,
94+
npoints,
95+
ndims,
96+
ncentroids,
97+
):
98+
arrayC, arrayCsum, arrayCnumpoint = kmeans_kernel(
99+
arrayP,
100+
arrayPclusters,
101+
arrayC,
102+
arrayCsum,
103+
arrayCnumpoint,
104+
niters,
105+
npoints,
106+
ncentroids,
107+
)
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# SPDX-FileCopyrightText: 2022 - 2023 Intel Corporation
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
import numba
6+
import numba_mlir as nb
7+
import numba_mlir.kernel as nbk
8+
import numpy as np
9+
10+
atomic_add = nbk.atomic.add
11+
12+
13+
# determine the euclidean distance from the cluster center to each point
14+
@nb.njit
15+
def groupByCluster(arrayP, arrayPcluster, arrayC, num_points, num_centroids):
16+
# parallel for loop
17+
for i0 in numba.prange(num_points):
18+
minor_distance = -1
19+
for i1 in range(num_centroids):
20+
dx = arrayP[i0, 0] - arrayC[i1, 0]
21+
dy = arrayP[i0, 1] - arrayC[i1, 1]
22+
my_distance = np.sqrt(dx * dx + dy * dy)
23+
if minor_distance > my_distance or minor_distance == -1:
24+
minor_distance = my_distance
25+
arrayPcluster[i0] = i1
26+
return arrayPcluster
27+
28+
29+
# assign points to cluster
30+
@nb.njit
31+
def calCentroidsSum(
32+
arrayP, arrayPcluster, arrayCsum, arrayCnumpoint, num_points, num_centroids
33+
):
34+
# parallel for loop
35+
for i in numba.prange(num_centroids):
36+
arrayCsum[i, 0] = 0
37+
arrayCsum[i, 1] = 0
38+
arrayCnumpoint[i] = 0
39+
40+
41+
@nbk.kernel
42+
def calCentroidsSum2(arrayP, arrayPcluster, arrayCsum, arrayCnumpoint):
43+
i = nbk.get_global_id(0)
44+
ci = arrayPcluster[i]
45+
atomic_add(arrayCsum, (ci, 0), arrayP[i, 0])
46+
atomic_add(arrayCsum, (ci, 1), arrayP[i, 1])
47+
atomic_add(arrayCnumpoint, ci, 1)
48+
49+
50+
# update the centriods array after computation
51+
@nb.njit
52+
def updateCentroids(arrayC, arrayCsum, arrayCnumpoint, num_centroids):
53+
for i in numba.prange(num_centroids):
54+
arrayC[i, 0] = arrayCsum[i, 0] / arrayCnumpoint[i]
55+
arrayC[i, 1] = arrayCsum[i, 1] / arrayCnumpoint[i]
56+
57+
58+
@nb.njit
59+
def copy_arrayC(arrayC, arrayP, num_centroids):
60+
for i in numba.prange(num_centroids):
61+
arrayC[i, 0] = arrayP[i, 0]
62+
arrayC[i, 1] = arrayP[i, 1]
63+
64+
65+
def kmeans_numba(
66+
arrayP,
67+
arrayPcluster,
68+
arrayC,
69+
arrayCsum,
70+
arrayCnumpoint,
71+
niters,
72+
num_points,
73+
num_centroids,
74+
):
75+
for i in range(niters):
76+
groupByCluster(arrayP, arrayPcluster, arrayC, num_points, num_centroids)
77+
78+
calCentroidsSum(
79+
arrayP,
80+
arrayPcluster,
81+
arrayCsum,
82+
arrayCnumpoint,
83+
num_points,
84+
num_centroids,
85+
)
86+
87+
calCentroidsSum2[num_points, ()](
88+
arrayP, arrayPcluster, arrayCsum, arrayCnumpoint
89+
)
90+
91+
updateCentroids(arrayC, arrayCsum, arrayCnumpoint, num_centroids)
92+
93+
return arrayC, arrayCsum, arrayCnumpoint
94+
95+
96+
def kmeans(
97+
arrayP,
98+
arrayPclusters,
99+
arrayC,
100+
arrayCsum,
101+
arrayCnumpoint,
102+
niters,
103+
npoints,
104+
ndims,
105+
ncentroids,
106+
):
107+
copy_arrayC(arrayC, arrayP, ncentroids)
108+
109+
arrayC, arrayCsum, arrayCnumpoint = kmeans_numba(
110+
arrayP,
111+
arrayPclusters,
112+
arrayC,
113+
arrayCsum,
114+
arrayCnumpoint,
115+
niters,
116+
npoints,
117+
ncentroids,
118+
)

0 commit comments

Comments
 (0)