Skip to content

support lm-head/embed requant - #3050

Open
ZX-ModelCloud wants to merge 4 commits into
mainfrom
zx_support_requant
Open

support lm-head/embed requant#3050
ZX-ModelCloud wants to merge 4 commits into
mainfrom
zx_support_requant

Conversation

@ZX-ModelCloud

Copy link
Copy Markdown
Collaborator

No description provided.

Signed-off-by: ZX-ModelCloud <zx@modelcloud.ai>
faulthandler.register(
signal.SIGUSR1, file=sys.stderr, all_threads=True, chain=False
)
except (AttributeError, ValueError):
try:
with open(source_config_path, "r", encoding="utf-8") as handle:
tie_word_embeddings = bool(json.load(handle).get("tie_word_embeddings", False))
except (OSError, TypeError, ValueError):
@ZX-ModelCloud
ZX-ModelCloud marked this pull request as ready for review September 4, 2026 14:39
@ZX-ModelCloud

Copy link
Copy Markdown
Collaborator Author

PR Review
PR: #3050
Reviewed head SHA: 319aee2
Result: findings

Findings:

  1. Severity: medium
    File and line: optimize/requant_embed_lm_head.py:85
    Rationale: On a tied-weight model, get_output_embeddings() is the same object as the input embedding, and named_modules() normally resolves both endpoints to the input path. The CLI therefore deduplicates the output target here and installs the requested bits/group-size override only for the input path. ModuleLooper unties the modules later, producing a new lm_head path; that path then receives the hard-coded 8-bit/group-32 fallback instead of the requested output configuration. Output-only and both modes can silently quantize the output endpoint with the wrong settings.
    Action: Untie tied endpoints before resolving target_names, or explicitly carry the requested output override from the pre-untie alias to the new output module name. Add a tied-model test that asserts the effective config on both runtime paths.
  2. Severity: high
    File and line: gptqmodel/models/writer.py:291
    Rationale: Single-endpoint requantization cannot save a tied source checkpoint correctly. In output-only mode, matched_shards_by_prefix contains only the output prefix, so the fallback condition requiring the input prefix in that mapping is false and save raises at line 304 because tied checkpoints commonly omit lm_head.weight. In input-only mode, only the input replacement is written, but line 785 persists tie_word_embeddings=false after ModuleLooper cloned an untied output head; the cloned lm_head weight is never serialized, so reload has a missing output weight.
    Action: Resolve the original tied input shard independently of the selected replacement prefixes and serialize the untied output state whenever the saved config becomes untied, including input-only mode. Cover input-only and output-only saves from a source containing only the tied input tensor, then reload both outputs.
  3. Severity: medium
    File and line: gptqmodel/nn_modules/qlinear/init.py:1549
    Rationale: The embedding branch leaves int_weight with one row per vocabulary entry, but the packing loop always reads a full pack_factor rows from every ceil-sized qweight row. For vocabularies not divisible by pack_factor, such as GPT-2 with 50,257 tokens at 4 bits, the final iteration indexes beyond int_weight and crashes. The current unit test uses a five-row embedding but stops before packing, while the end-to-end checkpoint happens to have an aligned vocabulary.
    Action: Pad the embedding rows and corresponding g_idx to the packing width or bound and zero-fill the final partial word, and ensure dequantization preserves or slices to the original vocabulary size. Add a pack/save/reload/forward test with a non-divisible vocabulary.

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.

1 participant