我们可以在 keras 中使用 tf.spectral 傅立叶函数吗?

Eze*_*ick 6 python keras tensorflow

让我们从一个简单的时间序列输入开始,并尝试构建一个自动编码器,该自动编码器简单地进行傅立叶变换,然后在 keras 中对我们的数据进行反变换。

如果我们尝试这样做:

inputs = Input(shape=(MAXLEN,1), name='main_input')
x = tf.spectral.rfft(inputs)
decoded = Lambda(tf.spectral.irfft)(x)
Run Code Online (Sandbox Code Playgroud)

然后第三行在输入时抛出错误:

>> ValueError: Tensor conversion requested dtype complex64 for Tensor with dtype float32
Run Code Online (Sandbox Code Playgroud)

你看,tf.spectral.irfft 的输出是 float32 但看起来 Lambda 认为它是 complex64??(Complex64 是上一步的输入 x)

我们可以在模型输入时修复该错误:

inputs = Input(shape=(MAXLEN,1), name='main_input')
x = tf.spectral.rfft(inputs)
decoded = Lambda(tf.cast(tf.spectral.irfft(x),dtype=tf.float32)))
Run Code Online (Sandbox Code Playgroud)

这在输入时被接受,但是当我们尝试构建模型时:

autoencoder = Model(inputs, decoded)
Run Code Online (Sandbox Code Playgroud)

它生成错误:

TypeError: Output tensors to a Model must be Keras tensors. Found: <keras.layers.core.Lambda object at 0x7f24f0f7bbe0>
Run Code Online (Sandbox Code Playgroud)

我想这是合理的,也是我不想首先投射它的原因。

主要问题:如何成功包装输出 float32 的 tf.spectral.irfft 函数?

更一般的学习问题:假设我实际上想在 rfft 和 irfft 之间做一些事情,如何在不破坏 keras 的情况下将这些虚数转换为绝对值,以便我可以应用各种卷积等?

All*_*oie 8

我认为你只需要更多的Lambda包装(tf.keras因为这就是我安装的):

import numpy
import tensorflow as tf
K = tf.keras

inputs = K.Input(shape=(10, 8), name='main_input')
x = K.layers.Lambda(tf.spectral.rfft)(inputs)
decoded = K.layers.Lambda(tf.spectral.irfft)(x)
model = K.Model(inputs, decoded)
output = model(tf.ones([10, 8]))
with tf.Session():
  print(output.eval())
Run Code Online (Sandbox Code Playgroud)

的输出irfft应该是真实的,所以可能不需要转换它。但如果您确实需要转换它(或者通常在Lambda层中组合操作),我会将其包装在 Python lambda 中:K.layers.Lambda(lambda v: tf.cast(tf.spectral.whatever(v), tf.float32))

例如,如果您知道中间值(在rfft和 之间irfft)的虚部为零,则可以将其截断:

import numpy
import tensorflow as tf
K = tf.keras

inputs = K.Input(shape=(10, 8), name='main_input')
x = K.layers.Lambda(lambda v: tf.real(tf.spectral.rfft(v)))(inputs)
decoded = K.layers.Lambda(
    lambda v: tf.spectral.irfft(tf.complex(real=v, imag=tf.zeros_like(v))))(x)
model = K.Model(inputs, decoded)
output = model(tf.reshape(tf.range(80, dtype=tf.float32), [10, 8]))
with tf.Session():
  print(output.eval())
Run Code Online (Sandbox Code Playgroud)

请注意,这对于一般序列而言并非如此,因为即使是实值输入一旦转换也可能具有虚部。它适用于tf.ones上面的输入,但是tf.range输入被破坏了:

[[ 0.  4.  4.  4.  4.  4.  4.  4.]
 [ 8. 12. 12. 12. 12. 12. 12. 12.]
 [16. 20. 20. 20. 20. 20. 20. 20.]
 [24. 28. 28. 28. 28. 28. 28. 28.]
 [32. 36. 36. 36. 36. 36. 36. 36.]
 [40. 44. 44. 44. 44. 44. 44. 44.]
 [48. 52. 52. 52. 52. 52. 52. 52.]
 [56. 60. 60. 60. 60. 60. 60. 60.]
 [64. 68. 68. 68. 68. 68. 68. 68.]
 [72. 76. 76. 76. 76. 76. 76. 76.]]
Run Code Online (Sandbox Code Playgroud)

(没有铸造,我们得到 0. 到 79. 完美重建)

  • 一种选择是将实数/虚数分割为通道(一个通道中的“tf.real()”,另一个通道中的“tf.imag()”)进行卷积。 (4认同)
  • [rfft 返回complex64](https://www.tensorflow.org/api_docs/python/tf/spectral/rfft),所以我不认为dtype是一个错误(尽管也许卷积应该适用于复数?)。如果您知道它是真实的,您可以转换/截断复杂位。我将添加一个例子。 (2认同)