Skip to main content

Last-Stage Neural Network Capacity Reduction Library

Project description

Last-Stage Capacity Reduction

CI PyPI version Python 3.10+ License: Apache-2.0

Patterns for progressively narrowing neural network representations in the final stages of a model — where compression into task-specific representations happens.

Core Principle

Early layers capture low-level features; later layers must compress these into task-specific representations. Strategic narrowing at this stage forces beneficial compression, improves regularization, and reduces inference cost without significant accuracy loss.

Grounded in: Huang et al., "Exploring Architectural Ingredients of Adversarially Robust DNNs" (NeurIPS 2021).

Two Tracks

Classification track — for backbones (ResNet, ConvNeXt, ViT, EfficientNet), embedding compression, and classification heads:

Block Use case
BottleneckBlock ResNet-style residual bottleneck with configurable ratio
ProgressiveNarrowing Stepwise width reduction over N stages (512→256→128→64)
WidthScaler Uniform width multiplier for any Sequential module
EmbeddingCompressor Pre-classifier embedding dimension reduction
DepthwiseFinal MobileNet-style final stage (lowest FLOPs)
SqueezeExcitation Standalone channel attention (plug-in)
CapacityReductionHead Drop-in classification head with compression

Detection track — for object detection necks (FPN, PAN, BiFPN), segmentation decoders, and multi-scale feature fusion:

Block Use case
LinearProjectionReduction Simple learnable channel projection (4D/3D/2D)
SEReduction Squeeze-and-Excitation channel attention + reduction
ConditionalCapacityBlock Spatial gating: network learns where reduction is safe
CapacityReductionStack Progressive narrowing across multiple stages

timm integration — apply capacity reduction to pretrained models from the timm library:

Function What it does
replace_classifier_head Swap the classifier for CapacityReductionHead
timm_feature_extractor Create a feature extractor with optional compression
scale_timm_model_width Uniformly scale channel width of any timm model
attach_final_stage_reduction Attach SE/conditional reduction before global pooling
describe_timm_model Inspect parameter count and head structure

Installation

pip install last-stage-capacity

Or install from source:

git clone https://github.com/johnmwhitman/last-stage-capacity.git
cd last-stage-capacity
pip install -e .

Dependencies: torch, timm, numpy

Quick Start

Classification: ResNet with progressive narrowing on the final stage

import torch
import torch.nn as nn
from last_stage_capacity import (
    BottleneckBlock, ProgressiveNarrowing,
    CapacityReductionHead, WidthScaler,
)

# Replace ResNet50's layer4 with progressive narrowing
# Standard: 256 -> 512 (no compression)
# Reduced:  256 -> 192 -> 128 -> 512 (bottleneck at each step)
final_stage = ProgressiveNarrowing(
    [256, 192, 128, 512],
    bottleneck_ratio=0.25,
    use_se=True,
)

# Compress features before the classifier
head = CapacityReductionHead(512, num_classes=1000, hidden_ratio=0.5)

Width scaling: uniformly reduce channel widths

import torch.nn as nn
from last_stage_capacity import WidthScaler

original = nn.Sequential(
    nn.Conv2d(64, 128, 3, padding=1),
    nn.BatchNorm2d(128),
    nn.ReLU(),
)

# Scale all channel dimensions by 0.5
# Conv2d(64, 128) -> Conv2d(32, 64), BN tracks correctly
scaled = WidthScaler(original, width_scale=0.5)

WidthScaler handles channel propagation through arbitrary module trees, including ResNet BasicBlock and Bottleneck blocks, with correct BatchNorm pairing after conv scaling.

Detection: channel reduction for FPN/PAN necks

import torch
from last_stage_capacity import (
    LinearProjectionReduction,
    SEReduction,
    ConditionalCapacityBlock,
    CapacityReductionStack,
)

# Simple projection: 256 -> 128 channels
reducer = LinearProjectionReduction(256, 128)
x = torch.randn(2, 256, 32, 32)  # BCHW
out = reducer(x)  # (2, 128, 32, 32)

# SE attention + reduction
se_reducer = SEReduction(256, 128, se_reduction=16)

