Andata e Ritorno… un Racconto RAPIDS

Andata e Ritorno - a RAPIDS Story.

Questo post del blog esplora le sfide nell’acquisizione di dati sufficienti e le limitazioni poste dai dataset tendenziosi utilizzando RapidsAI cuDF.

Di Kris Manohar e Kevin Baboolal

Nota dell’editore: Siamo entusiasti di annunciare che questo post è stato selezionato come vincitore del Nisoo & NVIDIA’s Blog Writing Contest.

Introduzione

Il machine learning ha rivoluzionato vari ambiti sfruttando grandi quantità di dati. Tuttavia, ci sono situazioni in cui l’acquisizione di dati sufficienti diventa una sfida a causa del costo o della scarsità. In tali casi, gli approcci tradizionali spesso faticano a fornire previsioni accurate. Questo post esplora le limitazioni poste dai piccoli set di dati e svela una soluzione innovativa proposta da TTLAB che sfrutta il potere dell’approccio dei vicini più vicini e un kernel specializzato. Approfondiremo i dettagli del loro algoritmo, i suoi vantaggi e come l’ottimizzazione GPU accelera la sua esecuzione.

La sfida dei dati limitati

Nel machine learning, avere una quantità sostanziale di dati è cruciale per addestrare modelli precisi. Tuttavia, quando ci si trova di fronte a un piccolo set di dati composto solo da poche centinaia di righe, i limiti diventano evidenti. Un problema comune è il problema della frequenza zero incontrato in alcuni algoritmi di classificazione come il classificatore di Bayes ingenuo. Ciò si verifica quando l’algoritmo incontra un valore di categoria non visto durante il test, portando a una stima della probabilità zero per quel caso. Allo stesso modo, i compiti di regressione affrontano sfide quando il set di test contiene valori che erano assenti nel set di addestramento. Potresti persino scoprire che la tua scelta di algoritmo è migliorata (sebbene subottimale) quando queste funzionalità mancanti sono escluse. Questi problemi si manifestano anche in set di dati più grandi con classi altamente sbilanciate.

Superare la scarsità di dati

Anche se le suddivisioni di addestramento-test spesso mitigano questi problemi, rimane un problema nascosto quando si tratta di set di dati più piccoli. Forzare un algoritmo a generalizzare basandosi su meno campioni può portare a previsioni subottimali. Anche se l’algoritmo funziona, le sue previsioni possono mancare di robustezza e accuratezza. La semplice soluzione di acquisire più dati non è sempre fattibile a causa di vincoli di costo o disponibilità. In tali situazioni, un approccio innovativo proposto da TTLAB si dimostra robusto e accurato.

L’algoritmo TTLAB

L’algoritmo di TTLAB affronta le sfide poste dai set di dati limitati e tendenziosi. Il loro approccio prevede di prendere la media ponderata di tutte le righe nel set di dati di addestramento per prevedere il valore per una variabile target in un campione di test. La chiave sta nell’aggiustare i pesi di ogni riga di addestramento per ogni riga di test, basandosi su una funzione non lineare parametrizzata che calcola la distanza tra due punti nello spazio delle caratteristiche. Anche se la funzione di pesatura utilizzata ha un singolo parametro (il tasso di decadimento dell’influenza di un campione di addestramento all’aumentare della sua distanza dal campione di test), lo sforzo di calcolo per ottimizzare su questo parametro potrebbe essere grande. Considerando l’intero set di dati di addestramento, l’algoritmo fornisce previsioni robuste. Questo approccio ha mostrato un notevole successo nel migliorare le prestazioni di modelli popolari come le foreste casuali e il Bayes ingenuo. Poiché l’algoritmo sta diventando sempre più popolare, sono in corso sforzi per migliorarne ulteriormente l’efficienza. L’implementazione attuale prevede di sintonizzare l’iperparametro kappa, che richiede una ricerca a griglia. Per accelerare questo processo, si sta esplorando una successiva approssimazione quadratica, promettendo una più rapida ottimizzazione dei parametri. Inoltre, le revisioni tra pari in corso mirano a convalidare e raffinare l’algoritmo per una più ampia adozione.

