Algoritmi per il calcolo di FFT in parallelo


12

Sto cercando di parallelizzare il calcolo di una FFT su file di segnale di dimensioni terabyte. In questo momento un tale FFT che utilizza una libreria open source richiede molte ore, anche passando attraverso CUDA sulla GPU più veloce che ho. Il framework che sto cercando di adattare a questo processo è Hadoop. In termini molto basilari, Hadoop distribuisce un problema su un numero qualsiasi di nodi server nel modo seguente:

• È stato suddiviso il file di input in coppie (chiave, valore).
• Queste coppie vengono inserite in un algoritmo "Mappa", che trasforma le tue coppie (chiave, valore) in alcune altre coppie (chiave, valore) in base a ciò che inserisci nella mappa.
• Il framework raccoglie quindi tutti gli output (chiave, valore) dalle mappe e li ordina per chiave, nonché aggregando i valori con la stessa chiave in una singola coppia, quindi si finisce con (chiave, elenco (valore1, valore2, ..)) coppie
• Queste coppie vengono quindi inserite in un algoritmo di "Riduzione", che a sua volta genera più coppie (chiave, valore) come risultato finale (scritto in un file).

Esistono molte applicazioni per questo modello in cose pratiche come l'elaborazione dei registri del server, ma non riesco ad applicare il framework per tagliare una FFT in attività di "mappa" e "riduzione", soprattutto perché non ho familiarità con DSP.

Non ti darò fastidio con il jumbo mumbo di programmazione, poiché si tratta di domande e risposte DSP. Sono, tuttavia, confuso su quali algoritmi esistono per il calcolo di FFT in parallelo; Le attività di mappatura e riduzione non possono (tecnicamente) parlare tra loro, quindi la FFT deve essere suddivisa in problemi indipendenti dai quali i risultati possono in qualche modo essere ricombinati alla fine.

Ho programmato una semplice implementazione di Cooley-Tukey Radix 2 DIT che funziona su piccoli esempi, ma usarlo per il calcolo ricorsivo di DFT su indici dispari / pari per un miliardo di byte non funzionerà. Ho trascorso alcune settimane a leggere molti articoli, incluso uno su un algoritmo MapReduce FFT (scritto da Tsz-Wo Sze come parte del suo articolo sulla moltiplicazione SSA, non riesco a collegare più di 2 collegamenti ipertestuali) e il "FFT a quattro fasi" ( qui e qui), che sembrano simili tra loro e a ciò che sto cercando di realizzare. Tuttavia, sono irrimediabilmente cattivo in matematica e l'applicazione manuale di uno di questi metodi a un semplice insieme di qualcosa come {1,2, 3, 4, 5, 6, 7, 8} (con tutti i componenti immaginari pari a 0) dà risultati selvaggiamente errati. Qualcuno può spiegarmi un algoritmo FFT parallelo efficiente in un inglese semplice (uno che ho collegato o altro) in modo da poter provare a programmarlo?

Modifica: Jim Clay e chiunque altro possa essere confuso dalla mia spiegazione, sto provando a fare una sola FFT del file terabyte. Ma voglio poterlo fare contemporaneamente su più server per accelerare il processo.


1
Cosa stai esattamente cercando di realizzare? Vuoi fare un singolo FFT del file di segnale terabyte o più FFT più piccoli di ciascun file?
Jim Clay,

Risposte:


13

Penso che il tuo problema principale non sia come parallelizzare l'algoritmo (che in realtà può essere fatto) ma è la precisione numerica. Le FFT di dimensioni così grandi sono numericamente piuttosto complicate. I coefficienti FFT sono nella forma e se N è molto grande il calcolo del coefficiente diventa rumoroso. Diciamo che hai e usi l'aritmetica a doppia precisione a 64 bit. I primi 1000 coefficienti hanno una parte reale che è esattamente l'unità (anche se non dovrebbe essere così), quindi avrai bisogno di una matematica di precisione più elevata, che è molto inefficiente e ingombrante da usare. N=240ej2πkNN=240

Accumulerai anche molti errori di arrotondamento e troncamento poiché anche il numero di operazioni che vanno in un singolo numero di output è molto elevato. A causa della natura "ogni uscita dipende da ogni ingresso" della FFT, la propagazione degli errori è dilagante.

Non sono a conoscenza di un modo semplice per aggirare questo. La tua richiesta è insolita. La maggior parte delle applicazioni che eseguono analisi spettrali di set di dati di grandi dimensioni eseguono un'analisi in esecuzione in cui non si riscontra questo problema. Forse se riesci a descrivere la tua applicazione e i suoi vincoli, ma ancora di più, possiamo indicarti una soluzione più adatta.


