Die Berechnung der Faltung zweier Funktionen mit FFT (FFTW)

Ich versuche zu beschleunigen, eine Berechnung für einen neuralen simulator mit Hilfe der FFT.

Ist die Gleichung:

(1) \sum(j=1 bis N) (w(i - j) * s_NMDA[j])

wo s_NMDA ist ein Vektor der Länge N und w ist definiert durch:

(2) w(j) = tanh[1/(2 * sigma * p)] * exp(-abs(j) /(sigma * p)]

wo sigma und p sind Konstanten.

(gibt es eine bessere Möglichkeit zum Rendern von Formeln auf stackoverflow?)

Die Berechnung muss durchgeführt werden, für die N Neuronen. Da (1) hängt nur von der absoluten Distanz abs(i - j), sollte es möglich sein, zu berechnen, diese mit Hilfe der FFT (convolution theorem).

Habe ich versucht, diese umsetzen mit FFTW aber die Ergebnisse passen nicht mit den erwarteten Ergebnissen. Ich habe noch nie verwendet FFTW vor und ich bin mir jetzt nicht sicher, ob meine Implementierung falsch ist, wenn meine Annahmen über das faltungs-theorem false sind.

void f_I_NMDA_FFT(
    const double     **states, //states[i][6] == s_NMDA[i]
    const unsigned int numNeurons)
{
    fftw_complex *distances, *sNMDAs, *convolution;
    fftw_complex *distances_f, *sNMDAs_f, *convolution_f;
    fftw_plan     p, pinv;
    const double scale = 1./numNeurons;

        distances = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * numNeurons);
        sNMDAs    = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * numNeurons);
        convolution = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * numNeurons);
        distances_f = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * numNeurons);
        sNMDAs_f    = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * numNeurons);
        convolution_f    = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * numNeurons);

        //fill input array for distances  
    for (unsigned int i = 0; i < numNeurons; ++i)
    {
        distances[i][0] = w(i);
        distances[i][1] = 0;
    }

        //fill input array for sNMDAs
    for (unsigned int i = 0; i < numNeurons; ++i)
    {
        sNMDAs[i][0] = states[i][6];
        sNMDAs[i][1] = 0;
    }

    p = fftw_plan_dft_1d(numNeurons,
                         distances,
                         distances_f,
                         FFTW_FORWARD,
                         FFTW_ESTIMATE);
    fftw_execute(p);

    p = fftw_plan_dft_1d(numNeurons,
                         sNMDAs,
                         sNMDAs_f,
                         FFTW_FORWARD,
                         FFTW_ESTIMATE);
    fftw_execute(p);

    //convolution in frequency domain
    for(unsigned int i = 0; i < numNeurons; ++i)
    {
        convolution_f[i][0] = (distances_f[i][0] * sNMDAs_f[i][0]
            - distances_f[i][1] * sNMDAs_f[i][1]) * scale;
        convolution_f[i][1] = (distances_f[i][0] * sNMDAs_f[i][1]
            - distances_f[i][1] * sNMDAs_f[i][0]) * scale;
    }

    pinv = fftw_plan_dft_1d(numNeurons,
                            convolution_f,
                            convolution,
                            FFTW_FORWARD,
                            FFTW_ESTIMATE);
    fftw_execute(pinv);

    //compute and compare with expected result
    for (unsigned int i = 0; i < numNeurons; ++i)
    {
            double expected = 0;

            for (int j = 0; j < numNeurons; ++j)
            {
                expected += w(i - j) * states[j][6];
            }
            printf("i=%d, FFT: r%f, i%f : Expected: %f\n", i, convolution[i][0], convolution[i][1], expected);
    }

    fftw_destroy_plan(p);
    fftw_destroy_plan(pinv);

    fftw_free(distances), fftw_free(sNMDAs), fftw_free(convolution);
    fftw_free(distances_f), fftw_free(sNMDAs_f), fftw_free(convolution_f);

Hier ist ein Beispiel für die Ausgabe für 20 Neuronen:

