// Browser front end. Every request goes straight from the visitor to // huggingface.co — this page has no backend and holds no token, so it // reads exactly what the visitor could read themselves. import { KNOWN_METHODS, EXCLUSION_FIELD, covers, moduleTree, modulePaths, resolveMethod, sameModule, unmatchedExclusions, } from './pack_check.js'; const HF = 'https://huggingface.co'; const $ = (id) => document.getElementById(id); // Tensor tails that mark a converted weight, used to compare a pack // against its source by module rather than by tensor name. const EXPECTED_UNQUANTIZED = new Set([ 'embed_tokens', 'lm_head', 'embed_out', 'A_log', 'dt_bias', 'conv1d', ]); function expectedUnquantized(module) { const tail = module.split('.').pop(); return EXPECTED_UNQUANTIZED.has(tail) || tail.endsWith('norm') || module.includes('.norm') || module.includes('embed') // embeddings are not LinearBase || tail.includes('conv'); // convolutions are not either } const esc = (s) => String(s).replace(/[&<>]/g, (c) => ({ '&': '&', '<': '<', '>': '>' }[c])); async function json(url) { const r = await fetch(url); if (!r.ok) throw new Error(`${r.status} ${r.statusText}`); return r.json(); } /** Tensor name -> shape, from safetensors headers only. * * Two ranged requests per shard: eight bytes for the header length, * then the header itself. A file of any size costs kilobytes. */ async function safetensorNames(repo) { const info = await json(`${HF}/api/models/${repo}`); const files = (info.siblings ?? []) .map((s) => s.rfilename) .filter((f) => f.endsWith('.safetensors')); const out = new Map(); await Promise.all(files.map(async (file) => { const url = `${HF}/${repo}/resolve/main/${file}`; const head = await fetch(url, { headers: { Range: 'bytes=0-7' } }); if (!head.ok) throw new Error(`${file}: ${head.status}`); const len = Number(new DataView(await head.arrayBuffer()) .getBigUint64(0, true)); const body = await fetch(url, { headers: { Range: `bytes=8-${8 + len - 1}` }, }); if (!body.ok) throw new Error(`${file}: ${body.status}`); for (const [name, entry] of Object.entries(JSON.parse(await body.text()))) { if (name !== '__metadata__') out.set(name, entry.shape ?? []); } })); return { names: out, info }; } function declared(quant, method, module, entries) { if (covers(quant, method, module)) return true; return entries.some((e) => { const t = String(e); return !t.startsWith('re:') && !t.startsWith('-:') && !t.startsWith('+:') && sameModule(t, module); }); } function card(kind, title, html) { return `
This repo has no .safetensors files.
No quantization_config, so nothing here could have '
+ 'been quantized away.
The checks reproduce the exclusion rules of compressed-tensors, ' + 'awq, gptq, bitsandbytes, modelopt and auto-round from vLLM\'s ' + 'source. Yours is not among them, so they are skipped rather than ' + 'guessed at.
'); } const out = []; const tree = moduleTree(names.keys()); // 1 — entries that name nothing const stray = unmatchedExclusions(quant, method, tree, tied); if (stray.length) { out.push(card('problem', `${stray.length} exclusion ${stray.length === 1 ? 'entry names' : 'entries name'} no module in this model`, 'They protect nothing, so whatever they were meant to keep was ' + 'quantized:
' + list(stray) + 'A common cause is a vision tower: Llama and Pixtral call it '
+ 'vision_tower, Qwen calls it visual.
from_pretrained does not materialise tensors the '
+ 'AutoModel class has no slot for, so they never reach the '
+ 'quantizer and never reach the artifact. For a '
+ 'multi-token-prediction head the symptom is 0% draft acceptance, '
+ 'with nothing in the logs.
${esc(base)} is named as the base but could not be `
+ `read (${esc(e.message)}), so that check was skipped.
A runtime builds these quantized, looks for a packed weight, finds ' + 'a plain one, and skips it — leaving the module randomly initialised ' + 'while the model still answers correctly.
' + list(undeclared, 12) + 'This is a prediction, not a measurement. Confirm '
+ 'it by serving the pack and grepping the startup log for '
+ 'not found in params_dict.
Every exclusion entry names a real module, no source module is ' + 'missing, and nothing is left at source precision without being ' + 'declared.
')); } return meta + out.join(''); } async function submit(event) { event?.preventDefault(); let repo = $('repo').value.trim().replace(/\/+$/, ''); if (!repo) return; if (repo.startsWith('http')) repo = repo.split('huggingface.co/').pop(); const out = $('out'); const button = $('go'); button.disabled = true; out.innerHTML = 'Reading headers…
'; try { out.innerHTML = await check(repo); } catch (e) { out.innerHTML = card('problem', `Could not check ${repo}`, `${esc(e.message)}
If the repo is gated or ` + `private, this page cannot read it — it has no token.
`); } finally { button.disabled = false; } } $('form').addEventListener('submit', submit); // Run once on load against the pre-filled example. A checker whose // first screen is empty asks the visitor to trust it before it has // shown them anything. submit(); for (const b of document.querySelectorAll('[data-ex]')) { b.addEventListener('click', () => { $('repo').value = b.dataset.ex; submit(); }); }