Fix flops profiler counts for transposed convolutions - #8323
Conversation
A ConvTranspose weight is [in_channels, out_channels // groups, *kernel], so weight.shape[1] is already the per-group filter count. Dividing it by groups a second time made every grouped transposed convolution under-count its macs by a factor of groups, and report exactly zero for a depthwise one, where out_channels // groups is 1 and the extra floor division truncates it away. The output shape was also computed with the forward convolution formula, which shrinks by the stride instead of growing by it, and output_padding was accepted but never read. Since the bias is added once per output element, that made the bias term wrong for every strided transposed convolution: a stride-2 layer counted 1/16 of its bias flops. Add a CPU regression test over groups, stride, padding and output_padding that checks both counts against the shapes torch itself produces. Signed-off-by: Vineeth Sai <vineethsai4444@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 20cdc7b436
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| batch_size = input.shape[0] | ||
| in_channels = input.shape[1] | ||
| out_channels = weight.shape[1] | ||
| # A transposed-convolution weight is [in_channels, out_channels // groups, *kernel], |
There was a problem hiding this comment.
Add the required Signed-off-by trailer
For this non-merge commit, the commit message has no Signed-off-by: trailer; the workspace rule requires that trailer on every non-merge commit, so DCO/CI checks can reject the change even though the code is correct. Please recommit with --signoff using the configured name/email.
AGENTS.md reference: AGENTS.md:L8-L8
Useful? React with 👍 / 👎.
Symptom
The flops profiler reports zero macs for a depthwise transposed convolution, and under-counts every other grouped one. Bias flops are wrong for every strided transposed convolution.
ConvTranspose2d(4, 6, 4, stride=2, padding=1)ConvTranspose2d(4, 4, 3, stride=2, padding=1, output_padding=1, groups=4)ConvTranspose2d(6, 6, 2, stride=2, groups=3)Root cause
Two independent problems in
_conv_trans_flops_compute.1. The per-group filter count is divided by
groupstwice. A transposed-convolution weight is[in_channels, out_channels // groups, *kernel], not[out_channels, in_channels // groups, *kernel]as for a forward convolution. Soweight.shape[1]is alreadyout_channels // groups, andyields
out_channels // groups ** 2. For a depthwise layer that is1 // groups, which floors to0, soconv_per_position_macsand the whole layer collapse to zero.2. The output shape uses the forward-convolution formula. A transposed convolution inverts it, and
output_paddingwas accepted by the signature but never read:The bias is added once per output element, so
bias_flops = out_channels * batch_size * prod(output_dims)inherits the error. For a stride-2 layer the formula returns roughlyinput_dim / stridewhere the real output isinput_dim * stride, so the bias term comes out about 16x too small in 2D.The three lines that recomputed
paddings/strides/dilationsas 2-tuples immediately after the loop were dead, and hardcoded 2D for a helper that also servesconv_transpose1dandconv_transpose3d, so they go with the fix.Fix
Read
filters_per_channelstraight offweight.shape[1]and recoverout_channelsby multiplying it back up, and compute the output shape with the transposed-convolution formula, includingoutput_padding.The mac convention is unchanged: a transposed convolution scatters every input element across the kernel, so
active_elements_countstays based oninput_dims.Test
tests/unit/profiling/flops_profiler/test_flops_profiler.py::test_conv_transpose_flops, parametrized overgroupsin 1/2/4 and(stride, padding, output_padding)in (1, 0, 0)/(2, 1, 1). It checks both counts against the shapes torch itself produced, so the expected values are not a copy of the implementation.Against master: 6 failed, 2 passed (
assert 0 == 9216for the depthwise cases). With the fix: 8 passed.Manually checked beyond what the test parametrizes, all matching torch:
ConvTranspose1d,ConvTranspose3d,dilation=2, andbias=False.