i=0, FFT: r0.042309, i0.000000 : Expected: 0.041504
i=1, FFT: r0.042389, i0.000000 : Expected: 0.042639
i=2, FFT: r0.042466, i0.000000 : Expected: 0.043633
i=3, FFT: r0.042543, i0.000000 : Expected: 0.044487
i=4, FFT: r0.041940, i0.000000 : Expected: 0.045203
i=5, FFT: r0.041334, i0.000000 : Expected: 0.045963
i=6, FFT: r0.041405, i0.000000 : Expected: 0.046585
i=7, FFT: r0.041472, i0.000000 : Expected: 0.047070
i=8, FFT: r0.041537, i0.000000 : Expected: 0.047419
i=9, FFT: r0.041600, i0.000000 : Expected: 0.047631
i=10, FFT: r0.041660, i0.000000 : Expected: 0.047708
i=11, FFT: r0.041717, i0.000000 : Expected: 0.047649
i=12, FFT: r0.041773, i0.000000 : Expected: 0.047454
i=13, FFT: r0.041826, i0.000000 : Expected: 0.047123
i=14, FFT: r0.041877, i0.000000 : Expected: 0.046656
i=15, FFT: r0.041926, i0.000000 : Expected: 0.046052
i=16, FFT: r0.041294, i0.000000 : Expected: 0.045310
i=17, FFT: r0.042059, i0.000000 : Expected: 0.044430
i=18, FFT: r0.042144, i0.000000 : Expected: 0.043412
i=19, FFT: r0.042228, i0.000000 : Expected: 0.042253

Scheinen die Ergebnisse zu sein, fast richtig, aber der Fehler steigt mit der Anzahl der Neuronen. Auch scheinen die Ergebnisse um genauer zu sein für die Positionen (i), die sehr niedrig oder sehr hoch. Was ist denn hier Los?

Update: Wie vorgeschlagen von Oli Charlesworth, ich implementierte den Algorithmus in octave zu sehen, ob es eine Umsetzung oder Mathe-problem:

input = [0.186775; 0.186775; 0.186775; 0.186775; 0.186775; 0; 0.186775; 0.186775; 0.186775; 0.186775];

function ret = _w(i)
  ret = tanh(1 / (2* 1 * 32)) * exp(-abs(i) / (1 * 32));
end

for i = linspace(1, 10, 10)
  expected = 0;
  for j = linspace(1, 10, 10)
    expected += _w(i-j) * input(j);
  end
  expected
end

distances = _w(transpose(linspace(0, 9, 10)));

input_f = fft(input);
distances_f = fft(distances);

convolution_f = input_f .* distances_f;

convolution = ifft(convolution_f)

Ergebnisse:

expected =  0.022959
expected =  0.023506
expected =  0.023893
expected =  0.024121
expected =  0.024190
expected =  0.024100
expected =  0.024034
expected =  0.023808
expected =  0.023424
expected =  0.022880
convolution =

   0.022959
   0.023036
   0.023111
   0.023183
   0.023253
   0.022537
   0.022627
   0.022714
   0.022798
   0.022880

Sind die Ergebnisse sehr ähnlich. Daher muss es etwas falsch mit meinem Verständnis der convolution theorem /FFT.

  • StackOverflow hat keine direkte Unterstützung für Latex. Sie können jedoch verwenden Sie eine Website wie codecogs.com/latex/eqneditor.php, die dynamisch erzeugt Bilder.
  • Für den Kern des Problems, denke ich, müssen Sie zuerst, um festzustellen, ob Sie ein Mathe-problem oder ein problem FFTW. Ich würde vorschlagen, prototyping Ihren Algorithmus in so etwas wie Matlab/Octave. Alternativ könnten Sie versuchen, die Durchführung der Berechnung mit einem naiven DFT-Algorithmus (es ist etwa 7 Zeilen code). Wenn das funktioniert, dann wissen Sie, machen Sie etwas falsch mit FFTW!
  • Vielen Dank für Ihre Anregungen. Leider kann ich keine Bilder, weil ich nicht genug Ruf noch. Ich werde versuchen, das zu implementieren einen einfachen Prototyp in die Oktave und die Ergebnisse vergleichen.
InformationsquelleAutor nebw | 2012-06-24
Schreibe einen Kommentar