Why different output of transpose conv2d in Keras and Tensorflow

Issue

Different output of transpose convolution in Keras and Tensorflow.

Keras gives output (1, 5, 5, 1) only:

import tensorflow as tf

x = tf.random.normal(shape=(1, 2, 2, 1)) 
print()

y = tf.keras.layers.Conv2DTranspose(1, (3, 3), 2, padding="valid")(x)
print(y.shape)

print() 

Tensorflow gives output (1, 6, 6, 1) or (1, 5, 5, 1) if configs output_shape repectively:

import tensorflow as tf

with tf.compat.v1.Session() as sess:
  x1 = tf.constant(
            [4.5, 5.4, 8.1, 9.0],
            shape=([1, 2, 2, 1]),
            dtype=tf.float32
  )
  
  dev_con1 = tf.ones(
      shape=([3, 3, 1, 1]),
      dtype=tf.float32
  )

  y1 = tf.nn.conv2d_transpose(
      x1,
      dev_con1,
      output_shape=[1,6,6,1] # OK with [1,5,5,1], too,
      strides=[1, 2, 2, 1],
      padding="VALID"
  )
 
  tf.compat.v1.global_variables_initializer()

  y1, x1 = sess.run([y1,x1])

  print(x1.shape)
  print()
  print(y1.shape) 

Solution

If strides > 1 then multiple output shapes for transpose convolution are possible.

In a normal convolution one can calculate the output shape if padding is VALID:

out_shape = ceil((inp_shape - kernel_size + 1) / strides)    

Thinking reversely, in transpose convolution, output_shape would be equal to the shape of the normal convolution’s input’s shape if it was convolved with specific filter and strides values.

With other words, there are more than one possible output shape for transpose convolution as you round the numbers.

Example from your code:

y1 = tf.nn.conv2d_transpose(
    x1,
    dev_con1,
    output_shape=[1,5,5,1], # OK with [1,5,5,1], too,
    strides=[1, 2, 2, 1],
    padding="VALID"
)

If I convolve this with same filters and strides:

tf.nn.conv2d(y1, filters = tf.ones(shape=([3, 3, 1, 1]),dtype=tf.float32), s 
             trides = [1,2,2,1], padding = 'VALID')

>> <tf.Tensor: shape=(1, 2, 2, 1) ...

It produced the same shape like x1 in the first place.

Changing the output shape to [1, 6, 6, 1] in conv2d_transpose:

y1 = tf.nn.conv2d_transpose(
    x1,
    dev_con1,
    output_shape=[1,6,6,1], # OK with [1,5,5,1], too,
    strides=[1, 2, 2, 1],
    padding="VALID"
)

tf.nn.conv2d(y1, filters = tf.ones(shape=([3, 3, 1, 1]),dtype=tf.float32), 
                 strides = [1,2,2,1], padding = 'VALID')

>> <tf.Tensor: shape=(1, 2, 2, 1) ...

So tf.keras.layers.Conv2DTranspose gives the minimum possible output shape.

Answered By – Frightera

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published