Abbastanza un punto valido .. Dovrò pensare di più a questo. Forse ricorrere a una "analisi in corso" alla fine, come dici tu.
Philipp

So di essere molto in ritardo, ma per caso hai una fonte su come può essere fatto, dal momento che hai detto che può essere fatto?
Claudio Brasser,

4

Invece di provare a riscrivere la FFT potresti provare a usare un'implementazione FFT esistente (come la FFTW per esempio) e applicarla ripetutamente lungo la lunghezza del tuo segnale (non importa quanto sia grande) attraverso la sovrapposizione-add o overlap- salvare i metodi. Ciò è possibile esprimendo la FFT come una convoluzione .

Questi FFT di lunghezza inferiore non devono comunicare tra loro e l'intero schema corrisponde ai passaggi di riduzione della mappa.

In generale, quello che ti aspetteresti di fare è di dividere il segnale X in segmenti più piccoli che potrebbero anche essere sovrapposti (ad esempio X [0:10], X [5:15], X [10:20] ... .). Eseguire la FFT su questi piccoli segmenti e ricombinarli alla fine per produrre quello finale. Questo si adatta molto bene agli operatori di riduzione delle mappe.

Durante la "mappa" è possibile generare coppie (chiave, valore) con la "chiave" che rappresenta un ID sequenziale di ciascun segmento (0,1,2,3,4,5, ....) e il "valore" è il INDICE (o posizione del file) del primo valore di un segmento nel file del segnale. Quindi, ad esempio, se il tuo file è pieno di INT32, allora l'indice del secondo segmento (sopra) è a 5 * sizeof (INT32). (O se è in qualsiasi altro formato potresti avere una lib per questo)

Ora, ogni lavoratore riceve una (chiave, valore) apre un file, cerca nel punto giusto, legge M campioni da esso (dove M è 10 sopra), esegue la FFT e lo salva in un file con un nome, ad esempio " RES_ [INKEY] .dat "e restituisce una coppia (chiave, valore). In questo caso, "chiave" sarebbe l'INDICE (il "valore" della tupla in entrata (chiave, valore)) e "valore" sarebbe il nome del file che contiene i risultati FFT. (torneremo su questo)

All'interno di "riduci" è ora possibile implementare la sovrapposizione-aggiunta o la sovrapposizione-salvataggio accettando un (chiave, valore) dal passaggio "mappa", aprendo quel file, caricando i risultati FFT, facendo o o os e salvandoli in l'INDICE giusto nel file di output. (Vedi pseudocodice in questa (o in questa ), la fase "map" gestisce in parallelo "yt = ..." e la fase "riduci" gestisce la parte "y (i, k) = ...".)

Alcuni file giocoleria potrebbero essere necessari qui per ridurre il traffico sulla rete o il carico di un server che potrebbe contenere il tuo file di dati effettivo.


1
Non sono sicuro della validità di overlap-add e overlap-save per combinare i pezzi più piccoli per recuperare la FFT di dimensioni maggiori - per quanto ne so è necessario un secondo passaggio di FFT per farlo (un DFT di una dimensione N = AB può essere suddiviso in DFT A di dimensione B, applicazione a fattore doppio, quindi DFT B di dimensione A). Potrebbe funzionare se vogliamo un output con una risoluzione inferiore ...
Pichenettes,

Ciao picenettes, grazie per questo, quello che avevo in mente era questo ( engineeringproductivitytools.com/stuff/T0001/PT11.HTM ) che includerò nella risposta.
A_A,

2

Supponiamo che la dimensione dei dati è . Pad con zeri altrimenti. Nel tuo caso, dal momento che menzioni le dimensioni "scala in Terabyte", prenderemo N = 40.2N

Poiché è una dimensione FFT grande, ma assolutamente ragionevole per una singola macchina, ti consiglio di fare solo una singola iterazione Cooley-Tukey di radix , e quindi lasciare una libreria FFT corretta (come FFTW) esegue il lavoro su ogni macchina per dimensioni inferiori .2N/2N/22N/2

Per essere più espliciti, non è necessario utilizzare la RM durante l'intera ricorsione, questo sarà piuttosto inefficiente. Il tuo problema può essere suddiviso in un milione di FFT interni ed esterni di dimensioni megabyte e questi FFT megabyte possono essere calcolati perfettamente utilizzando FFTW o simili. MR sarà solo responsabile della supervisione dello shuffle e della ricombinazione dei dati, non dell'effettivo calcolo FFT ...

