Repository navigation
feat(tools): add runntime quantize, a uv Python CLI that writes int8/int4 checkpoints in format v1 - #93
Merged
Conversation
chmjkb
force-pushed
the
@chmjkb/quant-minilm-e2e
branch
from
October 30, 2026 11:26
f510084 to
9513176
Compare
chmjkb
force-pushed
the
@chmjkb/python-quantizer
branch
from
October 30, 2026 11:26
4255299 to
ce5baab
Compare
chmjkb
force-pushed
the
@chmjkb/quant-minilm-e2e
branch
from
October 30, 2026 12:47
9513176 to
83bbd9e
Compare
chmjkb
force-pushed
the
@chmjkb/python-quantizer
branch
from
October 30, 2026 12:47
ce5baab to
38b4f11
Compare
chmjkb
force-pushed
the
@chmjkb/quant-minilm-e2e
branch
from
October 30, 2026 13:26
83bbd9e to
8306f44
Compare
chmjkb
force-pushed
the
@chmjkb/python-quantizer
branch
from
October 30, 2026 13:26
38b4f11 to
2bf87e9
Compare
chmjkb
force-pushed
the
@chmjkb/quant-minilm-e2e
branch
from
November 2, 2026 09:11
8306f44 to
d7432dd
Compare
chmjkb
force-pushed
the
@chmjkb/python-quantizer
branch
from
November 2, 2026 09:11
2bf87e9 to
b415564
Compare
chmjkb
force-pushed
the
@chmjkb/quant-minilm-e2e
branch
from
November 2, 2026 17:32
d7432dd to
8d1853d
Compare
chmjkb
force-pushed
the
@chmjkb/python-quantizer
branch
2 times, most recently
from
November 4, 2026 09:32
73334aa to
5e92e44
Compare
chmjkb
force-pushed
the
@chmjkb/quant-minilm-e2e
branch
from
November 4, 2026 09:32
8d1853d to
506da9c
Compare
chmjkb
force-pushed
the
@chmjkb/python-quantizer
branch
from
November 4, 2026 10:16
5e92e44 to
3c4e31a
Compare
chmjkb
marked this pull request as ready for review
November 4, 2026 15:05
xxpopielxx
reviewed
Nov 5, 2026
| raise ValueError("no tensor was quantized:\n" + "\n".join(report)) | ||
| setting = {"version": FORMAT_VERSION, "bits": options.bits, "groupSize": options.group_size, "scheme": "symmetric"} | ||
| metadata = checkpoint.metadata | {QUANT_METADATA_KEY: json.dumps(setting, separators=(",", ":"))} | ||
| write_safetensors(destination, tensors, metadata) |
Member
There was a problem hiding this comment.
If the output path is the same as the input, the input gets wiped. Runntime quantize m.safetensors m.safetensors --bits 8 crashes and leaves an empty file. Maybe write to a temp file first and rename it at the end?
| continue | ||
| reason = skip_reason(name, tensor, options) | ||
| if reason: | ||
| tensors[name] = to_float16(name, tensor) if options.float16 else tensor |
Member
There was a problem hiding this comment.
Running the tool on an already quantized file gives a file runntime can't load: --bits 4 on an int8 file exits 0, but the old int8 weights stay and the header says int4. I guess refuse a source that's already quantized?
| - It prints the max and mean absolute error of every quantized tensor and | ||
| why each other tensor was skipped. Exclude the layers that lose too much. | ||
|
|
||
| ## Development |
Member
There was a problem hiding this comment.
Don't we want to test this in CI too, on every change to tools/python?
…int4 checkpoints in format v1
…rough fromSafetensors
…shine's 288 and 416 inputs divide
…ming reads them as a lookup table
…ng every 3D tensor an expert
chmjkb
force-pushed
the
@chmjkb/python-quantizer
branch
from
November 5, 2026 11:42
d284954 to
0aaf88d
Compare
xxpopielxx
approved these changes
Nov 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Phase 3 of #70:
runntime quantize, a small Python CLI that writes int8/int4 checkpoints in format v1, the format the loader from #80–#82 reads.cd tools/python uv run runntime quantize model.safetensors model.int8.safetensors --bits 8 --f16tools/python(Python 3.11+, numpy only). pyright strict onsrc, ruff with a broad rule set, pytest..safetensorsfile or a Hugging Face model folder, sharded or not. Output is one.safetensorsfile. Untouched tensors are copied as stored (BF16 included) and the header metadata is kept, withrunntime.quantadded.*.weighttensors; embeddings (*embed*), position embeddings (*pos_emb*) andlm_headstay as stored.--include/--excludeglobs replace those defaults. A tensor is skipped when it would not load: in features a multiple of 8 and of the group size, out features a multiple of 4 (int8) or 8 (int4), the same rule asLinear.loadQuantized. Tensors that are not 2D (convs, experts) are skipped.--group-sizedefaults to 32, which divides the 288 and 416 inputs of Moonshine Tiny and Base.--f16stores the tensors that stay float as F16, and fails on a value beyond the f16 range.--dropleaves matching tensors out of the output, like MiniLM's unused pooler.scale = absmax / (2^(bits-1) - 1)rounded to f16,int = round(w / scale)(half to even) clamped to the symmetric range. int4 packs the even index in the low nibble.tools/python/tests/goldenholds a tiny float checkpoint and its int4 and int8 versions. The Python tests check the CLI reproduces them byte for byte and that the officialsafetensorslibrary reads them; a new test insafetensors.test.tsloads the same files throughfromSafetensorsand checks every value is within half a step of the float source.Introduces a breaking change?
Type of change
Testing instructions
cd tools/python && uv sync && uv run pytest(29 pass)uv run ruff check && uv run ruff format --check && uv run pyrightpnpm typecheck && pnpm lint && pnpm --filter runntime exec vitest run --project unit test/core/weights/safetensors.test.ts(103 pass, 2 new)Related issues
Part of #70. Stacked on #82.
Checklist
Additional notes
--bits 8 --f16writes 81.5 MB, against 123 MB for the f16 file.safetensorspackage, whose numpy API cannot read or write BF16. The package is a dev dependency, used to check the output.