Per implementare l’algoritmo TTLAB per la classificazione, i cicli e numpy si sono dimostrati inefficienti, dando luogo a tempi di esecuzione molto lunghi. L’implementazione della CPU presentata nella pubblicazione collegata si concentra sui problemi di classificazione, dimostrando la versatilità ed efficacia dell’approccio. https://arxiv.org/pdf/2205.14779.pdf . La pubblicazione mostra anche che l’algoritmo beneficia enormemente dalla vettorizzazione, suggerendo ulteriori miglioramenti di velocità che possono essere ottenuti dall’accelerazione GPU con CuPy. Infatti, per eseguire la sintonizzazione degli iperparametri e i K-fold casuali per la convalida dei risultati avrebbero impiegato settimane per la moltitudine di set di dati testati. Sfruttando la potenza delle GPU, i calcoli sono stati distribuiti in modo efficace, garantendo un miglioramento delle prestazioni.

Accelerazione dell’esecuzione con le GPU

Anche con ottimizzazioni come la vettorizzazione e la rifattorizzazione di .apply, il tempo di esecuzione rimane impraticabile per le applicazioni del mondo reale. Tuttavia, con l’ottimizzazione GPU, il tempo di esecuzione viene drasticamente ridotto, portando i tempi di esecuzione da ore a minuti. Questa notevole accelerazione apre possibilità per l’utilizzo dell’algoritmo in scenari in cui i risultati tempestivi sono essenziali.

Dopo aver appreso le lezioni dall’implementazione della CPU, abbiamo cercato di ottimizzare ulteriormente la nostra implementazione. Per questo, siamo saliti al livello di CuDF Dataframes. La vettorizzazione dei calcoli sulla GPU è un gioco da ragazzi con CuDF. Per noi, è stato sufficiente cambiare import pandas in import CuDF (è necessario vettorizzare correttamente in pandas.)

train_df["sum_diffs"] = 0
train_df["sum_diffs"] = train_df[diff_cols].sum(axis=1).values
train_df["d"] = train_df["sum_diffs"] ** 0.5
train_df["frac"] = 1 / (1 + train_df["d"]) ** kappa
train_df["part"] = train_df[target_col] * train_df["frac"]
test_df.loc[index, "pred"] = train_df["part"].sum() / train_df["frac"].sum()

Inoltre, più in profondità nella questione, dobbiamo fare affidamento sui kernel Numba. A questo punto, le cose diventano complicate. Ricordiamo perché le previsioni dell’algoritmo sono robuste perché ogni previsione utilizza tutte le righe nel dataframe di addestramento. Tuttavia, i kernel Numba non supportano il passaggio dei dataframe CuDF. Al momento stiamo sperimentando alcuni trucchi suggeriti su Github per gestire questo caso. ( https://github.com/rapidsai/cudf/issues/13375 )

Per ora, possiamo almeno passare il calcolo grezzo a un kernel numba tramite il .apply_rows

def predict_kernel(F, T, numer, denom, kappa):
    for i, (x, t) in enumerate(zip(F, T)):
        d = abs(x - t)  # la misura della distanza
        w = 1 / pow(d, kappa)  # parametrizzare la scala non lineare
        numer[i] = w
        denom[i] = d


_tdf = train_df[[att, target_col]].apply_rows(
    predict_kernel,
    incols={att: "F", "G3": "T"},
    outcols={"numer": np.float64, "denom": np.float64},
    kwargs={"kappa": kappa},
)

p = _tdf["numer"].sum() / _tdf["denom"].sum()  # previsione - media ponderata

A questo punto, non abbiamo eliminato tutti i cicli for, ma semplicemente spingendo la maggior parte dei calcoli numerici in Numba, abbiamo ridotto il tempo di esecuzione di CuDf > 50% portandoci intorno ai 2-4 secondi per lo standard 80-20 train-test split.

Conclusione

È stato un viaggio entusiasmante e delizioso esplorare le capacità delle librerie rapids, cupy e cudf per diverse attività di machine learning. Queste librerie si sono dimostrate user-friendly ed facilmente comprensibili, rendendole accessibili alla maggior parte degli utenti. Il design e la manutenzione di queste librerie sono encomiabili, permettendo agli utenti di approfondire le complessità quando necessario. In poche ore al giorno nel corso di una settimana, siamo riusciti a passare da novizi a spingere i confini della libreria implementando un algoritmo di previsione altamente personalizzato. Il nostro obiettivo successivo è raggiungere una velocità senza precedenti, mirando a superare la barriera del microsecondo con grandi dataset che vanno dai 20K ai 30K. Una volta raggiunto questo traguardo, abbiamo intenzione di rilasciare l’algoritmo come pacchetto pip alimentato da rapids, rendendolo disponibile per una più ampia adozione e utilizzo.

Kris Manohar è un direttore esecutivo presso ICPC, Trinidad e Tobago.