Obecnie pracuję nad projektem uczenia maszynowego gdzie - danej macierzy danych Z
oraz wektor rho
- Muszę obliczyć wartość i nachylenie logistic loss function pod adresem rho
. Obliczenia obejmują podstawowe operacje mnożenia macierzy-wektora i log/exp, z trikiem, aby uniknąć przepełnienia liczbowego (opisanego w tym previous post).Przyspieszenie matrycę wektor mnożenie i potęgowanie w Pythonie, ewentualnie poprzez wywołanie C/C++
Obecnie robię to w Pythonie za pomocą NumPy, jak pokazano poniżej (jako odniesienie, ten kod działa w 0.2s). Chociaż to działa dobrze, chciałbym go przyspieszyć, ponieważ wiele razy nazywam tę funkcję w moim kodzie (i reprezentuje ona ponad 90% obliczeń związanych z moim projektem).
Szukam sposobu na poprawę środowiska wykonawczego tego kodu bez równoległego (tj. Tylko 1 procesora). Cieszę się, używając dowolnego publicznie dostępnego pakietu w Pythonie, lub wywołując C lub C++ (ponieważ słyszałem, że poprawia to runtimes o rząd wielkości). Wstępne przetwarzanie matrycy danych Z
również byłoby OK. Niektóre rzeczy, które mogłyby być wykorzystane do lepszego obliczeń są takie, że wektor rho
jest zwykle rzadki (o około 50% zgłoszeń = 0) i są zwykle daleko więcej wierszy niż kolumn (w większości przypadków 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)
Dlaczego wykluczasz więcej niż 1 procesor? Mimo że maszyna wirtualna Python jest w zasadzie pojedyncza, można wywołać wątki POSIX z poziomu rozszerzenia C po skopiowaniu danych do bardziej przyjaznej dla wątków struktury danych.Mogą istnieć inne powody, aby nie używać wielu procesorów, ale nie jesteś ograniczony tym ograniczeniem, jeśli uciekniesz do C. – rts1
@rts Dobre pytanie. W tym przypadku muszę ograniczyć go do 1 procesora, ponieważ kod, który wywołuje funkcję "compute_logistic_loss_function" jest faktycznie zrównoleglony ... Tak więc tylko 1 CPU będzie dostępny, gdy funkcja zostanie wywołana. –
Dla dużego 'n' środowisko wykonawcze zdaje się być zdominowane przez' loss_slope = Z * (phi_slope - 1.0) ', które nadaje ten sam rozmiar co' Z'. Ponieważ bierzesz średnią ponad wiersze, możesz ponownie napisać to jako produkt kropki używając 'ZTdot (phi_slope) .T/Z.shape [0]', co daje około 4 przyspieszenie na moim maszyna. –