Tôi hiện đang làm việc trên một dự án học máy nơi - được cung cấp ma trận dữ liệu Z
và vector rho
- Tôi phải tính toán giá trị và độ dốc của số logistic loss function tại số rho
. Tính toán liên quan đến phép nhân ma trận-vector cơ bản và các hoạt động log/exp, với một thủ thuật để tránh tràn số (được mô tả trong số previous post) này.Tăng tốc phép nhân-vector và lũy thừa trong Python, có thể bằng cách gọi C/C++
Tôi hiện đang thực hiện việc này bằng Python bằng cách sử dụng NumPy như được hiển thị bên dưới (dưới dạng tham chiếu, mã này chạy bằng 0,2 giây). Mặc dù điều này hoạt động tốt, tôi muốn tăng tốc độ nó kể từ khi tôi gọi hàm nhiều lần trong mã của tôi (và nó đại diện cho hơn 90% tính toán liên quan đến dự án của tôi).
Tôi đang tìm bất kỳ cách nào để cải thiện thời gian chạy của mã này mà không cần song song (nghĩa là chỉ có 1 CPU). Tôi rất vui khi sử dụng bất kỳ gói công khai nào có sẵn trong Python, hoặc gọi C hoặc C++ (vì tôi đã nghe nói rằng điều này cải thiện thời gian hoạt động theo thứ tự độ lớn). Tiền xử lý ma trận dữ liệu Z
cũng sẽ ổn. Một số điều có thể được khai thác để tính toán tốt hơn là rằng vector rho
thường là thưa thớt (với khoảng 50% các mục = 0) và thường có xa hơn hàng hơn cột (trong hầu hết trường hợp n_cols <= 100
)
import time
import numpy as np
np.__config__.show() #make sure BLAS/LAPACK is being used
np.random.seed(seed = 0)
#initialize data matrix X and label vector Y
n_rows, n_cols = 1e6, 100
X = np.random.random(size=(n_rows, n_cols))
Y = np.random.randint(low=0, high=2, size=(n_rows, 1))
Y[Y==0] = -1
Z = X*Y # all operations are carried out on Z
def compute_logistic_loss_value_and_slope(rho, Z):
#compute the value and slope of the logistic loss function in a way that is numerically stable
#loss_value: (1 x 1) scalar = 1/n_rows * sum(log(1 .+ exp(-Z*rho))
#loss_slope: (n_cols x 1) vector = 1/n_rows * sum(-Z*rho ./ (1+exp(-Z*rho))
#see also: https://stackoverflow.com/questions/20085768/
scores = Z.dot(rho)
pos_idx = scores > 0
exp_scores_pos = np.exp(-scores[pos_idx])
exp_scores_neg = np.exp(scores[~pos_idx])
#compute loss value
loss_value = np.empty_like(scores)
loss_value[pos_idx] = np.log(1.0 + exp_scores_pos)
loss_value[~pos_idx] = -scores[~pos_idx] + np.log(1.0 + exp_scores_neg)
loss_value = loss_value.mean()
#compute loss slope
phi_slope = np.empty_like(scores)
phi_slope[pos_idx] = 1.0/(1.0 + exp_scores_pos)
phi_slope[~pos_idx] = exp_scores_neg/(1.0 + exp_scores_neg)
loss_slope = Z.T.dot(phi_slope - 1.0)/Z.shape[0]
return loss_value, loss_slope
#initialize a vector of integers where more than half of the entries = 0
rho_test = np.random.randint(low=-10, high=10, size=(n_cols, 1))
set_to_zero = np.random.choice(range(0,n_cols), size =(np.floor(n_cols/2), 1), replace=False)
rho_test[set_to_zero] = 0.0
start_time = time.time()
loss_value, loss_slope = compute_logistic_loss_value_and_slope(rho_test, Z)
print "total runtime = %1.5f seconds" % (time.time() - start_time)
Tại sao bạn loại trừ nhiều hơn 1 CPU? Mặc dù Python VM về cơ bản là một luồng đơn, bạn có thể gọi các chủ đề POSIX từ bên trong một phần mở rộng C sau khi bạn sao chép dữ liệu vào một cấu trúc dữ liệu thân thiện với luồng hơn.Có thể có các lý do khác không sử dụng nhiều CPU, nhưng bạn không bị hạn chế bởi giới hạn đó nếu bạn thoát khỏi C. – rts1
@rts Câu hỏi hay. Trong trường hợp này, tôi cần giới hạn nó thành 1 CPU vì mã gọi 'compute_logistic_loss_function' thực sự được song song ... Vì vậy, chỉ có 1 CPU sẽ có sẵn khi hàm được gọi. –
Đối với 'n' lớn, thời gian chạy dường như bị chi phối bởi' loss_slope = Z * (phi_slope - 1.0) ', nó phát ra cùng kích thước với' Z'. Vì bạn đang sử dụng các hàng trung bình, bạn có thể viết lại nó dưới dạng sản phẩm dấu chấm bằng cách sử dụng 'ZTdot (phi_slope) .T/Z.shape [0]', mang lại hệ số 4 tốc độ trên máy móc. –