# 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],
)

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.

``````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],
)
``````

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],
)

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. 