Skip to content

add utility to compute analytical bits per weight - #67

Open
pkmandke wants to merge 18 commits into
apple:mainfrom
pkmandke:dev/bpw_utility
Open

add utility to compute analytical bits per weight#67
pkmandke wants to merge 18 commits into
apple:mainfrom
pkmandke:dev/bpw_utility

Conversation

@pkmandke

@pkmandke pkmandke commented Aug 14, 2026

Copy link
Copy Markdown
Member

Add utility to compute the average bits-per-weight (bpw) of a prepared coreai-opt model in eager mode quantization and palettization.

Public API

Imported from coreai_opt.inspection:

def bits_per_weight(model: torch.nn.Module) -> BitsPerWeightResult
@dataclass
class BitsPerWeightResult:
    bpw: float                      # total_bits / total_weights, 0.0 if no params
    per_module: dict[str, float]    # module name -> module's own average bpw
    total_bits: int                 # total storage cost in bits, incl. amortized overhead
    total_weights: int              # total logical parameter elements

Usage:

from coreai_opt.inspection import BitsPerWeightResult, bits_per_weight

result = bits_per_weight(prepared_model)
result.bpw          # 4.13
result.per_module   # {"l1": 4.06, "l2": 4.25, ...}

Supported: eager-mode integer weight quantization (int8/int4/int2 and unsigned variants, symmetric or asymmetric, any granularity, sub-byte payloads packed at n_bits), and palettization at any spec-supported n_bits including a quantized LUT.

Raises NotImplementedError for: graph-mode / torch.fx.GraphModule models, floating-point (FP8/FP4) weight quantization, and parametrizations that store multiple original tensors (weight_norm, spectral_norm).

Note: This is an analytical estimate, not a measurement. It is meant for prepared models, not finalized ones.

Testing

  • tests/inspection/test_bits_per_weight.py: unit tests against hand-derived golden bit counts across quantization dtypes, qschemes, and granularities, plus palettization n_bits x granularity combinations. Also covers persistent and non-persistent buffers, tied weights, per-module attribution, and the unsupported-config errors.
  • tests/export/test_bpw_export_size.py: cross-checks total_bits / 8 against the measured payload of an actual Core AI export. The prediction must be a lower bound and land within a 2.5 percent structural-metadata budget.
  • tests/export/export_utils.py: adds coreai_export_size_bytes helper.
  • tests/models/simple.py: adds LinearBatchNormModel fixture (buffer coverage) and optional bias to two existing fixtures.

TODO:

  • Add export tests to validate analytical bpw against exported asset size
  • Add tests for per-module bpw

Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
@pkmandke
pkmandke marked this pull request as ready for review August 17, 2026 20:59
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
@pkmandke
pkmandke requested a review from guru-desh August 17, 2026 21:24
Comment thread src/coreai_opt/inspection/bits_per_weight.py Outdated
@pkmandke pkmandke added the enhancement New feature or request label Aug 18, 2026
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>

@u-simha u-simha left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have left some comments; my main suggestion would be to have a documentation page (even if it is brief) rather than the doc string at the top of the file

# Use of this source code is governed by a BSD-3-Clause license that can
# be found in the LICENSE file or at https://opensource.org/licenses/BSD-3-Clause

"""Compute the average bits-per-weight (bpw) of a prepared ``coreai-opt`` model.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My suggestion would be to have a doc page explaining the usage of this tool; doc strings in the headings of the file isn't often read, compared to the documentation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@u-simha any suggestions on where to add this in the doc? I'm thinking a new page under OTHER WORKFLOWS AND UTILITIES but if there's other similar utils mentioned elsewhere, it can belong there instead of a new page.

Comment thread src/coreai_opt/inspection/bits_per_weight.py Outdated
Comment thread src/coreai_opt/inspection/bits_per_weight.py Outdated
Comment thread src/coreai_opt/inspection/bits_per_weight.py
Comment thread src/coreai_opt/inspection/bits_per_weight.py Outdated
Comment thread tests/export/test_bpw_export_size.py Outdated
Comment thread tests/export/test_bpw_export_size.py
Comment thread tests/export/test_bpw_export_size.py

# Sanity envelope for the qparam / LUT / bias overhead a sane config adds on top of the
# nominal bit width, in bpw. See _assert_bpw_is_plausible for why 2 and not 1.
_MAX_EXPECTED_OVERHEAD_BPW = 2.0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite a large upper bound; didn't find more information in _assert_bpw_is_plausible which explains this?

@pkmandke pkmandke Aug 21, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah so this is to basically accommodate for cases where the scale/LUTs would add non-trivial overhead. Even per-channel scales and minval add quite a bit of overhead. This gets highlighted here due to the models being relatively small. In real models, these should get amortized and the overhead (ideally) won't be this much. But it does depend on the config chosen. Like for a really small block/group size, the scale/LUT overhead will be non-trivial.

For eg, in this test file, the max overhead is 1.637 for the palettized[n8_per_tensor-pcs-bias] case. So I chose 2 as the bound..

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lmk if/how we should address this. We could only use configs for this smallish model that don't add such a large overhead, but that won't ensure config coverage for the actual BPW logic..

Comment thread tests/inspection/test_bits_per_weight.py Outdated
@pkmandke
pkmandke requested a review from anotheranshu August 20, 2026 00:22
pkmandke and others added 8 commits August 21, 2026 14:10
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
Co-authored-by: Utkarsh Simha <135899523+u-simha@users.noreply.github.com>
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>
Signed-off-by: Prathamesh Mandke <46148373+pkmandke@users.noreply.github.com>

def full_precision_bits(tensor: torch.Tensor) -> int:
"""Return the dense storage cost of a tensor in bits."""
return int(tensor.numel() * tensor.element_size() * 8)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Can we replace all usages of "8" with defining a _BITS_PER_BYTE = 8 and using that instead?


Args:
weight (torch.Tensor): The dense original weight tensor.
pal (_FakePalettizeImplBase): The weight fake-palettize parametrization.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, argument in the docstring is misnamed

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants