8

Ich habe eine Reihe von 2000 trainierten Random Regression Bäume (von scikit lernen Random Forest Regressor mit n_estimators=1). Das parallele Trainieren der Bäume (50 Kerne) auf einem großen Datensatz (~ 100000 * 700000 = 70 GB @ 8-Bit) unter Verwendung von multiprocessing und Shared Memory funktioniert wie ein Zauber. Beachten Sie, dass ich die integrierte Multicore-Unterstützung von RF nicht verwende, da ich die Feature-Auswahl vorher mache.verstehen scikit lernen Random Forest Speicheranforderung für die Vorhersage

Das Problem: Beim parallelen Testen einer großen Matrix (~ 20000 * 700000) habe ich immer keinen Speicher mehr (ich habe Zugriff auf einen Server mit 500 GB RAM).

Meine Strategie ist es, die Testmatrix im Speicher zu haben und sie unter allen Prozessen zu teilen. Laut einem statement by one of the developers ist die Speicheranforderung für das Testen 2 * n_jobs * sizeof (X), und in meinem Fall ist ein weiterer Faktor von * 4 relevant, da die 8bit-Matrixeinträge in RF intern float32 sind.

durch Zahlen, glaube ich für die Prüfung ich brauche:
14GB die Testmatrix im Speicher + 50 (= n_jobs) * 20000 (N_SAMPLES) * 700 (= n_features) * 4 (Upcasting zu schweben) zu halten * 2 Bytes = 14 GB + 5,6 GB = ~ 21 GB Speicher.

Dennoch explodiert es immer auf mehrere hundert GB. Was fehlt mir hier? (Ich bin auf der neuesten Version von Scikit-Learn, so dass die alten Speicherprobleme ausgebügelt werden sollen)

Eine Beobachtung:
nur auf einem Kern Laufspeichernutzung für den Test zwischen 30 und 100 GB (gemessen schwankt von free)

Mein Code:

#---------------- 
#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: eine andere Beobachtung: Wenn Chunking die Testdaten das Programm ausgeführt wird s moothly mit viel reduziertem Speicherverbrauch. Dies ist, was ich benutzt habe, um das Programm laufen zu lassen.
-Code-Schnipsel für die aktualisierte predTree Funktion:

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

Wie viel Speicher nehmen Ihre 2000 trainierten Zufallsregressionsbäume? Werden sie für jeden der 50 Kerne kopiert? –

+0

@ BrianO'Donnell meinst du die Größe des Modells? Ich habe keinen Zugriff mehr auf das Modell, aber es war definitiv überschaubar. – Dahlai

+0

Ja, die Größe des Modells. –

Antwort

0

Ich bin nicht sicher, ob das Speicherproblem nicht auf die Verwendung von itertools.izip in args = itertools.izip(models, features_idx) verwandt ist, die über alle Fäden zusammen mit seinen Argumenten Herstellung von Kopien des Iterators auslösen können . Haben Sie versucht, nur zip zu verwenden?

Eine andere Hypothese könnte ineffiziente Garbage Collection sein - nicht ausgelöst, wenn Sie es brauchen. Ich würde prüfen, ob das Laufen gc.collect() kurz vor model.predict in predTree nicht hilft.

Es gibt auch einen dritten möglichen Grund (wahrscheinlich der glaubwürdigste). Lassen Sie mich Python FAQ on How does Python manage memory? zitieren:

In aktuellen Versionen von CPython, jede neue Zuordnung zu x innerhalb der Schleife wird kurz die zuvor zugewiesenen Ressource.

In Ihrer Chunked-Funktion tun Sie genau das - wiederholt zuweisen zu pred_chunked.