Spaces:
Running
Running
llama serve rename, 3-bit default floor, blank dominated warnings, band-worst heuristics, hide non-fits on best-sort
Browse files- fork.js +13 -3
- index.html +2 -2
- rankQuants.js +9 -9
fork.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
| 6 |
const API = "https://codelion-local-model-explorer.hf.space";
|
| 7 |
const $ = (s, r = document) => r.querySelector(s);
|
| 8 |
const $$ = (s, r = document) => [...r.querySelectorAll(s)];
|
| 9 |
-
let META = null, SCORES = null, runId = 0, offset = 0, total = 0;
|
| 10 |
|
| 11 |
function el(tag, cls, text) {
|
| 12 |
const n = document.createElement(tag);
|
|
@@ -59,7 +59,7 @@ function query(append) {
|
|
| 59 |
sort: $("#sort").value, family: $("#family").value || null, size: $("#size").value || null,
|
| 60 |
search: $("#search").value.trim() || null,
|
| 61 |
moe_only: $("#moe-only").checked, vision_only: $("#vision-only").checked,
|
| 62 |
-
fits_only: $("#fits-only").checked,
|
| 63 |
vram_only: r.kind === "gpu" && $("#vram-only").checked, mmproj: $("#mmproj").value,
|
| 64 |
offset: append ? offset : 0, limit: 24,
|
| 65 |
};
|
|
@@ -147,7 +147,8 @@ function renderDetail(m, body) {
|
|
| 147 |
if (sel && sel.commands) {
|
| 148 |
const row = el("div", "row");
|
| 149 |
const copy = el("button", "btn ghost", "Copy command");
|
| 150 |
-
|
|
|
|
| 151 |
copy.addEventListener("click", async () => {
|
| 152 |
try { await navigator.clipboard.writeText(pre.textContent); copy.textContent = "Copied"; }
|
| 153 |
catch { copy.textContent = "Select and copy"; }
|
|
@@ -360,6 +361,10 @@ async function search(append) {
|
|
| 360 |
$("#count").textContent = `${total.toLocaleString()} models`;
|
| 361 |
$("#more").hidden = offset >= total;
|
| 362 |
const r = rig();
|
|
|
|
|
|
|
|
|
|
|
|
|
| 363 |
|
| 364 |
for (const m of res.results) {
|
| 365 |
const ui = card(m);
|
|
@@ -395,6 +400,9 @@ async function search(append) {
|
|
| 395 |
if (hr) ui.status.append(el("div", "muted", hr));
|
| 396 |
const railEl = rail(pick.fit, r);
|
| 397 |
if (railEl) ui.status.append(railEl);
|
|
|
|
|
|
|
|
|
|
| 398 |
} else {
|
| 399 |
ui.status.textContent = warnings[0] || "Doesn't fit this hardware.";
|
| 400 |
}
|
|
@@ -405,6 +413,8 @@ async function search(append) {
|
|
| 405 |
}
|
| 406 |
}
|
| 407 |
await Promise.all(Array.from({ length: 4 }, worker));
|
|
|
|
|
|
|
| 408 |
}
|
| 409 |
|
| 410 |
let deb;
|
|
|
|
| 6 |
const API = "https://codelion-local-model-explorer.hf.space";
|
| 7 |
const $ = (s, r = document) => r.querySelector(s);
|
| 8 |
const $$ = (s, r = document) => [...r.querySelectorAll(s)];
|
| 9 |
+
let META = null, SCORES = null, runId = 0, offset = 0, total = 0, nofitDropped = 0;
|
| 10 |
|
| 11 |
function el(tag, cls, text) {
|
| 12 |
const n = document.createElement(tag);
|
|
|
|
| 59 |
sort: $("#sort").value, family: $("#family").value || null, size: $("#size").value || null,
|
| 60 |
search: $("#search").value.trim() || null,
|
| 61 |
moe_only: $("#moe-only").checked, vision_only: $("#vision-only").checked,
|
| 62 |
+
fits_only: $("#fits-only").checked || $("#sort").value === "best",
|
| 63 |
vram_only: r.kind === "gpu" && $("#vram-only").checked, mmproj: $("#mmproj").value,
|
| 64 |
offset: append ? offset : 0, limit: 24,
|
| 65 |
};
|
|
|
|
| 147 |
if (sel && sel.commands) {
|
| 148 |
const row = el("div", "row");
|
| 149 |
const copy = el("button", "btn ghost", "Copy command");
|
| 150 |
+
// upstream still emits the old `llama-server` binary name; current llama.cpp renamed it.
|
| 151 |
+
const pre = el("pre", "cmd", (sel.commands["llama.cpp"] || "").replace(/llama-server/g, "llama serve"));
|
| 152 |
copy.addEventListener("click", async () => {
|
| 153 |
try { await navigator.clipboard.writeText(pre.textContent); copy.textContent = "Copied"; }
|
| 154 |
catch { copy.textContent = "Select and copy"; }
|
|
|
|
| 361 |
$("#count").textContent = `${total.toLocaleString()} models`;
|
| 362 |
$("#more").hidden = offset >= total;
|
| 363 |
const r = rig();
|
| 364 |
+
// best-sort promises fitting models, so non-fits are filtered server-side
|
| 365 |
+
// (fits_only above) and dropped client-side (headroom residuals) below.
|
| 366 |
+
const bestSort = q.sort === "best";
|
| 367 |
+
if (!append) nofitDropped = 0;
|
| 368 |
|
| 369 |
for (const m of res.results) {
|
| 370 |
const ui = card(m);
|
|
|
|
| 400 |
if (hr) ui.status.append(el("div", "muted", hr));
|
| 401 |
const railEl = rail(pick.fit, r);
|
| 402 |
if (railEl) ui.status.append(railEl);
|
| 403 |
+
} else if (bestSort) {
|
| 404 |
+
ui.c.remove();
|
| 405 |
+
nofitDropped++;
|
| 406 |
} else {
|
| 407 |
ui.status.textContent = warnings[0] || "Doesn't fit this hardware.";
|
| 408 |
}
|
|
|
|
| 413 |
}
|
| 414 |
}
|
| 415 |
await Promise.all(Array.from({ length: 4 }, worker));
|
| 416 |
+
if (alive() && bestSort) $("#count").textContent =
|
| 417 |
+
`${(total - nofitDropped).toLocaleString()} models that fit your hardware`;
|
| 418 |
}
|
| 419 |
|
| 420 |
let deb;
|
index.html
CHANGED
|
@@ -103,7 +103,7 @@
|
|
| 103 |
<option value="q4_0">4-bit (q4_0) — bench: small KL cost</option>
|
| 104 |
</select></div>
|
| 105 |
<div class="field"><label for="mmproj">Vision projector (vision models)</label><select id="mmproj">
|
| 106 |
-
<option value="gpu">On the GPU, llama
|
| 107 |
<option value="ram">In system RAM (--no-mmproj-offload)</option>
|
| 108 |
<option value="off">Don't load it, text only (--no-mmproj)</option>
|
| 109 |
</select></div>
|
|
@@ -122,7 +122,7 @@
|
|
| 122 |
<div class="field"><label for="min-bits">Lowest quant to consider</label><select id="min-bits">
|
| 123 |
<option value="0">Any, down to 1-bit</option>
|
| 124 |
<option value="2">2-bit and up</option>
|
| 125 |
-
<option value="3">3-bit and up</option>
|
| 126 |
<option value="4">4-bit and up (Q4, IQ4, MXFP4)</option>
|
| 127 |
<option value="5">5-bit and up</option>
|
| 128 |
<option value="6">6-bit and up</option>
|
|
|
|
| 103 |
<option value="q4_0">4-bit (q4_0) — bench: small KL cost</option>
|
| 104 |
</select></div>
|
| 105 |
<div class="field"><label for="mmproj">Vision projector (vision models)</label><select id="mmproj">
|
| 106 |
+
<option value="gpu">On the GPU, llama serve default</option>
|
| 107 |
<option value="ram">In system RAM (--no-mmproj-offload)</option>
|
| 108 |
<option value="off">Don't load it, text only (--no-mmproj)</option>
|
| 109 |
</select></div>
|
|
|
|
| 122 |
<div class="field"><label for="min-bits">Lowest quant to consider</label><select id="min-bits">
|
| 123 |
<option value="0">Any, down to 1-bit</option>
|
| 124 |
<option value="2">2-bit and up</option>
|
| 125 |
+
<option value="3" selected>3-bit and up</option>
|
| 126 |
<option value="4">4-bit and up (Q4, IQ4, MXFP4)</option>
|
| 127 |
<option value="5">5-bit and up</option>
|
| 128 |
<option value="6">6-bit and up</option>
|
rankQuants.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
| 7 |
* recommend/model handlers; fit estimation stays untouched.
|
| 8 |
*
|
| 9 |
* Single mode: best measured quality that sits fully on the hardware
|
| 10 |
-
* wins, with warnings when nothing fits fully / only sub-4-bit fits
|
| 11 |
-
*
|
| 12 |
*
|
| 13 |
* Fit awareness: full offloads (tier gpu/gpu_moe/cpu/unified/ram) always
|
| 14 |
* outrank partial ones. A partial "quality" pick (e.g. 12 of 64 layers on
|
|
@@ -52,11 +52,14 @@ function scoreMap(scoresJson) {
|
|
| 52 |
// measurement; ties break measured-first in the sort below.
|
| 53 |
function classifyUnknown(quant) {
|
| 54 |
const q = quant.toUpperCase();
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
| 56 |
const bit = q.match(/(\d(\.\d)?)\s*BIT/);
|
| 57 |
-
if (bit) return parseFloat(bit[1]) < 4 ? ["emergency",
|
| 58 |
-
if (/IQ1|1BIT|_I1|TERNARY|Q1(?!\d)/.test(q)) return ["emergency",
|
| 59 |
-
if (/Q2|IQ2/.test(q)) return ["emergency",
|
| 60 |
if (/IQ3|Q3/.test(q)) return ["tight", 0.1166];
|
| 61 |
if (/Q4|IQ4|MXFP4/.test(q)) return ["default", 0.0541];
|
| 62 |
if (/Q5|Q6/.test(q)) return ["step", 0.0118];
|
|
@@ -164,9 +167,6 @@ function rankOptions(options, family, scoresJson) {
|
|
| 164 |
|
| 165 |
// best measured quality that fits. no band caps.
|
| 166 |
let pick = byKlThenPub(cands, family)[0];
|
| 167 |
-
if (pick.band === "avoid") {
|
| 168 |
-
warnings.push(`legacy pick: ${pick.quant} is an outdated format — nothing better in this repo`);
|
| 169 |
-
}
|
| 170 |
|
| 171 |
const ranked = byKlThenPub(cands, family);
|
| 172 |
const twins = cands.filter((o) => o.quant.toUpperCase() === pick.quant.toUpperCase());
|
|
|
|
| 7 |
* recommend/model handlers; fit estimation stays untouched.
|
| 8 |
*
|
| 9 |
* Single mode: best measured quality that sits fully on the hardware
|
| 10 |
+
* wins, with warnings when nothing fits fully / only sub-4-bit fits.
|
| 11 |
+
* no band caps: if Q8_0 fits, it wins.
|
| 12 |
*
|
| 13 |
* Fit awareness: full offloads (tier gpu/gpu_moe/cpu/unified/ram) always
|
| 14 |
* outrank partial ones. A partial "quality" pick (e.g. 12 of 64 layers on
|
|
|
|
| 52 |
// measurement; ties break measured-first in the sort below.
|
| 53 |
function classifyUnknown(quant) {
|
| 54 |
const q = quant.toUpperCase();
|
| 55 |
+
// heuristic kl must equal the WORST measured kl in its band (avoid
|
| 56 |
+
// 0.5345 = UD-Q2_K_XL, emergency 1.0 = UD-IQ2_XXS; see quant_scores.json)
|
| 57 |
+
// so a guess never outranks a measurement; ties break measured-first.
|
| 58 |
+
if (/Q4_0|Q4_1|Q3_K_S|Q3_K_M|Q5_K_S|Q4_K_S|Q4_K_L|Q5_0|Q3_0/.test(q)) return ["avoid", 0.5345];
|
| 59 |
const bit = q.match(/(\d(\.\d)?)\s*BIT/);
|
| 60 |
+
if (bit) return parseFloat(bit[1]) < 4 ? ["emergency", 1.0] : ["tight", 0.1166];
|
| 61 |
+
if (/IQ1|1BIT|_I1|TERNARY|Q1(?!\d)/.test(q)) return ["emergency", 1.0];
|
| 62 |
+
if (/Q2|IQ2/.test(q)) return ["emergency", 1.0];
|
| 63 |
if (/IQ3|Q3/.test(q)) return ["tight", 0.1166];
|
| 64 |
if (/Q4|IQ4|MXFP4/.test(q)) return ["default", 0.0541];
|
| 65 |
if (/Q5|Q6/.test(q)) return ["step", 0.0118];
|
|
|
|
| 167 |
|
| 168 |
// best measured quality that fits. no band caps.
|
| 169 |
let pick = byKlThenPub(cands, family)[0];
|
|
|
|
|
|
|
|
|
|
| 170 |
|
| 171 |
const ranked = byKlThenPub(cands, family);
|
| 172 |
const twins = cands.filter((o) => o.quant.toUpperCase() === pick.quant.toUpperCase());
|