profile
viewpoint

Ask questionstf.keras custom layer does not use "compute_output_shape"

System information

  • Have I written custom code (as opposed to using a stock example script provided in TensorFlow): Yes
  • OS Platform and Distribution (e.g., Linux Ubuntu 16.04): Ubuntu 18.04
  • Mobile device (e.g. iPhone 8, Pixel 2, Samsung Galaxy) if the issue happens on mobile device: n/a
  • TensorFlow installed from (source or binary): pip
  • TensorFlow version (use command below):
  • Python version: v2.2.0-rc1-34-ge6e5d6df2a 2.2.0-rc2
  • Bazel version (if compiling from source): n/a
  • GCC/Compiler version (if compiling from source): n/a
  • CUDA/cuDNN version: Driver Version: 440.33.01 CUDA Version: 10.2
  • GPU model and memory: GTX 1080 Ti 11162MiB ram

Describe the current behavior

When implementing a custom layer where the output shape is not computable directly from the code within the call method, the compute_output_shape function is not used to determine the output shape.

This causes issues when passing to a layer which must know some of the shape, e.g. a Conv*D layer which needs to know the number of channels ahead of time.

Describe the expected behavior

The compute_output_shape function is used to determine the output shape.

Standalone code to reproduce the issue

import tensorflow as tf


class Spectrogram(tf.keras.layers.Layer):
    def __init__(self, num_freqs, max_freq, **kwargs):
        super(Spectrogram, self).__init__(**kwargs)

        self.num_freqs = num_freqs
        self.max_freq = max_freq

        self.input_spec = [
            tf.keras.layers.InputSpec(ndim=2), tf.keras.layers.InputSpec(ndim=2)
        ]

    def call(self, x_fs):
        x, fs = x_fs
        nfft = tf.cast(
            fs[0,0] * (self.num_freqs - 1) / self.max_freq,
            tf.int32
        )
        y = tf.signal.stft(x, nfft, 256, nfft, pad_end=True)
        y = tf.sqrt(tf.abs(y))[:, :, :self.num_freqs]
        return y

    def compute_output_shape(self, input_shape):
        return (input_shape[0], None, self.num_freqs)


signal = tf.keras.layers.Input(shape=(None,))
fs = tf.keras.layers.Input(shape=(1,))
x = Spectrogram(257, 10_000)([signal, fs])
y = tf.keras.layers.Conv1D(16, 3)(x)

tf.keras.models.Model([signal, fs], [y]).summary()

Logs

Traceback (most recent call last):
  File "chorus/repro.py", line 32, in <module>
    y = tf.keras.layers.Conv1D(16, 3)(x)
  File "/home/kevin/.pyenv/versions/chorus/lib/python3.7/site-packages/tensorflow/python/keras/engine/base_layer.py", line 897, in __call__
    self._maybe_build(inputs)
  File "/home/kevin/.pyenv/versions/chorus/lib/python3.7/site-packages/tensorflow/python/keras/engine/base_layer.py", line 2416, in _maybe_build
    self.build(input_shapes)  # pylint:disable=not-callable
  File "/home/kevin/.pyenv/versions/chorus/lib/python3.7/site-packages/tensorflow/python/keras/layers/convolutional.py", line 153, in build
    input_channel = self._get_input_channel(input_shape)
  File "/home/kevin/.pyenv/versions/chorus/lib/python3.7/site-packages/tensorflow/python/keras/layers/convolutional.py", line 293, in _get_input_channel
    raise ValueError('The channel dimension of the inputs '
ValueError: The channel dimension of the inputs should be defined. Found `None`.

Other info

This was originally opened in #19961 but was unfortunately closed as "not a bug", but I'm pretty sure this is not expected behavior according to the keras docs.

tensorflow/tensorflow

Answer questions tomerk

This is a difference between tf.keras and the older OSS keras releases.

As an immediate stop-gap you should be able to manually set the output shape on the tensor and be okay, e.g.

        y = tf.sqrt(tf.abs(y))[:, :, :self.num_freqs]
        y.set_shape(self.compute_output_shape(x.shape))
        return y

Currently tf.keras uses compute_output_shape to set the output shape only when layers are dynamic and can only be run eagerly.

In the medium-term we need to figure out whether it makes sense for Keras to automatically set the output shape to the result of compute_output_shape whenever compute_output_shape is implemented, rather than just for dynamic layers.

useful!

Related questions

ModuleNotFoundError: No module named 'tensorflow.contrib' hot 8
Error occurred when finalizing GeneratorDataset iterator hot 6
ModuleNotFoundError: No module named 'tensorflow.contrib'
When importing TensorFlow, error loading Hadoop
tf.keras.layers.Conv1DTranspose ?
tensorflow-gpu CUPTI errors hot 4
[TF 2.0] tf.keras.optimizers.Adam hot 4
Lossy conversion from float32 to uint8. Range [0, 1]. Convert image to uint8 prior to saving to suppress this warning. hot 4
TF2.0 AutoGraph issue hot 4
Tf.Keras metrics issue hot 4
module 'tensorflow' has no attribute 'ConfigProto' hot 4
TF 2.0 'Tensor' object has no attribute 'numpy' while using .numpy() although eager execution enabled by default hot 4
ModuleNotFoundError: No module named 'tensorflow.examples.tutorials' hot 4
AttributeError: module &#39;tensorflow.python.framework.op_def_registry&#39; has no attribute &#39;register_op_list&#39; hot 4
tensorflow2.0 detected 'xla_gpu' , but 'gpu' expected hot 3
Github User Rank List