Skip to content

Commit 3786cd2

Browse files
committed
Updating improvements
1 parent 7c549ae commit 3786cd2

File tree

5 files changed

+177
-40
lines changed

5 files changed

+177
-40
lines changed

scripts/profiling.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import cupyx.scipy.sparse as cpsp
2+
import cupy as cp
3+
from pyclassify import (
4+
eigenvalues_np,
5+
eigenvalues_sp,
6+
eigenvalues_cp,
7+
power_method,
8+
power_method_numba,
9+
power_method_cp,
10+
QR,
11+
QR_cp,
12+
)
13+
from pyclassify.utils import make_symmetric, read_config
14+
import numpy as np
15+
import scipy.sparse as sp
16+
import random
17+
import argparse
18+
import cProfile
19+
import os
20+
import csv
21+
22+
23+
seed = 8422
24+
random.seed(seed)
25+
cp.random.seed(seed)
26+
np.random.seed(seed)
27+
28+
29+
parser = argparse.ArgumentParser()
30+
parser.add_argument("--config", type=str, required=False, help="config file:")
31+
32+
args = parser.parse_args()
33+
filename = (
34+
args.config if args.config else "./experiments/config"
35+
) # automatic choice if no argument is passed
36+
37+
kwargs = read_config(filename)
38+
dim = kwargs["dim"]
39+
density = kwargs["density"]
40+
tol = kwargs["tol"]
41+
max_iter = kwargs["max_iter"]
42+
43+
44+
matrix = sp.random(dim, dim, density=density, format="coo")
45+
matrix = make_symmetric(matrix)
46+
cp_symm_matrix = cpsp.csr_matrix(matrix)
47+
48+
49+
logs = "./logs"
50+
iteration_factor = 300
51+
52+
53+
def profile_with_cprofile(func_name, func, *args, **kwargs):
54+
log_file = "./logs/timings.csv"
55+
with open(log_file, "a", newline="") as csvfile:
56+
writer = csv.writer(csvfile)
57+
58+
profile_output = cProfile.Profile()
59+
profile_output.enable()
60+
61+
result = func(*args, **kwargs)
62+
63+
profile_output.disable()
64+
65+
stats = profile_output.getstats()
66+
total_time = sum(stat.totaltime for stat in stats)
67+
68+
print(f"{func_name}: {total_time:.6f} s")
69+
70+
writer.writerow([func_name, dim, total_time])
71+
72+
return result
73+
74+
75+
profile_with_cprofile(
76+
"eigenvalues_np", eigenvalues_np, matrix.toarray(), symmetric=True
77+
)
78+
profile_with_cprofile("eigenvalues_sp", eigenvalues_sp, matrix, symmetric=True)
79+
profile_with_cprofile("power_method", power_method, matrix)
80+
profile_with_cprofile("power_method_numba", power_method_numba, matrix.toarray())
81+
profile_with_cprofile("QR", QR, matrix.toarray(), max_iter=iteration_factor * dim)
82+
83+
84+
def profile_with_cupy_profiler(func_name, func, *args, **kwargs):
85+
log_file = "./logs/timings.csv"
86+
with open(log_file, "a", newline="") as csvfile:
87+
writer = csv.writer(csvfile)
88+
start = cp.cuda.Event()
89+
end = cp.cuda.Event()
90+
91+
start.record()
92+
result = func(*args, **kwargs)
93+
end.record()
94+
end.synchronize()
95+
96+
result = func(*args, **kwargs)
97+
elapsed_time = cp.cuda.get_elapsed_time(start, end) / 1000
98+
print(f"{func_name}: {elapsed_time:.6f} s")
99+
100+
writer.writerow([func_name, dim, elapsed_time])
101+
102+
return result
103+
104+
105+
profile_with_cupy_profiler("eigenvalues_cp", eigenvalues_cp, cp_symm_matrix)
106+
profile_with_cupy_profiler("power_method_cp", power_method_cp, cp_symm_matrix)
107+
profile_with_cupy_profiler(
108+
"QR_cp",
109+
QR_cp,
110+
cp_symm_matrix,
111+
q0=cp.random.rand(dim),
112+
tol=1e-3,
113+
max_iter=iteration_factor * dim,
114+
)

scripts/run.py

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,23 @@
77
power_method,
88
power_method_numba,
99
power_method_cp,
10+
QR,
11+
QR_cp,
1012
)
1113
from pyclassify.utils import make_symmetric, read_config
1214
import numpy as np
1315
import scipy.sparse as sp
1416
import random
1517
import argparse
18+
import cProfile
19+
import cupyx.profiler as profiler
20+
import os
21+
import csv
1622

