【问题标题】:Can we use tf.spectral fourier functions in keras?我们可以在 keras 中使用 tf.spectral 傅立叶函数吗?
【发布时间】:2019-04-27 02:02:51
【问题描述】:

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

如果我们尝试这样做:

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

然后第三行输入的时候报错:

>> ValueError: Tensor conversion requested dtype complex64 for Tensor with dtype float32

你看,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)))

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

autoencoder = Model(inputs, decoded)

它会产生错误:

TypeError: Output tensors to a Model must be Keras tensors. Found: <keras.layers.core.Lambda object at 0x7f24f0f7bbe0>

我认为这是合理的,也是我一开始不想投射它的原因。

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

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

【问题讨论】:

    标签: python tensorflow keras


    【解决方案1】:

    我认为您只需要更多 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())
    

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

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

    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())
    

    请注意,这不适用于一般序列,因为即使是实值输入也可以在转换后具有虚部。它适用于上面的 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.]]
    

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

    【讨论】:

    • 我将其标记为正确,因为我不能否认它如图所示运行 :) 即使我使用 tf.keras,它似乎也不接受 rfft 和 irfft 之间的其他层类型,尽管。如果我尝试将 K.layers.Conv1D 放在这两者之间,例如,即使包装在 Lambda 中,我会得到:“传递给参数'输入'的值的 DataType complex64 不在允许值列表中:”尽管 rfft 应该具有真实的输出。你知道如何在 rfft 和 irfft 之间进行卷积吗?
    • rfft returns complex64,所以我不认为 dtype 是一个错误(尽管卷积可能适用于复数?)。如果您知道它是真实的,您可以转换/截断复杂的位。我将添加一个示例。
    • 一种选择是将实部/虚部分割成通道(一个通道中的tf.real(),另一个通道中的tf.imag())用于卷积。
    • 这是一个 fft,所以我需要幅度,我会用数值运算来尝试。谢谢!
    • 这个答案结合:@Mark.F 的datascience.stackexchange.com/a/42806/27662 帮助了我。
    【解决方案2】:

    当我试图解决同样的问题时,我偶然发现了这一点。您可以通过将tf.realtf.imag 包装到Lambda 层中来使转换无损(我使用stft,因为没有真正有价值的等价物):

    x = tf.keras.layers.Lambda(
        lambda v: tf.signal.stft(
            v,
            frame_length=1024,
            frame_step=256,
            fft_length=1024,
        ), name='gen/FFTLayer')(inputs)
    real = tf.keras.layers.Lambda(tf.real)(x)
    imag = tf.keras.layers.Lambda(tf.imag)(x)
    ...
    # transform real and imag either separately or by concatenating them in the feature space.
    ...
    x = tf.keras.layers.Lambda(lambda x: tf.complex(x[0], x[1]))([real, imag])
    x = tf.keras.layers.Lambda(
        lambda v: tf.signal.inverse_stft(
            v,
            frame_length=1024,
            frame_step=256,
            fft_length=1024,
        ))(x)
    

    【讨论】:

      【解决方案3】:

      只是为从搜索引擎到达这里的任何人添加更多内容。以下,在this google group discussion 中提供,将运行 rfft 然后 ifft 与卷积和其他层之间:

      inputs = Input(shape=(10, 8), name='main_input')
      x = Lambda(lambda v: tf.to_float(tf.spectral.rfft(v)))(inputs)
      x = Conv1D(filters=5, kernel_size=3, activation='relu', padding='same')(x)
      x = Lambda(lambda v: tf.to_float(tf.spectral.irfft(tf.cast(v, dtype=tf.complex64))))(x)
      x = Flatten()(x)
      output = Dense(1)(x)
      model = Model(inputs, output)
      model.summary()
      

      它使用与 Allen 的答案相同的概念,但细微的差异允许与中间卷积兼容。

      【讨论】:

      • tf.to_float 扔掉了虚构的部分吗?
      • 同样 rfft 只沿一个轴作用?
      猜你喜欢
      • 1970-01-01
      • 2019-02-18
      • 1970-01-01
      • 2016-03-25
      • 2012-07-03
      • 1970-01-01
      • 1970-01-01
      • 2013-01-31
      • 1970-01-01
      相关资源
      最近更新 更多