# Spatial gating: network learns WHERE reduction is safe
conditional = ConditionalCapacityBlock(256, 128)

# Progressive narrowing across multiple FPN levels
stack = CapacityReductionStack([256, 192, 128, 64])

timm integration: attach reduction to pretrained models

from last_stage_capacity.timm_integration import (
    describe_timm_model,
    attach_final_stage_reduction,
    scale_timm_model_width,
    replace_classifier_head,
)

# Inspect a model
info = describe_timm_model('resnet18')
print(f"Parameters: {info['num_params']:,}")

# Attach SE reduction to the final stage
reduced = attach_final_stage_reduction('resnet18', reduction_ratio=0.5, block_type='se')

# Scale the entire model's width by 50%
scaled = scale_timm_model_width('resnet18', width_scale=0.5)

# Replace the classifier with a compressed head
reheaded = replace_classifier_head('resnet18', num_classes=10, hidden_ratio=0.5)

Parameter Reduction Example

Running the included demo (python examples.py):

Bottleneck efficiency (same in/out channels):
  Standard block params:  590,080
  Bottleneck block params: 148,480
  Reduction ratio:         25.2%

WidthScaler (50% width reduction):
  Conv2d(64,128) -> scaled Conv2d(32,64)
  Param reduction: 75,008 -> 18,944 (74.7%)

Project Structure

last-stage-capacity/
├── __init__.py              # Classification track (BottleneckBlock, ProgressiveNarrowing, WidthScaler, etc.)
├── _detection.py            # Detection track (LinearProjectionReduction, SEReduction, ConditionalCapacityBlock, etc.)
├── timm_integration.py      # timm integration (replace_classifier_head, scale_timm_model_width, etc.)
├── examples.py              # Classification demos (ResNet with reduction, width scaling)
├── examples/
│   └── timm_demo.py         # timm integration demo
├── test_*.py                # Test suite
├── pyproject.toml           # Package config
└── README.md

Tests

# Core library tests (no timm required)
python test_capacity_reduction.py

# Detection track tests
python test_detection_track.py

# timm integration tests (requires timm)
python test_vit_convnext.py
python test_timm_integration.py

Research Context

This library implements patterns from Huang et al., "Exploring Architectural Ingredients of Adversarially Robust DNNs" (NeurIPS 2021), which showed that last-stage capacity reduction improves robustness with fewer parameters. The key insight: early layers capture low-level features that need full capacity, but later layers compress into task-specific representations where strategic narrowing forces beneficial regularization.

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

last_stage_capacity-1.0.0.tar.gz (24.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

last_stage_capacity-1.0.0-py3-none-any.whl (24.9 kB view details)

Uploaded Python 3

File details

Details for the file last_stage_capacity-1.0.0.tar.gz.

File metadata

  • Download URL: last_stage_capacity-1.0.0.tar.gz
  • Upload date:
  • Size: 24.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for last_stage_capacity-1.0.0.tar.gz
Algorithm Hash digest
SHA256 153badf5ba3b73a8d0b95d0e320ef9f0c9eafa66090d5a29355b547fca0b5525
MD5 058d34b4c96b3fcb14198794dd8a5f0b
BLAKE2b-256 a15efdd12cfa33101a46f05f3b28f8d3f3dfabebe05de34637e3c444988b443c

See more details on using hashes here.

Provenance

The following attestation bundles were made for last_stage_capacity-1.0.0.tar.gz:

Publisher: release.yml on johnmwhitman/last-stage-capacity

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file last_stage_capacity-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for last_stage_capacity-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 840b68b5ec28f0f15385ed89864eb7e85d25bd0653826dbee5a10d2325c32b38
MD5 eb44117aa26fd694688f7178b00a9d3d
BLAKE2b-256 87ed0008ea0edcc43ea98fb933dce02b570cfade3e438a1d629fecec74950f55

See more details on using hashes here.

Provenance

The following attestation bundles were made for last_stage_capacity-1.0.0-py3-none-any.whl:

Publisher: release.yml on johnmwhitman/last-stage-capacity

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page