1723

1824
random.seed(226)
25+
cp.random.seed(226)
26+
np.random.seed(226)
1927

2028

2129
parser = argparse.ArgumentParser()
@@ -40,23 +48,45 @@
4048
cp_symm_matrix = cpsp.csr_matrix(matrix)
4149

4250

43-
eigs_np = eigenvalues_np(matrix.toarray(), symmetric=True)
44-
eigs_sp = eigenvalues_sp(matrix, symmetric=True)
45-
eigs_cp = eigenvalues_cp(cp_symm_matrix)
51+
logs = "./logs"
52+
iteration_factor = 300
4653

4754

48-
index_np = np.argmax(np.abs(eigs_np))
49-
index_sp = np.argmax(np.abs(eigs_sp))
50-
index_cp = np.argmax(np.abs(eigs_cp))
55+
cProfile.run(
56+
"eigenvalues_np(matrix.toarray(), symmetric=True)",
57+
os.path.join(logs, f"eigenvalues_np_{dim}.prof"),
58+
)
59+
cProfile.run(
60+
"eigenvalues_np(matrix, symmetric=True)",
61+
os.path.join(logs, f"eigenvalues_sp_{dim}.prof"),
62+
)
63+
cProfile.run("power_method(matrix)", os.path.join(logs, f"power_method_{dim}.prof"))
64+
cProfile.run(
65+
"power_method(matrix.toarray())",
66+
os.path.join(logs, f"power_method_numba{dim}.prof"),
67+
)
68+
cProfile.run(
69+
"QR(matrix.toarray(), max_iter=iteration_factor*d)",
70+
os.path.join(logs, f"QR_{dim}.prof"),
71+
)
72+
73+
74+
def profile_function(func_name, func, *args, **kwargs):
75+
cupyx.profiler.start()
76+
result = func(*args, **kwargs)
77+
cupyx.profiler.stop()
78+
79+
profiler_data = cupyx.profiler.get_profiler()
5180

81+
output_file = os.path.join(logs, f"{func_name}_{dim}.prof")
82+
with open(output_file, "w") as f:
83+
f.write(str(profiler_data))
5284

53-
biggest_eigenvalue_np = eigs_np[index_np]
54-
biggest_eigenvalue_sp = eigs_sp[index_sp]
55-
biggest_eigenvalue_cp = eigs_cp[index_cp]
85+
elapsed_time = profiler_data[0]["time"]
86+
print(f"{func_name}: {elapsed_time/1000} s")
87+
return result
5688

57-
biggest_eigenvalue_pm = power_method(matrix)
58-
# biggest_eigenvalue_pm_numba = power_method_numba(matrix.toarray())
59-
biggest_eigenvalue_cp = power_method_cp(cp_symm_matrix)
6089

61-
_, __ = QR(A)
62-
_, __ = QR_cp(A)
90+
profile_function("eigenvalues_cp", eigenvalues_cp, cp_symm_matrix)
91+
profile_function("power_method_cp", power_method_cp, cp_symm_matrix)
92+
profile_function("QR_cp", QR_cp, cp_symm_matrix, max_iter=iteration_factor * d)

shell/submit.sbatch

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,34 +31,24 @@ conda init
3131
source ~/.bashrc
3232
conda activate /scratch/ltomada/miniconda3/envs/dtsc
3333

34-
mkdir -p tmp_data experiments logs
35-
touch tmp_data/timings.csv
34+
#touch log/timings.csv
3635

37-
export LINE_PROFILE=0
38-
39-
density=0.1
36+
density=0.2
4037
tol=0.0001
4138
max_iter=1000
4239

40+
echo "function,dim,time">logs/timings.csv
4341

44-
for dim in 100 500 1000 5000; do
42+
for dim in 100 500 1000; do
4543
echo "d: $dim" # for readability
4644
echo "dim: $dim" > experiments/config.yaml
4745
echo "density: $density" >> experiments/config.yaml
4846
echo "tol: $tol" >> experiments/config.yaml
4947
echo "max_iter: $max_iter" >> experiments/config.yaml
5048

51-
python -m kernprof -l -o tmp_data/profile.dat scripts/run.py --config=experiments/config
52-
53-
if [ ! -f tmp_data/timings.csv ]; then
54-
echo "dim,function_name,time" > tmp_data/timings.csv
55-
fi
56-
57-
python -m line_profiler -rmt tmp_data/profile.dat | awk -v dim="$dim" '
58-
/Function: / {func_name=$2}
59-
/Total time:/ {if (func_name != "") print dim, func_name, $3}' OFS=',' >> tmp_data/timings.csv
49+
python scripts/profiling.py
6050

