Skip to content

fix(architectures): follow layer_sizes for any ResNet num_blocks - #538

Open
ChrisW09 wants to merge 2 commits into
mainfrom
fix/resnet-num-blocks
Open

ChrisW09 wants to merge 2 commits into
mainfrom
fix/resnet-num-blocks

Conversation

@ChrisW09

@ChrisW09 ChrisW09 commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #537

Problem

ResNet.__init__ took block i's input width from layer_sizes[i] and always built the output layer as nn.Linear(layer_sizes[-1], num_classes). Only num_blocks equal to len(layer_sizes) - 1 or len(layer_sizes) worked:

  • with more blocks, layer_sizes[i] raised IndexError, contrary to the model page's "later blocks stay at the final width";
  • with fewer blocks (including num_blocks=0), the output layer didn't match the last block's width and the first forward pass failed.

Fix

deeptab/architectures/resnet.py tracks the running width:

  • block i maps the current width to layer_sizes[min(i + 1, len(layer_sizes) - 1)];
  • the output layer reads the width the last block produces, or layer_sizes[0] without blocks.

Configurations that worked before build the identical network.

Tests

tests/architectures/test_architecture_contracts.py::test_resnet_blocks_follow_layer_sizes_for_any_num_blocks[0-blocks|1-block|2-blocks|3-blocks|4-blocks|5-blocks] checks each block's widths, the output layer width, a forward pass and a backward pass with layer_sizes=[16, 8, 4]. The cases with 0, 1, 4 and 5 blocks fail on main; four blocks is the issue's IndexError case. The 2- and 3-block cases worked before and build the same state_dict as on main. All pass with this change.

This also makes the documented example in docs/api/configs/index.rst work. It uses ResNetConfig(layer_sizes=[256, 128, 32], num_blocks=4) and raises IndexError on main.

Docs

  • ResNetConfig numpydoc: layer_sizes is described as the width schedule, and num_blocks explains blocks beyond it and the output width.
  • docs/model_zoo/stable/resnet.md: the building-blocks table and the implementation notes describe the schedule and the output layer.

Checks

  • just test: 3242 passed, 46 skipped, 28 xfailed; coverage 91.29%
  • just docs: build succeeded (warnings treated as errors)
  • just check: all hooks passed (ruff, prettier, pyright)

Block i read its input width from layer_sizes[i] and the output layer
always used layer_sizes[-1], so ResNet raised IndexError for more blocks
than widths and a shape mismatch for fewer blocks than transitions.
Track the running width: block i maps layer_sizes[i] to layer_sizes[i + 1],
later blocks keep the last width (as documented), and the output layer
reads the width of the last block. Document the schedule in ResNetConfig
and the ResNet model page.

Fixes #537
Four blocks is the case from the issue (one more block than layer_sizes
entries) that raised IndexError.

Refs #537

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] ResNet crashes unless num_blocks is len(layer_sizes) - 1 or len(layer_sizes)

1 participant