8

Ho un set di 2000 alberi di regressione randomizzati addestrati (da Regolatore forestale casuale di scikit learn con n_estimators=1). Addestrando gli alberi in parallelo (50 core) su un set di dati di grandi dimensioni (~ 100000 * 700000 = 70 GB a 8 bit) utilizzando multiprocessing e la memoria condivisa funziona come un incantesimo. Nota, non sto utilizzando il supporto multicore integrato di RF poiché sto facendo la selezione delle funzioni in anticipo.Scikit di comprensione impara i requisiti di memoria di Foresta casuale per la previsione

Il problema: durante il test di una matrice di grandi dimensioni (~ 20000 * 700000) in parallelo, ho sempre esaurito la memoria (ho accesso a un server con 500 GB di RAM).

La mia strategia è di avere la matrice di test in memoria e condividerla tra tutti i processi. Secondo uno statement by one of the developers il requisito di memoria per il test è 2 * n_jobs * sizeof (X), e nel mio caso un altro fattore di * 4 è rilevante, dal momento che le voci della matrice a 8 bit sono trasmesse a float32 internamente in RF.

dai numeri, Credo per la prova ho bisogno:
14GB per tenere la matrice di test in memoria + 50 (= n_jobs) * 20000 (N_SAMPLES) * 700 (= n_features) * 4 (upcasting galleggiare) * 2 byte = 14 GB + 5,6 GB = ~ 21 GB di memoria.

Tuttavia, si verificano sempre diverse centinaia di GB. Cosa mi manca qui? (sono sulla nuova versione di scikit-learn, in modo che i vecchi problemi di memoria dovrebbero essere appianate)

Un'osservazione:
esecuzione su un core solo l'utilizzo della memoria per i test oscilla tra 30 e 100 GB (come misurato da free)

il mio codice:

#---------------- 
#helper functions 
def initializeRFtest(*args): 
    global df_test, pt_test #initialize test data and test labels as globals in shared memory 
    df_test, pt_test = args 


def star_testTree(model_featidx): 
    return predTree(*model_featidx) 

#end of helper functions 
#------------------- 

def RFtest(models, df_test, pt_test, features_idx, no_trees): 
    #test trees in parallel 
    ncores = 50 
    p = Pool(ncores, initializer=initializeRFtest, initargs=(df_test, pt_test)) 
    args = itertools.izip(models, features_idx) 
    out_list = p.map(star_testTree, args) 
    p.close() 
    p.join() 
    return out_list 

def predTree(model, feat_idx): 
    #get all indices of samples that meet feature subset requirement 
    nan_rows = np.unique(np.where(df_test.iloc[:,feat_idx] == settings.nan_enc)[0]) 
    all_rows = np.arange(df_test.shape[0]) 
    rows = all_rows[np.invert(np.in1d(all_rows, nan_rows))] #discard rows with missing values in the given features 

    #predict 
    pred = model.predict(df_test.iloc[rows,feat_idx]) 
    return predicted 

#main program 
out = RFtest(models, df_test, pt_test, features_idx, no_trees) 

Edit: un'altra osservazione: Quando suddivisione in blocchi i dati di test viene eseguito il programma s moothly con un utilizzo della memoria molto ridotto. Questo è quello che usavo per far funzionare il programma.
Codice frammento per la funzione di aggiornamento predTree:

def predTree(model, feat_idx): 
    # get all indices of samples that meet feature subset requirement 
    nan_rows = np.unique(np.where(test_df.iloc[:,feat_idx] == settings.nan_enc)[0]) 
    all_rows = np.arange(test_df.shape[0]) 
    rows = all_rows[np.invert(np.in1d(all_rows, nan_rows))] #discard rows with missing values in the given features 

    # predict height per valid sample 
    chunksize = 500 
    n_chunks = np.int(math.ceil(np.float(rows.shape[0])/chunksize)) 


    pred = [] 
    for i in range(n_chunks): 
     if n_chunks == 1: 
      pred_chunked = model.predict(test_df.iloc[rows[i*chunksize:], feat_idx]) 
      pred.append(pred_chunked) 
      break 
     if i == n_chunks-1: 
      pred_chunked = model.predict(test_df.iloc[rows[i*chunksize:], feat_idx]) 
     else: 
      pred_chunked = model.predict(test_df.iloc[rows[i*chunksize:(i+1)*chunksize], feat_idx]) 
     print pred_chunked.shape 
     pred.append(pred_chunked) 
    pred = np.concatenate(pred) 

    # populate matrix 
    predicted = np.empty(test_df.shape[0]) 
    predicted.fill(np.nan) 
    predicted[rows] = pred 
    return predicted 
+0

Quanta memoria occupano gli alberi di regressione casuale addestrati a 2000? Vengono copiati per ciascuno dei 50 core? –

+0

@ BrianO'Donnell intendi le dimensioni del modello? Non ho più accesso al modello, ma era di dimensioni decisamente gestibili. – Dahlai

+0

Sì, la dimensione del modello. –

risposta

0

Non sono sicuro se il problema di memoria non è correlato all'uso di itertools.izip in args = itertools.izip(models, features_idx) che possono innescare la creazione di copie del iteratore insieme con i suoi argomenti in tutte le discussioni . Hai provato a usare solo zip?

Un'altra ipotesi potrebbe essere la garbage collection inefficiente - non attivata quando ne hai bisogno. Vorrei verificare se l'esecuzione di poco prima di model.predict in predTree non aiuta.

C'è anche un terzo motivo potenziale (probabilmente il più credibile). Citerò Python FAQ on How does Python manage memory?:

Nelle versioni attuali di CPython, ogni nuova assegnazione ad x all'interno del ciclo rilascerà la risorsa precedentemente allocato.

Nella funzione Chunked si esegue esattamente questo - assegnando ripetutamente a pred_chunked.