Acelerar la multiplicación y exponenciación de vectores de matriz en Python, posiblemente llamando a C / C ++

Actualmente estoy trabajando en un proyecto de aprendizaje automático donde, dada una matriz de datosZ y un vectorrho - Tengo que calcular el valor y la pendiente de lafunción de pérdida logística arho. El cálculo involucra la multiplicación básica de matriz-vector y las operaciones log / exp, con un truco para evitar el desbordamiento numérico (descrito en estePublicación anterior)

Actualmente estoy haciendo esto en Python usando NumPy como se muestra a continuación (como referencia, este código se ejecuta en 0.2s). Aunque esto funciona bien, me gustaría acelerarlo ya que llamo a la función varias veces en mi código (y representa más del 90% de la computación involucrada en mi proyecto).

Estoy buscando cualquier forma de mejorar el tiempo de ejecución de este código sin paralelización (es decir, solo 1 CPU). Estoy contento de usar cualquier paquete disponible públicamente en Python, o llamar a C o C ++ (ya que he oído que esto mejora los tiempos de ejecución en un orden de magnitud). Preprocesando la matriz de datosZ También estaría bien. Algunas cosas que podrían explotarse para una mejor computación son que el vectorrho generalmente es escaso (con alrededor del 50% de las entradas = 0) y generalmente haylejos más filas que columnas (en la mayoría de los casosn_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)

Respuestas a la pregunta(2)

Su respuesta a la pregunta