The ConvTranspose2d Output Size Formula in PyTorch
For each spatial dimension, out = (in - 1) * stride - 2*padding + kernel_size + output_padding. Height and width are computed independently with the same formula.
The Formula
output_size = (input_size - 1) * stride - 2 * padding + kernel_size + output_padding
PyTorch's ConvTranspose2d applies this formula to the height and width independently. The channel dimensions work differently: ConvTranspose2d(in_channels, out_channels, ...) maps a tensor of shape (N, in_channels, H, W) to (N, out_channels, H_out, W_out).
Worked Examples
# in=7, kernel=2, stride=2, padding=0
out = (7 - 1) * 2 - 2*0 + 2 + 0 = 14 # 7x7 -> 14x14
# in=8, kernel=4, stride=2, padding=1
out = (8 - 1) * 2 - 2*1 + 4 + 0 = 16 # 8x8 -> 16x16
# in=5, kernel=4, stride=2, padding=1, output_padding=1
out = (5 - 1) * 2 - 2*1 + 4 + 1 = 11 # 5x5 -> 11x11
The Classic GAN Upsample, 7×7 to 14×14
The most common use of ConvTranspose2d is upsampling in generator networks. The canonical case is doubling a 7×7 feature map to 14×14 with kernel_size=2, stride=2, padding=0:
import torch
import torch.nn as nn
x = torch.randn(1, 512, 7, 7) # 512-channel, 7x7
up = nn.ConvTranspose2d(512, 256, 2, stride=2) # kernel=2, stride=2, padding=0
print(up(x).shape) # [1, 256, 14, 14]
The DCGAN generator uses this exact pattern in sequence, doubling the spatial size at each stage while halving the channels:
z = torch.randn(1, 100, 1, 1)
net = nn.Sequential(
nn.ConvTranspose2d(100, 512, 4, 1, 0), # 1 -> 4
nn.ConvTranspose2d(512, 256, 4, 2, 1), # 4 -> 8
nn.ConvTranspose2d(256, 128, 4, 2, 1), # 8 -> 16
nn.ConvTranspose2d(128, 64, 4, 2, 1), # 16 -> 32
nn.ConvTranspose2d(64, 3, 4, 2, 1), # 32 -> 64
)
print(net(z).shape) # [1, 3, 64, 64]
Verify any one of these stages with the formula. For 8→16 with kernel=4, stride=2, padding=1: (8-1)*2 - 2*1 + 4 = 16.
What output_padding Does
output_padding adds extra rows and columns to one side of the output to control its size. It is added to the result of the transposed convolution and is the final term in the formula:
out = (in - 1) * stride - 2 * padding + kernel_size + output_padding
It exists because when stride > 1, several valid output sizes are ambiguous under the standard convolution inverse. For example, a forward Conv2d with kernel=3, stride=2, padding=1 maps both a 7×7 and an 8×8 input to a 4×4 output. The matching transposed layer cannot know which size to restore, so output_padding lets you pick between the candidate shapes.
# Same kernel, stride, padding - output_padding chooses the size
c1 = nn.ConvTranspose2d(3, 3, 3, stride=2, padding=1, output_padding=0)
c2 = nn.ConvTranspose2d(3, 3, 3, stride=2, padding=1, output_padding=1)
print(c1(torch.randn(1, 3, 4, 4)).shape) # [1, 3, 7, 7]
print(c2(torch.randn(1, 3, 4, 4)).shape) # [1, 3, 8, 8]
Note that output_padding does not change what the layer learns; it only affects the output spatial size. The valid range for a given configuration is 0 to max(stride - 1, kernel_size - 2*padding - 1) per PyTorch documentation. Setting it to a value outside this range raises an error. Use the smallest value that yields the output size you need.
Contrast With the Conv2d Formula
The regular Conv2d formula shrinks the spatial dimensions:
conv2d_out = floor((in - kernel + 2 * padding) / stride) + 1
The transposed formula is its algebraic inverse. Where Conv2d divides by stride, ConvTranspose2d multiplies by it. A Conv2d that maps 14→7 with kernel=2, stride=2, padding=0 is reversed by a ConvTranspose2d that maps 7→14 with the same parameters:
# Forward Conv2d: 14 -> 7
forward = floor((14 - 2 + 0) / 2) + 1 = 7
# Transposed: 7 -> 14
inverse = (7 - 1) * 2 - 0 + 2 = 14
Because of this inverse relationship, ConvTranspose2d is also called a fractionally-strided convolution or deconvolution (a name PyTorch avoids to prevent confusion with true mathematical deconvolution).