Jonna Marie Matthiesen Copilot commited on
Commit Β·
19a0613
1
Parent(s): 2d4b81f
Add accuracy table above filters for model families with accuracy data
Browse filesAdd accuracy_file config key per model family pointing to a CSV with
accuracy benchmarks. When present, an accuracy table renders above the
filter buttons showing per-model scores with best values highlighted.
The table respects variant selection, filtering to active models.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- app.js +86 -0
- config.json +2 -1
- index.html +3 -0
app.js
CHANGED
|
@@ -59,6 +59,38 @@ async function loadFamilyData(familyKey) {
|
|
| 59 |
// Current family's loaded data
|
| 60 |
let DATA = [];
|
| 61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
// βββ Config shortcuts βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 63 |
|
| 64 |
const MODEL_COL = config.model_column;
|
|
@@ -705,6 +737,59 @@ function buildExperimentSetup() {
|
|
| 705 |
});
|
| 706 |
}
|
| 707 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 708 |
// βββ Render βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 709 |
|
| 710 |
function render() {
|
|
@@ -729,6 +814,7 @@ function render() {
|
|
| 729 |
(config.metrics.length <= 1 || !chartsShown) ? "none" : "";
|
| 730 |
}
|
| 731 |
buildTables(filtered, chartsShown);
|
|
|
|
| 732 |
buildExperimentSetup();
|
| 733 |
}
|
| 734 |
|
|
|
|
| 59 |
// Current family's loaded data
|
| 60 |
let DATA = [];
|
| 61 |
|
| 62 |
+
// βββ Accuracy data cache ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 63 |
+
|
| 64 |
+
const accDataCache = {};
|
| 65 |
+
|
| 66 |
+
async function loadAccuracyData(filePath) {
|
| 67 |
+
if (!filePath) return null;
|
| 68 |
+
if (accDataCache[filePath]) return accDataCache[filePath];
|
| 69 |
+
try {
|
| 70 |
+
const text = await fetch(filePath).then(r => {
|
| 71 |
+
if (!r.ok) return null;
|
| 72 |
+
return r.text();
|
| 73 |
+
});
|
| 74 |
+
if (!text) return null;
|
| 75 |
+
const lines = text.replace(/\r/g, "").trim().split("\n");
|
| 76 |
+
const headers = lines[0].split(",");
|
| 77 |
+
const rows = lines.slice(1).map(line => {
|
| 78 |
+
const vals = line.split(",");
|
| 79 |
+
const row = {};
|
| 80 |
+
headers.forEach((h, i) => {
|
| 81 |
+
const raw = (vals[i] || "").trim();
|
| 82 |
+
row[h] = raw;
|
| 83 |
+
});
|
| 84 |
+
return row;
|
| 85 |
+
});
|
| 86 |
+
const result = { headers, rows };
|
| 87 |
+
accDataCache[filePath] = result;
|
| 88 |
+
return result;
|
| 89 |
+
} catch {
|
| 90 |
+
return null;
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
// βββ Config shortcuts βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 95 |
|
| 96 |
const MODEL_COL = config.model_column;
|
|
|
|
| 737 |
});
|
| 738 |
}
|
| 739 |
|
| 740 |
+
// βββ Accuracy Table βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 741 |
+
|
| 742 |
+
async function buildAccuracyTable() {
|
| 743 |
+
const section = document.getElementById("accuracy-section");
|
| 744 |
+
section.innerHTML = "";
|
| 745 |
+
const familyCfg = config.model_families?.[activeFamilyKey()] || {};
|
| 746 |
+
const accFile = familyCfg.accuracy_file;
|
| 747 |
+
if (!accFile) return;
|
| 748 |
+
|
| 749 |
+
const accData = await loadAccuracyData(accFile);
|
| 750 |
+
if (!accData || !accData.rows.length) return;
|
| 751 |
+
|
| 752 |
+
// Filter to active models if a variant is selected
|
| 753 |
+
const activeModels = getActiveModelSet();
|
| 754 |
+
const rows = accData.rows.filter(r => activeModels.has(r[accData.headers[0]]));
|
| 755 |
+
if (!rows.length) return;
|
| 756 |
+
|
| 757 |
+
const modelCol = accData.headers[0];
|
| 758 |
+
const metricCols = accData.headers.slice(1);
|
| 759 |
+
|
| 760 |
+
const card = document.createElement("div");
|
| 761 |
+
card.className = "table-card";
|
| 762 |
+
|
| 763 |
+
let html = `<h3>Accuracy</h3><div class="table-scroll"><table><thead><tr>`;
|
| 764 |
+
html += `<th>MODEL</th>`;
|
| 765 |
+
html += metricCols.map(h => `<th class="metric-cell">${h}</th>`).join("");
|
| 766 |
+
html += `</tr></thead><tbody>`;
|
| 767 |
+
|
| 768 |
+
// Find best value per column (higher is better for accuracy)
|
| 769 |
+
const best = {};
|
| 770 |
+
metricCols.forEach(col => {
|
| 771 |
+
const vals = rows.map(r => parseFloat(r[col])).filter(v => !isNaN(v));
|
| 772 |
+
if (vals.length) best[col] = Math.max(...vals);
|
| 773 |
+
});
|
| 774 |
+
|
| 775 |
+
rows.forEach(r => {
|
| 776 |
+
const model = r[modelCol];
|
| 777 |
+
const modelColor = MODEL_COLORS[model]?.border || '#888';
|
| 778 |
+
html += `<tr><td class="model-cell"><span class="model-dot" style="background:${modelColor}"></span><a href="${LINK_PREFIX}${model}" target="_blank" rel="noopener" style="color:${modelColor}">${model}</a></td>`;
|
| 779 |
+
metricCols.forEach(col => {
|
| 780 |
+
const val = parseFloat(r[col]);
|
| 781 |
+
const isBest = !isNaN(val) && val === best[col];
|
| 782 |
+
const display = isNaN(val) ? (r[col] || "β") : val.toFixed(2);
|
| 783 |
+
html += `<td class="metric-cell">${isBest ? '<strong style="color: white; opacity: 0.7">' + display + '</strong>' : display}</td>`;
|
| 784 |
+
});
|
| 785 |
+
html += `</tr>`;
|
| 786 |
+
});
|
| 787 |
+
|
| 788 |
+
html += `</tbody></table></div>`;
|
| 789 |
+
card.innerHTML = html;
|
| 790 |
+
section.appendChild(card);
|
| 791 |
+
}
|
| 792 |
+
|
| 793 |
// βββ Render βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 794 |
|
| 795 |
function render() {
|
|
|
|
| 814 |
(config.metrics.length <= 1 || !chartsShown) ? "none" : "";
|
| 815 |
}
|
| 816 |
buildTables(filtered, chartsShown);
|
| 817 |
+
buildAccuracyTable();
|
| 818 |
buildExperimentSetup();
|
| 819 |
}
|
| 820 |
|
config.json
CHANGED
|
@@ -138,7 +138,8 @@
|
|
| 138 |
"agx_orin": "Measurement setup: NVIDIA AI IoT vLLM 0.14.0 tegra, 256 tokens generated, 10 warm-up runs, averaged over 25 runs.",
|
| 139 |
"orin_nano": "Measurement setup: NVIDIA AI IoT vLLM 0.14.0 tegra, 256 tokens generated, 10 warm-up runs, averaged over 25 runs."
|
| 140 |
},
|
| 141 |
-
"default_device": "orin_nano"
|
|
|
|
| 142 |
},
|
| 143 |
"Qwen3.5": {
|
| 144 |
"data_file": "data/Qwen3.5.csv",
|
|
|
|
| 138 |
"agx_orin": "Measurement setup: NVIDIA AI IoT vLLM 0.14.0 tegra, 256 tokens generated, 10 warm-up runs, averaged over 25 runs.",
|
| 139 |
"orin_nano": "Measurement setup: NVIDIA AI IoT vLLM 0.14.0 tegra, 256 tokens generated, 10 warm-up runs, averaged over 25 runs."
|
| 140 |
},
|
| 141 |
+
"default_device": "orin_nano",
|
| 142 |
+
"accuracy_file": "data/acc-Cosmos-Reason2.csv"
|
| 143 |
},
|
| 144 |
"Qwen3.5": {
|
| 145 |
"data_file": "data/Qwen3.5.csv",
|
index.html
CHANGED
|
@@ -28,6 +28,9 @@
|
|
| 28 |
<p class="hero-sub" id="hero-sub">Compare throughput and latency across devices and model variants.</p>
|
| 29 |
</header>
|
| 30 |
|
|
|
|
|
|
|
|
|
|
| 31 |
<!-- Filters -->
|
| 32 |
<section class="filters-bar" id="filters-bar"></section>
|
| 33 |
|
|
|
|
| 28 |
<p class="hero-sub" id="hero-sub">Compare throughput and latency across devices and model variants.</p>
|
| 29 |
</header>
|
| 30 |
|
| 31 |
+
<!-- Accuracy Table -->
|
| 32 |
+
<section id="accuracy-section"></section>
|
| 33 |
+
|
| 34 |
<!-- Filters -->
|
| 35 |
<section class="filters-bar" id="filters-bar"></section>
|
| 36 |
|