我想在tensorflow中使用fft。但是我发现在numpy和tensorflow中分别使用FFT函数时结果是不同的。特别是当输入数组的大小很大时
import tensorflow as tf
import numpy as np
aa = tf.lin_space(1.0, 10000.0, 10000)
bb = tf.lin_space(1.0, 10000.0, 10000)
dd = tf.concat([[aa],[bb]],axis = 0)
c_input = tf.complex(dd[0,:], dd[1,:])
Spec = tf.fft(c_input)
sess = tf.Session()
uuu = sess.run(Spec)
print(uuu)
aaa = np.linspace(1.0, 10000.0, 10000)
bbb = aaa + 1j*aaa
ccc = np.fft.fft(bbb)
print(ccc)
结果是
[ 11645833.000000+11645826.j -544529.875000 -6242453.5j
-913097.437500 -781089.0625j ..., 78607.218750 -108219.109375j
103245.156250 -182935.3125j 214871.765625 -790986.0625j ]
[ 50005000.00000000+50005000.j -15920493.78559075+15910493.78559076j
-7962746.10739718 +7952746.10739719j ...,
5300163.19893340 -5310163.19893345j
7952746.10739715 -7962746.10739723j
15910493.78559067-15920493.78559085j]
那么,当我在tensorflow中使用fft函数时,我能做些什么来获得相同的结果? 谢谢你的回答
我发现tf.fft输出的数据类型是complex64。但是np.fft.fft的输出是复杂的128。这是这个问题的关键吗?我该如何解决这个问题?
答案 0 :(得分:4)
你是对的,差异恰好在张量流和numpy中的dtype
。
Tensorflow tf.fft
强制输入张量为tf.complex64
,最有可能是GPU op compatiblity。 Numpy还硬编码FFT的数组类型。源代码采用本机C fftpack_litemodule.c
,其中类型为NPY_CDOUBLE
- 128位,即np.complex128
。有关详细信息,请参阅this issue。
所以,我担心没有简单的解决方案可以匹配它们。您可以尝试定义适用np.fft.fft
的{{3}},但这也需要您手动评估渐变。或者避免将FFT应用于大型矢量,因此数值不准确性不会成为问题。
答案 1 :(得分:0)
我做了一些调查,虽然Maxim的回答是差异可以归结为不同的dtype
,但我认为这是不正确的。
的确,Numpy对其FFT使用64位运算(即使您将32位Numpy数组传递给它),而Tensorflow使用32位运算。但是,您可以在Scipy中执行32位FFT。但是,即使32位的Scipy FFT也与Tensorflow计算不匹配。
带有噪音的正弦曲线的小测试:
import matplotlib.pyplot as plt
import numpy as np
import scipy
import tensorflow as tf
X = np.linspace(0, 1, num=512)
data = np.sin(X * 2 * np.pi * 4) + np.random.uniform(-0.3, 0.3, size=512)
data = data.astype(np.float32)
plt.plot(X, data)
现在进行一些FFT并进行比较:
np_fft = np.fft.rfft(data)
sp_fft = scipy.fftpack.rfft(data)
sp_fft = np.r_[sp_fft[:1], sp_fft[1:-1:2] + sp_fft[2:-1:2] * 1j, sp_fft[-1:]]
input_placeholder = tf.placeholder(tf.float32, [512])
tf_fft = tf.signal.rfft(input_placeholder)
with tf.Session() as sess:
tf_fft_ = sess.run(tf_fft, feed_dict={input_placeholder: data})
plt.plot(np.abs(sp_fft - tf_fft_), label='Scipy-Tensorflow')
plt.plot(np.abs(sp_fft - np_fft), label='Scipy-Numpy')
plt.plot(np.abs(np_fft - tf_fft_), label='Numpy-Tensorflow')
plt.yscale('log')
plt.xlabel('Frequency bin')
plt.ylabel('Difference')
plt.legend();
这很难看,但是Numpy和Tensorflow之间的差异可与Scipy和Tensorflow之间的差异相提并论,而Numpy和Scipy之间的差异要小得多,即使Scipy正在以Tensorflow这样的32位进行操作是。因此,除了运算的位深度之外,Tensorflow FFT实施中似乎还有一些其他差异。不过,对于我来说,这种差异还不清楚。
答案 2 :(得分:0)
确实,complex64不是唯一的原因。在这里进行测试:
import tensorflow as tf
import numpy as np
aaa = np.linspace(1.0, 10000.0, 10000)
x = aaa + 1j*aaa
x_tensor = tf.convert_to_tensor(x)
tf_fft = tf.signal.fft(x_tensor)
np_fft = np.fft.fft(x)
print(tf_fft.dtype)
print(np.all(tf_fft.numpy() == np_fft))
在这里,输出为:
tf.complex128
False
这一次显示,tensorflow的输出很复杂128,但是结果却不同。
正如我在评论部分中所展示的。这种差异是如此之小,可能会被忽略,并且由于实际原因,您将获得相同的结果。因此,解决方案只是将输入张量从complex64投射到complex128 。
答案 3 :(得分:0)
一定是因为选择了 N
来计算 FFT。
tf.signal.fft
只是接收信号并使用默认值 N(不确定是什么)。
np.fft.fft
接收信号和参数 N
。不同的 N 值给出不同的 FFT 值。