张量流中fft的结果与numpy不同

时间:2017-11-10 01:53:49

标签: python numpy tensorflow fft

我想在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。这是这个问题的关键吗?我该如何解决这个问题?

4 个答案:

答案 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)

Noisy sinusoid

现在进行一些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();

FFT differences

这很难看,但是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 值。