La mia prima idea sarebbe la seguente, ma sospetto che ciò possa essere fatto in un singolo MR con una rappresentazione dei dati più intelligente.

Sia tuo segnale di input,sR=2N/2

Primo MR: interno FFT

Mappa: esegue la decimazione nel tempo, raggruppa i campioni in blocchi per la FFT interna

input: dove è l'indice di esempio in ; il valore assunto da(k,v)k0..2N1vs[k]

emit: - dove% rappresenta la divisione modulo e / integer.(k%R,(k/R,v))

Ridurre: calcolare FFT interno

input: dove è l'indice del blocco; e è un elenco di coppie(k,vs)kvs(i,v)

compilare un vettore di dimensioni tale che per tutti i valori nell'elenco.inRin[i]=v

eseguire una dimensione FFT per ottenere un vettore di dimensioniRinoutR

per in , emettii0..R1(k,(i,out[i]))

Secondo MR: FFT esterno

Mappa: raggruppa campioni per fft esterno e applica i fattori di twiddle

input: dove è un indice di blocco, un campione della FFT interna per questo blocco.(k,(i,v))k(i,v)

emit(i,(k,v×exp2πjik2N))

Riduzione: esegue la FFT esterna

input: dove è l'indice del blocco; e è un elenco di coppiek v s ( i , v )(k,vs)kvs(i,v)

compilare un vettore di dimensioni tale che per tutti i valori nell'elenco.R i n [ i ] = vinRin[i]=v

eseguire una dimensione FFT per ottenere un vettore di dimensionii n o u t RRinoutR

per in , emetti0 . . R - 1 ( i × R + k , o u t [ i ] ) )i0..R1(i×R+k,out[i]))

Prova del concetto di codice python qui.

Come puoi vedere, i Mapper stanno solo mescolando l'ordine dei dati, quindi con i seguenti presupposti:

  • la decimazione nel tempo (Mapper 1) può essere effettuata in un passaggio precedente (ad esempio dal programma che converte i dati nel giusto formato di input).
  • il tuo framework MR supporta i riduttori che scrivono su una chiave diversa dalla loro chiave di input (nell'implementazione di Google i riduttori possono solo trasmettere i dati alla stessa chiave in cui li hanno ricevuti, penso che sia dovuto al fatto che SSTable viene utilizzato come formato di output).

Tutto ciò può essere fatto in un singolo MR, la FFT interna nel mappatore, la FFT esterna nel riduttore. Prova del concetto qui .


La tua implementazione sembra promettente e la sto attraversando proprio ora, ma nel riduttore FFT interno, scrivi "esegui una dimensione 2 ^ R FFT su in per ottenere un vettore fuori dalla dimensione 2 ^ R". Se R è 2 ^ (N / 2), questo FFT non sarebbe di dimensioni 2 ^ (2 ^ N / 2) e quindi errato? Intendevi FFT di taglia R?
Philipp

Sì, sembra che abbia mischiato e in alcuni punti ... modificato. Nota che il commento di Hilmar si applica al mio approccio: dovrai usare una precisione maggiore rispetto al doppio, altrimenti alcuni dei fattori di twiddle ( ) avranno una parte reale di 1 mentre non dovrebbero avere - portando a imprecisioni numeriche. 2 R exp - 2 π j i kR2Rexp2πjik2N
Pichenettes,

0

Se il tuo segnale è multidimensionale, la parallelizzazione della FFT può essere realizzata abbastanza facilmente; mantenere una dimensione contigua in un processo MPI, eseguire la FFT e trasporre (tutto sommato) per lavorare sulla dimensione successiva. FFTW fa questo.

Se i dati sono 1D, il problema è molto più difficile. FFTW, ad esempio, non ha scritto un FFT 1D usando MPI. Se si utilizza un algoritmo di decimazione in frequenza radix-2, i primi pochi stadi possono essere eseguiti come un DFT ingenuo, consentendo di utilizzare 2 o 4 nodi senza alcuna perdita di precisione (questo perché le radici dell'unità per il le prime fasi sono -1 o i, che sono belle con le quali lavorare).

Per inciso, cosa hai intenzione di fare con i dati dopo averli trasformati? Potrebbe essere fare qualcosa se si sa cosa succede all'output (cioè una convoluzione, un filtro passa-basso, ecc.).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.