Ускорение умножения и возведения в степень матрицы-вектора в Python, возможно, путем вызова C / C ++

В настоящее время я работаю над проектом машинного обучения, где - с учетом матрицы данныхZ и векторrho - Я должен вычислить значение и наклонфункция логистических потерь вrho, Вычисление включает в себя базовое умножение матрицы на вектор и операции log / exp, с хитростью, чтобы избежать числового переполнения (описано в этомпредыдущий пост).

В настоящее время я делаю это в Python, используя NumPy, как показано ниже (в качестве ссылки, этот код выполняется в 0.2 с). Хотя это работает хорошо, я хотел бы ускорить его, так как я вызываю функцию несколько раз в своем коде (и это составляет более 90% вычислений, задействованных в моем проекте).

Я ищу любой способ улучшить время выполнения этого кода без распараллеливания (то есть только 1 процессор). Я счастлив использовать любой общедоступный пакет в Python или вызывать C или C ++ (так как я слышал, что это улучшает время выполнения на порядок). Предварительная обработка матрицы данныхZ также будет хорошо. Некоторые вещи, которые могут быть использованы для лучшего вычисления, это то, что векторrho обычно редко (около 50% записей = 0) и обычнодалеко больше строк, чем столбцов (в большинстве случаев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)

Ответы на вопрос(2)

Ваш ответ на вопрос