私が行っているいくつかの計算作業をプロファイリングすると、私のプログラムの1つのボトルネックは、基本的にこれを実行する関数であることがわかりました(np
is numpy
、sp
is scipy
):
def mix1(signal1, signal2):
spec1 = np.fft.fft(signal1, axis=1)
spec2 = np.fft.fft(signal2, axis=1)
return np.fft.ifft(spec1*spec2, axis=1)
両方の信号の形状(C, N)
はC
、データセットの数(通常は20未満)とN
各セットのサンプル数(約5000)です。各セット(行)の計算は、他のセットから完全に独立しています。
これは単なる畳み込みであると考えたので、次のように置き換えようとしました。
def mix2(signal1, signal2):
outputs = np.empty_like(signal1)
for idx, row in enumerate(outputs):
outputs[idx] = sp.signal.convolve(signal1[idx], signal2[idx], mode='same')
return outputs
...同じ結果が得られたかどうかを確認するためだけに。しかし、私はしませんでした、そして私の質問は次のとおりです:
- なぜだめですか?
- に相当するものを計算するためのより良い方法はあり
mix1()
ますか?
(mix2
おそらく、そのままでは高速ではなかったと思いますが、並列化の開始点としては適切だったかもしれません。)
これをすばやく確認するために使用した完全なスクリプトは次のとおりです。
import numpy as np
import scipy as sp
import scipy.signal
N = 4680
C = 6
def mix1(signal1, signal2):
spec1 = np.fft.fft(signal1, axis=1)
spec2 = np.fft.fft(signal2, axis=1)
return np.fft.ifft(spec1*spec2, axis=1)
def mix2(signal1, signal2):
outputs = np.empty_like(signal1)
for idx, row in enumerate(outputs):
outputs[idx] = sp.signal.convolve(signal1[idx], signal2[idx], mode='same')
return outputs
def test(num, chans):
sig1 = np.random.randn(chans, num)
sig2 = np.random.randn(chans, num)
res1 = mix1(sig1, sig2)
res2 = mix2(sig1, sig2)
np.testing.assert_almost_equal(res1, res2)
if __name__ == "__main__":
np.random.seed(0x1234ABCD)
test(N, C)