61-
echo "dim: $dim - times saved in tmp_data/timings.csv"
51+
echo "dim: $dim - times saved in logs/timings.csv"
6252
echo '--------------------------------------------------'
6353
done
6454

src/pyclassify/eigenvalues.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ def power_method_cp(A, max_iter=500, tol=1e-4, x=None):
196196
return x @ A @ x
197197

198198

199-
@jit(nopython=True)
199+
# @jit(nopython=True)
200200
def Lanczos_PRO(A, q=None, m=None, tol=1e-8):
201201
r"""
202202
Perform the Lanczos algorithm for symmetric matrices.
@@ -267,8 +267,8 @@ def Lanczos_PRO(A, q=None, m=None, tol=1e-8):
267267
return Q, np.array(alpha), np.array(beta[:-1])
268268

269269

270-
@jit(nopython=True)
271-
def QR_method(diag, off_diag, tol=1e-8, max_iter=100):
270+
# @jit(nopython=True)
271+
def QR_method(diag, off_diag, tol=1e-8, max_iter=1000):
272272
"""
273273
Compute the eigenvalues of a tridiagonal matrix using the QR algorithm.
274274
@@ -366,6 +366,8 @@ def QR_method(diag, off_diag, tol=1e-8, max_iter=100):
366366
x_new = x_0 - np.cos(x_0) * np.cos(x_0) * (
367367
np.tan(x_0) + b_2 / d
368368
)
369+
if np.isclose(x_new, 0):
370+
break
369371
err_rel = np.abs((x_new - x_0) / x_new)
370372
x_0 = x_new
371373
iter_newton += 1
@@ -394,7 +396,7 @@ def QR_method(diag, off_diag, tol=1e-8, max_iter=100):
394396

395397

396398
@profile
397-
def QR(A, q0=None, tol=1e-8, max_iter=100):
399+
def QR(A, q0=None, tol=1e-8, max_iter=1000):
398400
"""
399401
Compute the eigenvalues of a square matrix using the QR algorithm.
400402
Done using the Lanczos algorithm to compute the tridiagonal matrix and then the QR
@@ -480,12 +482,11 @@ def Lanczos_PRO_cp(A, q=None, m=None, tol=1e-8):
480482
beta.append(cp.linalg.norm(r))
481483

482484
if cp.abs(beta[j]) < 1e-15:
483-
484-
return cp.array(alpha), cp.array(beta[:-1])
485+
return Q, cp.array(alpha), cp.array(beta[:-1])
485486
return Q, cp.array(alpha), cp.array(beta[:-1])
486487

487488

488-
def QR_method_cp(diag, off_diag, tol=1e-8, max_iter=100):
489+
def QR_method_cp(diag, off_diag, tol=1e-8, max_iter=1000):
489490
"""
490491
Compute the eigenvalues of a tridiagonal matrix using the QR algorithm.
491492
@@ -568,7 +569,7 @@ def QR_method_cp(diag, off_diag, tol=1e-8, max_iter=100):
568569
s = -cp.sqrt(2) / 2
569570
else:
570571
c = s = cp.sqrt(2) / 2
571-
572+
# if off diagonal ... do nothing
572573
else:
573574
b_2 = off_diag[0]
574575
if off_diag[0] * d > 0:
@@ -582,6 +583,8 @@ def QR_method_cp(diag, off_diag, tol=1e-8, max_iter=100):
582583
x_new = x_0 - cp.cos(x_0) * cp.cos(x_0) * (
583584
cp.tan(x_0) + b_2 / d
584585
)
586+
if cp.isclose(cp.linalg.norm(x_new), 0):
587+
break
585588
err_rel = cp.abs((x_new - x_0) / x_new)
586589
x_0 = x_new
587590
iter_newton += 1
@@ -610,7 +613,7 @@ def QR_method_cp(diag, off_diag, tol=1e-8, max_iter=100):
610613

611614

612615
@profile
613-
def QR_cp(A, q0=None, tol=1e-8, max_iter=100):
616+
def QR_cp(A, q0=None, tol=1e-8, max_iter=1000):
614617
"""
615618
Compute the eigenvalues of a square matrix using the QR algorithm.
616619
Done using the Lanczos algorithm to compute the tridiagonal matrix and then the QR

test/test_.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ def test_QR_method(size):
158158

159159

160160
@pytest.mark.parametrize("size", sizes)
161-
def test_qr(size):
161+
def test_QR(size):
162162
eig = np.arange(1, size + 1)
163163
A = np.diag(eig)
164164
U = scipy.stats.ortho_group.rvs(size)

0 commit comments

Comments
 (0)