tf.keras.layers.Conv: Use most_specific_compatible_shape to determine when to re-build the internal nn_ops.Convolution object.

If the build shape was more specific then the call shape (i.e., the call shape has None values where the build shape had concrete values), it would not trigger a re-build.

TESTED:
- a unit test that fails without the fix.
PiperOrigin-RevId: 308744888
Change-Id: I35ce6a6e2ee092cf31d53fd80de9e5192acf8d7a
This commit is contained in:
A. Unique TensorFlower 2020-04-27 19:13:23 -07:00 committed by TensorFlower Gardener
parent 7f2dc64ee0
commit 5b9624278f
2 changed files with 8 additions and 29 deletions

View File

@ -305,9 +305,8 @@ class Conv(Layer):
"""Recreate conv_op if necessary.
Check if the input_shape in call() is different from that in build().
If the most-specific input shape describing the build and call shapes is not
equal to the shape we currently built with, then we need to rebuild the
_convolution_op to avoid incorrect behavior.
For the values that are not None, if they are different, recreate
the _convolution_op to avoid the stateful behavior.
Args:
inputs: The input data to call() method.
@ -316,10 +315,12 @@ class Conv(Layer):
`True` or `False` to indicate whether to recreate the conv_op.
"""
call_input_shape = inputs.get_shape()
# If the most specific compatible shape between _build_input_shape and
# call_input_shape is not _build_input_shape then we must re-build.
return self._build_conv_op_input_shape.most_specific_compatible_shape(
call_input_shape) != self._build_conv_op_input_shape
for axis in range(1, len(call_input_shape)):
if (call_input_shape[axis] is not None
and self._build_conv_op_input_shape[axis] is not None
and call_input_shape[axis] != self._build_conv_op_input_shape[axis]):
return True
return False
@keras_export('keras.layers.Conv1D', 'keras.layers.Convolution1D')

View File

@ -23,8 +23,6 @@ import numpy as np
from tensorflow.python import keras
from tensorflow.python.eager import context
from tensorflow.python.eager import def_function
from tensorflow.python.framework import tensor_spec
from tensorflow.python.framework import test_util
from tensorflow.python.keras import keras_parameterized
from tensorflow.python.keras import testing_utils
@ -110,26 +108,6 @@ class Conv1DTest(keras_parameterized.TestCase):
_ = layer(inpt2).shape
self.assertEqual(outp1_shape, layer(inpt1).shape)
def test_conv1d_recreate_conv_unknown_dims(self):
with self.cached_session(use_gpu=True):
layer = keras.layers.Conv1D(filters=1,
kernel_size=3,
strides=1,
dilation_rate=2,
padding='causal')
inpt1 = np.random.normal(size=[1, 9, 1]).astype(np.float32)
inpt2 = np.random.normal(size=[1, 2, 1]).astype(np.float32)
outp1_shape = layer(inpt1).shape
@def_function.function(input_signature=[
tensor_spec.TensorSpec([1, None, 1])])
def fn(inpt):
return layer(inpt)
fn(inpt2)
self.assertEqual(outp1_shape, layer(inpt1).shape)
@keras_parameterized.run_all_keras_modes
class Conv2DTest(keras_parameterized.TestCase):