1

ここでユーザーが Stackoverflow で提示したソリューションを試してみました: henry-gomersall を使用して FFT ベースの畳み込みの高速化を繰り返しましたが、異なる結果が得られました。

import numpy as np
import pyfftw
import scipy.signal
import timeit

class CustomFFTConvolution(object):

    def __init__(self, A, B, threads=1):

        shape = (np.array(A.shape) + np.array(B.shape))-1

        if np.iscomplexobj(A) and np.iscomplexobj(B):
            self.fft_A_obj = pyfftw.builders.fftn(
                    A, s=shape, threads=threads)
            self.fft_B_obj = pyfftw.builders.fftn(
                    B, s=shape, threads=threads)
            self.ifft_obj = pyfftw.builders.ifftn(
                    self.fft_A_obj.get_output_array(), s=shape,
                    threads=threads)

        else:
            self.fft_A_obj = pyfftw.builders.rfftn(
                    A, s=shape, threads=threads)
            self.fft_B_obj = pyfftw.builders.rfftn(
                    B, s=shape, threads=threads)
            self.ifft_obj = pyfftw.builders.irfftn(
                    self.fft_A_obj.get_output_array(), s=shape,
                    threads=threads)

    def __call__(self, A, B):

        fft_padded_A = self.fft_A_obj(A)
        fft_padded_B = self.fft_B_obj(B)

        return self.ifft_obj(fft_padded_A * fft_padded_B)

N = 200

A = np.random.rand(N, N, N)
B = np.random.rand(N, N, N)

start_time = timeit.default_timer()

C = scipy.signal.fftconvolve(A,B,"same")
print timeit.default_timer() - start_time

custom_fft_conv_nthreads = CustomFFTConvolution(A, B, threads=1)
C = custom_fft_conv_nthreads(A, B)
print timeit.default_timer() - start_time

PyFFTW は約です。他のユーザーの経験とは異なり、SciPy FFT よりも 7 倍遅くなります。このコードのどこが間違っていますか? Python 2.7.9、PyFFTW 0.9.2。

4

1 に答える 1

1

あなたは自分がしていると思っていることをしていないし、自分がしていると思っていることも、するべきではありません。

上記のコードは 1 回しか定義していないため、実行していると思っていることを実行していませんstart_time(したがって、pyfftw のテストには、時間のかかるCustomFFTConvolutionオブジェクトの作成だけでなく、scipy 畳み込みも含まれます!)。

timeitこの種のことをテストするために使用する必要があるため、自分がしていると思うことをするべきではありません。

だから、いくつかのファイルでfoo.py

import numpy as np
import pyfftw
import scipy.signal

class CustomFFTConvolution(object):

    def __init__(self, A, B, threads=1):

        shape = (np.array(A.shape) + np.array(B.shape))-1

        if np.iscomplexobj(A) and np.iscomplexobj(B):
            self.fft_A_obj = pyfftw.builders.fftn(
                    A, s=shape, threads=threads)
            self.fft_B_obj = pyfftw.builders.fftn(
                    B, s=shape, threads=threads)
            self.ifft_obj = pyfftw.builders.ifftn(
                    self.fft_A_obj.get_output_array(), s=shape,
                    threads=threads)

        else:
            self.fft_A_obj = pyfftw.builders.rfftn(
                    A, s=shape, threads=threads)
            self.fft_B_obj = pyfftw.builders.rfftn(
                    B, s=shape, threads=threads)
            self.ifft_obj = pyfftw.builders.irfftn(
                    self.fft_A_obj.get_output_array(), s=shape,
                    threads=threads)

    def __call__(self, A, B):

        fft_padded_A = self.fft_A_obj(A)
        fft_padded_B = self.fft_B_obj(B)

        return self.ifft_obj(fft_padded_A * fft_padded_B)

N = 200

A = np.random.rand(N, N, N)
B = np.random.rand(N, N, N)

ipython では、以下を取得できます。

In [1]: %run foo.py

In [2]: timeit scipy.signal.fftconvolve(A,B,"same")
1 loops, best of 3: 8.38 s per loop

In [3]: custom_fft_conv_nthreads = CustomFFTConvolution(A, B, threads=1)

In [4]: timeit custom_fft_conv_nthreads(A, B)
1 loops, best of 3: 6.9 s per loop

複数のスレッドを使用する場合:

In [5]: custom_fft_conv_nthreads = CustomFFTConvolution(A, B, threads=4)

In [6]: timeit custom_fft_conv_nthreads(A, B)
1 loops, best of 3: 3.81 s per loop

start_time = timeit.default_timer()beforeを挿入して、コードが実行していると思われることを実行するようにコードを修正するとC = custom_fft_conv_nthreads(A, B)、予想に近いものが得られます。

10.8795630932
8.31241607666
于 2015-06-03T09:02:02.077 に答える