Upload folder using huggingface_hub
Browse files- index.html +176 -83
index.html
CHANGED
|
@@ -145,6 +145,9 @@
|
|
| 145 |
border-bottom: 2px solid var(--border-strong);
|
| 146 |
text-transform: uppercase; letter-spacing: 0.03em; font-size: 0.72rem;
|
| 147 |
}
|
|
|
|
|
|
|
|
|
|
| 148 |
table.dt td {
|
| 149 |
padding: 0.5rem 0.65rem; border-bottom: 1px solid var(--border);
|
| 150 |
vertical-align: middle;
|
|
@@ -182,6 +185,8 @@
|
|
| 182 |
font-family: var(--mono); font-weight: 600; font-size: 0.72rem;
|
| 183 |
}
|
| 184 |
.cell-val { color: var(--good); background: var(--good-bg); padding: 0.15rem 0.35rem; border-radius: 3px; }
|
|
|
|
|
|
|
| 185 |
.cell-plan { color: var(--warn); background: var(--warn-bg); padding: 0.15rem 0.35rem; border-radius: 3px; }
|
| 186 |
.cell-none { color: var(--text-muted); opacity: 0.5; }
|
| 187 |
.cell-target { color: var(--text-muted); background: #f4f4f4; padding: 0.15rem 0.35rem; border-radius: 3px; }
|
|
@@ -452,19 +457,6 @@
|
|
| 452 |
</div>
|
| 453 |
</div>
|
| 454 |
|
| 455 |
-
<div class="section">
|
| 456 |
-
<div class="section-header"><h2>Accuracy vs On-target Throughput</h2>
|
| 457 |
-
<span class="section-note">COCO val2017 · pipelined FPS measured on each platform by the <a href="https://doc.edgefirst.ai/latest/profiler/" target="_blank" rel="noopener" style="color:var(--teal-text)">EdgeFirst Profiler</a></span>
|
| 458 |
-
</div>
|
| 459 |
-
<div class="chart-host" style="height:420px"><canvas id="chart-det-fps"></canvas></div>
|
| 460 |
-
<p style="font-family:var(--serif);color:var(--text-muted);font-size:0.82rem;margin-top:0.5rem">
|
| 461 |
-
Each point is a public validation session: color = platform, shape = model family
|
| 462 |
-
(● YOLOv5 · ■ YOLOv8 · ▲ YOLO11 · ◆ YOLO26). X axis is sustained pipelined throughput on a log
|
| 463 |
-
scale — the full image load → decode → preprocess → inference → postprocess pipeline, not bare
|
| 464 |
-
inference time. ⚠ flagged sessions are shown at their measured accuracy.
|
| 465 |
-
</p>
|
| 466 |
-
</div>
|
| 467 |
-
|
| 468 |
<div class="section">
|
| 469 |
<div class="section-header"><h2>Nano Segmentation — Mask mAP</h2>
|
| 470 |
<span class="section-note">YOLOv8 / YOLO11 / YOLO26, COCO val2017</span>
|
|
@@ -482,12 +474,25 @@
|
|
| 482 |
</div>
|
| 483 |
|
| 484 |
<div class="section">
|
| 485 |
-
<div class="section-header"><h2>On-target
|
| 486 |
-
<span class="section-note">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 487 |
</div>
|
| 488 |
<div id="timing-host">
|
| 489 |
<p style="font-family:var(--serif);color:var(--text-muted);font-size:0.92rem">
|
| 490 |
-
On-target latency
|
| 491 |
See the <a href="https://doc.edgefirst.ai/latest/profiler/" target="_blank" rel="noopener" style="color:var(--teal-text)">EdgeFirst Profiler documentation</a>
|
| 492 |
for how profiling and validation are performed.
|
| 493 |
</p>
|
|
@@ -509,16 +514,16 @@
|
|
| 509 |
</div>
|
| 510 |
<table class="dt" id="studio-table" style="display:none">
|
| 511 |
<thead><tr>
|
| 512 |
-
<th>Session</th>
|
| 513 |
-
<th>Family · Task</th>
|
| 514 |
-
<th>Target</th>
|
| 515 |
-
<th>Precision</th>
|
| 516 |
-
<th>Det mAP<sub>50</sub></th>
|
| 517 |
-
<th>Det mAP<sub>50-95</sub></th>
|
| 518 |
-
<th>Mask mAP<sub>50-95</sub></th>
|
| 519 |
-
<th>Inf (ms)</th>
|
| 520 |
-
<th>E2E (ms)</th>
|
| 521 |
-
<th>FPS</th>
|
| 522 |
<th>Studio</th>
|
| 523 |
</tr></thead>
|
| 524 |
<tbody id="studio-body"></tbody>
|
|
@@ -545,7 +550,7 @@
|
|
| 545 |
<div class="coverage-wrap"><table class="matrix" id="coverage-seg"></table></div>
|
| 546 |
</div>
|
| 547 |
<div class="legend">
|
| 548 |
-
<span><span class="swatch" style="background:var(--good-bg);border:1px solid var(--good)"></span>Validated —
|
| 549 |
<span><span class="swatch" style="background:transparent;border:1px solid var(--border)"></span>Validation pending</span>
|
| 550 |
</div>
|
| 551 |
</section>
|
|
@@ -568,7 +573,7 @@
|
|
| 568 |
<section class="tab-panel" id="tab-leaderboard">
|
| 569 |
<div class="section">
|
| 570 |
<div class="section-header"><h2>Platform Throughput Leaderboard</h2>
|
| 571 |
-
<span class="section-note">
|
| 572 |
</div>
|
| 573 |
<table class="dt">
|
| 574 |
<thead><tr>
|
|
@@ -634,9 +639,14 @@
|
|
| 634 |
// Platforms as rows: hosts (reference) first, then embedded targets, then Jetson.
|
| 635 |
// `match` is tested (in order) against the Studio target/footer string to map a
|
| 636 |
// validation session onto a platform row.
|
|
|
|
|
|
|
|
|
|
| 637 |
const PLATFORM_ROWS = [
|
| 638 |
{ key: "linux-x86", label: "Linux x86_64", detail: "ONNX Runtime + CUDA", group: "reference", color: "#6C757D", match: /linux|x86|cuda/ },
|
| 639 |
-
{ key: "m2max",
|
|
|
|
|
|
|
| 640 |
{ key: "imx8mp", label: "NXP i.MX 8M Plus", detail: "VSI NPU · TFLite INT8", group: "embedded", color: "#E8B820", match: /imx8mp/ },
|
| 641 |
{ key: "imx93", label: "NXP i.MX 93", detail: "Ethos-U65 · VELA TFLite", group: "embedded", color: "#8B7DC4", match: /imx93/ },
|
| 642 |
{ key: "imx95", label: "NXP i.MX 95", detail: "eIQ Neutron · TFLite INT8", group: "embedded", color: "#1FA0A8", match: /imx95/ },
|
|
@@ -822,13 +832,20 @@ const COVERAGE_SIZES = ["n", "s", "m"];
|
|
| 822 |
const SIZE_NAMES = { n: "Nano", s: "Small", m: "Medium" };
|
| 823 |
|
| 824 |
// Build a lookup of validated (task, version, size, platform) cells from the
|
| 825 |
-
// embedded Studio sessions.
|
|
|
|
| 826 |
function coverageLookup() {
|
| 827 |
const seen = {};
|
| 828 |
for (const s of (STUDIO?.sessions ?? [])) {
|
| 829 |
const p = platformRowForSession(s);
|
| 830 |
if (!p || !s.has_metrics) continue;
|
| 831 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 832 |
}
|
| 833 |
return seen;
|
| 834 |
}
|
|
@@ -868,8 +885,9 @@ function renderCoverageTable(taskKey, tableId, seen) {
|
|
| 868 |
for (const v of versions) {
|
| 869 |
for (const sz of COVERAGE_SIZES) {
|
| 870 |
const td = el("td");
|
| 871 |
-
|
| 872 |
-
|
|
|
|
| 873 |
} else {
|
| 874 |
td.innerHTML = '<span class="cell cell-none">—</span>';
|
| 875 |
}
|
|
@@ -971,23 +989,27 @@ function leaderboardEntries(platformKey, metricKey) {
|
|
| 971 |
}));
|
| 972 |
}
|
| 973 |
|
| 974 |
-
// Cross-platform throughput board:
|
| 975 |
-
// pipelined FPS (accuracy intentionally not
|
|
|
|
| 976 |
function renderPlatformThroughput() {
|
| 977 |
const host = document.getElementById("platform-fps-body");
|
| 978 |
if (!host) return;
|
| 979 |
host.innerHTML = "";
|
| 980 |
-
const
|
| 981 |
-
for (const
|
| 982 |
-
|
| 983 |
-
|
| 984 |
-
|
| 985 |
-
|
| 986 |
-
|
|
|
|
|
|
|
| 987 |
}
|
| 988 |
-
if (top) rows.push({ p, s: top });
|
| 989 |
}
|
| 990 |
-
rows
|
|
|
|
|
|
|
| 991 |
for (let i = 0; i < rows.length; i++) {
|
| 992 |
const { p, s } = rows[i];
|
| 993 |
const tr = el("tr");
|
|
@@ -1005,7 +1027,8 @@ function renderPlatformThroughput() {
|
|
| 1005 |
function renderLeaderboard() {
|
| 1006 |
const grid = document.getElementById("leaderboard-grid");
|
| 1007 |
grid.innerHTML = "";
|
| 1008 |
-
const platforms = PLATFORM_ROWS.filter(p =>
|
|
|
|
| 1009 |
const metricLabel = lbMetric === "fps"
|
| 1010 |
? "Pipelined throughput FPS (higher is better)"
|
| 1011 |
: "mAP@0.5-0.95 (higher is better)";
|
|
@@ -1120,7 +1143,7 @@ function chartDetFps() {
|
|
| 1120 |
const datasets = PLATFORM_ROWS.filter(p => byPlatform[p.key]).map(p => {
|
| 1121 |
const pts = byPlatform[p.key];
|
| 1122 |
return {
|
| 1123 |
-
label: p.label,
|
| 1124 |
data: pts.map(s => ({
|
| 1125 |
x: s.fps_median,
|
| 1126 |
y: s.det_map_50_95,
|
|
@@ -1309,13 +1332,6 @@ function totalMs(s) {
|
|
| 1309 |
return v > 0 ? v : null;
|
| 1310 |
}
|
| 1311 |
|
| 1312 |
-
function studioSessionLabel(s) {
|
| 1313 |
-
const sz = s.size ? s.size.toUpperCase() : "?";
|
| 1314 |
-
const tk = s.task_key === "det" ? "Det" : "Seg";
|
| 1315 |
-
const tgt = s.target_label || s.target_raw || s.format_key || "?";
|
| 1316 |
-
return `${s.version_key?.toUpperCase()}${sz}-${tk} · ${tgt}`;
|
| 1317 |
-
}
|
| 1318 |
-
|
| 1319 |
function renderStudio() {
|
| 1320 |
const table = document.getElementById("studio-table");
|
| 1321 |
const empty = document.getElementById("studio-empty");
|
|
@@ -1329,27 +1345,93 @@ function renderStudio() {
|
|
| 1329 |
empty.style.display = "none";
|
| 1330 |
table.style.display = "";
|
| 1331 |
const okCount = STUDIO.counts?.sessions_ok ?? STUDIO.counts?.ok ?? STUDIO.sessions.length;
|
| 1332 |
-
source.innerHTML = `updated <code>${STUDIO.generated_at}</code> · ${okCount} public sessions · every row links to <a href="https://edgefirst.studio" target="_blank" rel="noopener" style="color:var(--teal-text)">EdgeFirst Studio</a>`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1333 |
|
| 1334 |
-
|
| 1335 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1336 |
|
| 1337 |
-
|
| 1338 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1339 |
const targetOrder = ["onnx", "tflite", "imx93", "imx95", "imx8mp", "ara240", "hailo8l", "hailo8", "hailo10", "engine"];
|
| 1340 |
-
|
| 1341 |
if (a.task_key !== b.task_key) return a.task_key.localeCompare(b.task_key);
|
| 1342 |
const ai = VERSION_ORDER.indexOf(a.version_key);
|
| 1343 |
const bi = VERSION_ORDER.indexOf(b.version_key);
|
| 1344 |
if (ai !== bi) return ai - bi;
|
| 1345 |
-
const si =
|
| 1346 |
if (si !== sj) return si - sj;
|
| 1347 |
const ti = targetOrder.indexOf(a.target_key) === -1 ? 99 : targetOrder.indexOf(a.target_key);
|
| 1348 |
const tj = targetOrder.indexOf(b.target_key) === -1 ? 99 : targetOrder.indexOf(b.target_key);
|
| 1349 |
if (ti !== tj) return ti - tj;
|
| 1350 |
return (a.precision || "").localeCompare(b.precision || "");
|
| 1351 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1352 |
|
|
|
|
| 1353 |
for (const s of sessions) {
|
| 1354 |
const total = totalMs(s);
|
| 1355 |
const tr = el("tr");
|
|
@@ -1377,13 +1459,13 @@ function renderStudio() {
|
|
| 1377 |
}
|
| 1378 |
}
|
| 1379 |
|
| 1380 |
-
//
|
|
|
|
| 1381 |
function renderTiming() {
|
| 1382 |
const host = document.getElementById("timing-host");
|
| 1383 |
if (!host) return;
|
| 1384 |
const usable = (STUDIO?.sessions ?? []).filter(s =>
|
| 1385 |
-
|
| 1386 |
-
typeof s.det_map_50_95 === "number"
|
| 1387 |
);
|
| 1388 |
if (usable.length === 0) {
|
| 1389 |
// leave the default placeholder copy
|
|
@@ -1391,29 +1473,38 @@ function renderTiming() {
|
|
| 1391 |
}
|
| 1392 |
|
| 1393 |
host.innerHTML = `
|
| 1394 |
-
<div class="chart-host" style="height:
|
| 1395 |
<p style="font-family:var(--serif);color:var(--text-muted);font-size:0.82rem;margin-top:0.5rem">
|
| 1396 |
-
Each point is a public
|
| 1397 |
-
|
| 1398 |
-
|
|
|
|
| 1399 |
</p>
|
| 1400 |
`;
|
| 1401 |
|
| 1402 |
-
const
|
| 1403 |
for (const s of usable) {
|
| 1404 |
-
|
| 1405 |
-
|
| 1406 |
-
|
| 1407 |
-
label: studioSessionLabel(s),
|
| 1408 |
-
});
|
| 1409 |
}
|
| 1410 |
-
|
| 1411 |
-
|
| 1412 |
-
|
| 1413 |
-
|
| 1414 |
-
|
| 1415 |
-
|
| 1416 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1417 |
|
| 1418 |
destroyChart("timing");
|
| 1419 |
charts.timing = new Chart(document.getElementById("chart-timing"), {
|
|
@@ -1425,13 +1516,15 @@ function renderTiming() {
|
|
| 1425 |
legend: { display: true, position: "bottom" },
|
| 1426 |
tooltip: {
|
| 1427 |
callbacks: {
|
| 1428 |
-
label: (ctx) => `${ctx.raw.label}: ${ctx.parsed.y}
|
| 1429 |
},
|
| 1430 |
},
|
| 1431 |
},
|
| 1432 |
scales: {
|
| 1433 |
-
x: {
|
| 1434 |
-
|
|
|
|
|
|
|
| 1435 |
y: { title: { display: true, text: "mAP@0.5-0.95 (%)" }, beginAtZero: false,
|
| 1436 |
ticks: { font: { family: "monospace", size: 10 } } },
|
| 1437 |
},
|
|
|
|
| 145 |
border-bottom: 2px solid var(--border-strong);
|
| 146 |
text-transform: uppercase; letter-spacing: 0.03em; font-size: 0.72rem;
|
| 147 |
}
|
| 148 |
+
table.dt th[data-sort] { cursor: pointer; user-select: none; white-space: nowrap; }
|
| 149 |
+
table.dt th[data-sort]:hover { color: var(--navy); }
|
| 150 |
+
table.dt th .sort-ind { color: var(--gold); margin-left: 0.2rem; }
|
| 151 |
table.dt td {
|
| 152 |
padding: 0.5rem 0.65rem; border-bottom: 1px solid var(--border);
|
| 153 |
vertical-align: middle;
|
|
|
|
| 185 |
font-family: var(--mono); font-weight: 600; font-size: 0.72rem;
|
| 186 |
}
|
| 187 |
.cell-val { color: var(--good); background: var(--good-bg); padding: 0.15rem 0.35rem; border-radius: 3px; }
|
| 188 |
+
a.cell-val { text-decoration: none; cursor: pointer; }
|
| 189 |
+
a.cell-val:hover { background: var(--good); color: #fff; }
|
| 190 |
.cell-plan { color: var(--warn); background: var(--warn-bg); padding: 0.15rem 0.35rem; border-radius: 3px; }
|
| 191 |
.cell-none { color: var(--text-muted); opacity: 0.5; }
|
| 192 |
.cell-target { color: var(--text-muted); background: #f4f4f4; padding: 0.15rem 0.35rem; border-radius: 3px; }
|
|
|
|
| 457 |
</div>
|
| 458 |
</div>
|
| 459 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 460 |
<div class="section">
|
| 461 |
<div class="section-header"><h2>Nano Segmentation — Mask mAP</h2>
|
| 462 |
<span class="section-note">YOLOv8 / YOLO11 / YOLO26, COCO val2017</span>
|
|
|
|
| 474 |
</div>
|
| 475 |
|
| 476 |
<div class="section">
|
| 477 |
+
<div class="section-header"><h2>Accuracy vs On-target Throughput</h2>
|
| 478 |
+
<span class="section-note">COCO val2017 · pipelined FPS measured on each platform by the <a href="https://doc.edgefirst.ai/latest/profiler/" target="_blank" rel="noopener" style="color:var(--teal-text)">EdgeFirst Profiler</a></span>
|
| 479 |
+
</div>
|
| 480 |
+
<div class="chart-host" style="height:420px"><canvas id="chart-det-fps"></canvas></div>
|
| 481 |
+
<p style="font-family:var(--serif);color:var(--text-muted);font-size:0.82rem;margin-top:0.5rem">
|
| 482 |
+
Each point is a public validation session: color = platform, shape = model family
|
| 483 |
+
(● YOLOv5 · ■ YOLOv8 · ▲ YOLO11 · ◆ YOLO26). X axis is sustained pipelined throughput on a log
|
| 484 |
+
scale — the full image load → decode → preprocess → inference → postprocess pipeline, not bare
|
| 485 |
+
inference time. ⚠ flagged sessions are shown at their measured accuracy.
|
| 486 |
+
</p>
|
| 487 |
+
</div>
|
| 488 |
+
|
| 489 |
+
<div class="section">
|
| 490 |
+
<div class="section-header"><h2>Accuracy vs On-target Latency</h2>
|
| 491 |
+
<span class="section-note">End-to-end per-image latency measured by the <a href="https://doc.edgefirst.ai/latest/profiler/" target="_blank" rel="noopener" style="color:var(--teal-text)">EdgeFirst Profiler</a> on deployment hardware</span>
|
| 492 |
</div>
|
| 493 |
<div id="timing-host">
|
| 494 |
<p style="font-family:var(--serif);color:var(--text-muted);font-size:0.92rem">
|
| 495 |
+
On-target latency results are being collected across the platform matrix.
|
| 496 |
See the <a href="https://doc.edgefirst.ai/latest/profiler/" target="_blank" rel="noopener" style="color:var(--teal-text)">EdgeFirst Profiler documentation</a>
|
| 497 |
for how profiling and validation are performed.
|
| 498 |
</p>
|
|
|
|
| 514 |
</div>
|
| 515 |
<table class="dt" id="studio-table" style="display:none">
|
| 516 |
<thead><tr>
|
| 517 |
+
<th data-sort="session">Session</th>
|
| 518 |
+
<th data-sort="family">Family · Task</th>
|
| 519 |
+
<th data-sort="target">Target</th>
|
| 520 |
+
<th data-sort="precision">Precision</th>
|
| 521 |
+
<th data-sort="det50">Det mAP<sub>50</sub></th>
|
| 522 |
+
<th data-sort="det5095">Det mAP<sub>50-95</sub></th>
|
| 523 |
+
<th data-sort="mask">Mask mAP<sub>50-95</sub></th>
|
| 524 |
+
<th data-sort="inf">Inf (ms)</th>
|
| 525 |
+
<th data-sort="e2e">E2E (ms)</th>
|
| 526 |
+
<th data-sort="fps">FPS</th>
|
| 527 |
<th>Studio</th>
|
| 528 |
</tr></thead>
|
| 529 |
<tbody id="studio-body"></tbody>
|
|
|
|
| 550 |
<div class="coverage-wrap"><table class="matrix" id="coverage-seg"></table></div>
|
| 551 |
</div>
|
| 552 |
<div class="legend">
|
| 553 |
+
<span><span class="swatch" style="background:var(--good-bg);border:1px solid var(--good)"></span>Validated — click ✓ to open the proving session on EdgeFirst Studio</span>
|
| 554 |
<span><span class="swatch" style="background:transparent;border:1px solid var(--border)"></span>Validation pending</span>
|
| 555 |
</div>
|
| 556 |
</section>
|
|
|
|
| 573 |
<section class="tab-panel" id="tab-leaderboard">
|
| 574 |
<div class="section">
|
| 575 |
<div class="section-header"><h2>Platform Throughput Leaderboard</h2>
|
| 576 |
+
<span class="section-note">Top 20 fastest validated model × platform results · full image load → decode → preprocess → inference → postprocess pipeline</span>
|
| 577 |
</div>
|
| 578 |
<table class="dt">
|
| 579 |
<thead><tr>
|
|
|
|
| 639 |
// Platforms as rows: hosts (reference) first, then embedded targets, then Jetson.
|
| 640 |
// `match` is tested (in order) against the Studio target/footer string to map a
|
| 641 |
// validation session onto a platform row.
|
| 642 |
+
// The three CoreML compute units are separate accelerators on one host —
|
| 643 |
+
// each gets its own coverage row, but only the ANE (the fastest) is ranked
|
| 644 |
+
// in leaderboards; CPU/GPU numbers remain in the validation sessions table.
|
| 645 |
const PLATFORM_ROWS = [
|
| 646 |
{ key: "linux-x86", label: "Linux x86_64", detail: "ONNX Runtime + CUDA", group: "reference", color: "#6C757D", match: /linux|x86|cuda/ },
|
| 647 |
+
{ key: "m2max-ane", label: "Apple M2 Max", detail: "ONNX + CoreML ANE", group: "reference", color: "#4B0082", match: /coreml-ane/ },
|
| 648 |
+
{ key: "m2max-gpu", label: "Apple M2 Max", detail: "ONNX + CoreML GPU", group: "reference", color: "#7A4FB3", match: /coreml-gpu/, leaderboard: false },
|
| 649 |
+
{ key: "m2max-cpu", label: "Apple M2 Max", detail: "ONNX + CoreML CPU", group: "reference", color: "#A98FD0", match: /coreml-cpu|macos|coreml/, leaderboard: false },
|
| 650 |
{ key: "imx8mp", label: "NXP i.MX 8M Plus", detail: "VSI NPU · TFLite INT8", group: "embedded", color: "#E8B820", match: /imx8mp/ },
|
| 651 |
{ key: "imx93", label: "NXP i.MX 93", detail: "Ethos-U65 · VELA TFLite", group: "embedded", color: "#8B7DC4", match: /imx93/ },
|
| 652 |
{ key: "imx95", label: "NXP i.MX 95", detail: "eIQ Neutron · TFLite INT8", group: "embedded", color: "#1FA0A8", match: /imx95/ },
|
|
|
|
| 832 |
const SIZE_NAMES = { n: "Nano", s: "Small", m: "Medium" };
|
| 833 |
|
| 834 |
// Build a lookup of validated (task, version, size, platform) cells from the
|
| 835 |
+
// embedded Studio sessions. Each cell keeps the best proving session (smart
|
| 836 |
+
// decoder preferred, then highest mAP) so the ✓ can link to it.
|
| 837 |
function coverageLookup() {
|
| 838 |
const seen = {};
|
| 839 |
for (const s of (STUDIO?.sessions ?? [])) {
|
| 840 |
const p = platformRowForSession(s);
|
| 841 |
if (!p || !s.has_metrics) continue;
|
| 842 |
+
const key = `${s.task_key}|${s.version_key}|${s.size}|${p.key}`;
|
| 843 |
+
const metric = s.det_map_50_95 ?? s.mask_map_50_95 ?? 0;
|
| 844 |
+
const isSmart = isSmartSession(s);
|
| 845 |
+
const cur = seen[key];
|
| 846 |
+
if (!cur || (isSmart && !cur.isSmart) || (isSmart === cur.isSmart && metric > cur.metric)) {
|
| 847 |
+
seen[key] = { s, metric, isSmart };
|
| 848 |
+
}
|
| 849 |
}
|
| 850 |
return seen;
|
| 851 |
}
|
|
|
|
| 885 |
for (const v of versions) {
|
| 886 |
for (const sz of COVERAGE_SIZES) {
|
| 887 |
const td = el("td");
|
| 888 |
+
const hit = seen[`${taskKey}|${v}|${sz}|${p.key}`];
|
| 889 |
+
if (hit) {
|
| 890 |
+
td.innerHTML = `<a class="cell cell-val" href="${hit.s.url}" target="_blank" rel="noopener" title="Open validation session ${hit.s.session_id} on EdgeFirst Studio">✓</a>`;
|
| 891 |
} else {
|
| 892 |
td.innerHTML = '<span class="cell cell-none">—</span>';
|
| 893 |
}
|
|
|
|
| 989 |
}));
|
| 990 |
}
|
| 991 |
|
| 992 |
+
// Cross-platform throughput board: the top 20 fastest validated
|
| 993 |
+
// model × platform results by pipelined FPS (accuracy intentionally not
|
| 994 |
+
// ranked here; smart decoder preferred over logical duplicates).
|
| 995 |
function renderPlatformThroughput() {
|
| 996 |
const host = document.getElementById("platform-fps-body");
|
| 997 |
if (!host) return;
|
| 998 |
host.innerHTML = "";
|
| 999 |
+
const best = {};
|
| 1000 |
+
for (const s of (STUDIO?.sessions ?? [])) {
|
| 1001 |
+
const p = platformRowForSession(s);
|
| 1002 |
+
if (!p || p.leaderboard === false || s.fps_median == null) continue;
|
| 1003 |
+
const key = `${p.key}|${s.task_key}|${s.version_key}|${s.size}`;
|
| 1004 |
+
const isSmart = isSmartSession(s);
|
| 1005 |
+
const cur = best[key];
|
| 1006 |
+
if (!cur || (isSmart && !cur.isSmart) || (isSmart === cur.isSmart && s.fps_median > cur.s.fps_median)) {
|
| 1007 |
+
best[key] = { p, s, isSmart };
|
| 1008 |
}
|
|
|
|
| 1009 |
}
|
| 1010 |
+
const rows = Object.values(best)
|
| 1011 |
+
.sort((a, b) => b.s.fps_median - a.s.fps_median)
|
| 1012 |
+
.slice(0, 20);
|
| 1013 |
for (let i = 0; i < rows.length; i++) {
|
| 1014 |
const { p, s } = rows[i];
|
| 1015 |
const tr = el("tr");
|
|
|
|
| 1027 |
function renderLeaderboard() {
|
| 1028 |
const grid = document.getElementById("leaderboard-grid");
|
| 1029 |
grid.innerHTML = "";
|
| 1030 |
+
const platforms = PLATFORM_ROWS.filter(p =>
|
| 1031 |
+
p.leaderboard !== false && (lbGroup === "all" || p.group === lbGroup));
|
| 1032 |
const metricLabel = lbMetric === "fps"
|
| 1033 |
? "Pipelined throughput FPS (higher is better)"
|
| 1034 |
: "mAP@0.5-0.95 (higher is better)";
|
|
|
|
| 1143 |
const datasets = PLATFORM_ROWS.filter(p => byPlatform[p.key]).map(p => {
|
| 1144 |
const pts = byPlatform[p.key];
|
| 1145 |
return {
|
| 1146 |
+
label: `${p.label} ${p.detail.includes("CoreML") ? p.detail.replace("ONNX + ", "") : ""}`.trim(),
|
| 1147 |
data: pts.map(s => ({
|
| 1148 |
x: s.fps_median,
|
| 1149 |
y: s.det_map_50_95,
|
|
|
|
| 1332 |
return v > 0 ? v : null;
|
| 1333 |
}
|
| 1334 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1335 |
function renderStudio() {
|
| 1336 |
const table = document.getElementById("studio-table");
|
| 1337 |
const empty = document.getElementById("studio-empty");
|
|
|
|
| 1345 |
empty.style.display = "none";
|
| 1346 |
table.style.display = "";
|
| 1347 |
const okCount = STUDIO.counts?.sessions_ok ?? STUDIO.counts?.ok ?? STUDIO.sessions.length;
|
| 1348 |
+
source.innerHTML = `updated <code>${STUDIO.generated_at}</code> · ${okCount} public sessions · every row links to <a href="https://edgefirst.studio" target="_blank" rel="noopener" style="color:var(--teal-text)">EdgeFirst Studio</a> · click a column header to sort`;
|
| 1349 |
+
|
| 1350 |
+
// Attach sort handlers once
|
| 1351 |
+
table.querySelectorAll("th[data-sort]").forEach(th => {
|
| 1352 |
+
if (th.dataset.bound) return;
|
| 1353 |
+
th.dataset.bound = "1";
|
| 1354 |
+
th.addEventListener("click", () => {
|
| 1355 |
+
const key = th.dataset.sort;
|
| 1356 |
+
if (studioSortKey === key) {
|
| 1357 |
+
studioSortDir = -studioSortDir;
|
| 1358 |
+
} else {
|
| 1359 |
+
studioSortKey = key;
|
| 1360 |
+
// Metrics default to descending (best first), text to ascending.
|
| 1361 |
+
studioSortDir = ["session", "family", "target", "precision"].includes(key) ? 1 : -1;
|
| 1362 |
+
}
|
| 1363 |
+
renderStudioBody();
|
| 1364 |
+
});
|
| 1365 |
+
});
|
| 1366 |
|
| 1367 |
+
renderStudioBody();
|
| 1368 |
+
}
|
| 1369 |
+
|
| 1370 |
+
const SIZE_ORDER = ["n", "s", "m", "l", "x"];
|
| 1371 |
+
|
| 1372 |
+
const STUDIO_SORT_ACCESSORS = {
|
| 1373 |
+
session: s => s.session_name || s.session_id || "",
|
| 1374 |
+
family: s => `${String(VERSION_ORDER.indexOf(s.version_key)).padStart(2, "0")}|${s.task_key}|${SIZE_ORDER.indexOf(s.size)}`,
|
| 1375 |
+
target: s => s.target_label || s.target_raw || "",
|
| 1376 |
+
precision: s => s.precision || "",
|
| 1377 |
+
det50: s => s.det_map_50,
|
| 1378 |
+
det5095: s => s.det_map_50_95,
|
| 1379 |
+
mask: s => s.mask_map_50_95,
|
| 1380 |
+
inf: s => s.avg_inference_ms,
|
| 1381 |
+
e2e: s => totalMs(s),
|
| 1382 |
+
fps: s => s.fps_median,
|
| 1383 |
+
};
|
| 1384 |
|
| 1385 |
+
let studioSortKey = null;
|
| 1386 |
+
let studioSortDir = 1;
|
| 1387 |
+
|
| 1388 |
+
function sortedStudioSessions() {
|
| 1389 |
+
const sessions = STUDIO.sessions.slice();
|
| 1390 |
+
if (studioSortKey && STUDIO_SORT_ACCESSORS[studioSortKey]) {
|
| 1391 |
+
const acc = STUDIO_SORT_ACCESSORS[studioSortKey];
|
| 1392 |
+
sessions.sort((a, b) => {
|
| 1393 |
+
const va = acc(a), vb = acc(b);
|
| 1394 |
+
if (va == null && vb == null) return 0;
|
| 1395 |
+
if (va == null) return 1; // nulls always last
|
| 1396 |
+
if (vb == null) return -1;
|
| 1397 |
+
const c = (typeof va === "number" && typeof vb === "number")
|
| 1398 |
+
? va - vb
|
| 1399 |
+
: String(va).localeCompare(String(vb));
|
| 1400 |
+
return c * studioSortDir;
|
| 1401 |
+
});
|
| 1402 |
+
return sessions;
|
| 1403 |
+
}
|
| 1404 |
+
// Default: detection first, then by version, size, target, precision
|
| 1405 |
const targetOrder = ["onnx", "tflite", "imx93", "imx95", "imx8mp", "ara240", "hailo8l", "hailo8", "hailo10", "engine"];
|
| 1406 |
+
return sessions.sort((a, b) => {
|
| 1407 |
if (a.task_key !== b.task_key) return a.task_key.localeCompare(b.task_key);
|
| 1408 |
const ai = VERSION_ORDER.indexOf(a.version_key);
|
| 1409 |
const bi = VERSION_ORDER.indexOf(b.version_key);
|
| 1410 |
if (ai !== bi) return ai - bi;
|
| 1411 |
+
const si = SIZE_ORDER.indexOf(a.size), sj = SIZE_ORDER.indexOf(b.size);
|
| 1412 |
if (si !== sj) return si - sj;
|
| 1413 |
const ti = targetOrder.indexOf(a.target_key) === -1 ? 99 : targetOrder.indexOf(a.target_key);
|
| 1414 |
const tj = targetOrder.indexOf(b.target_key) === -1 ? 99 : targetOrder.indexOf(b.target_key);
|
| 1415 |
if (ti !== tj) return ti - tj;
|
| 1416 |
return (a.precision || "").localeCompare(b.precision || "");
|
| 1417 |
});
|
| 1418 |
+
}
|
| 1419 |
+
|
| 1420 |
+
function renderStudioBody() {
|
| 1421 |
+
const table = document.getElementById("studio-table");
|
| 1422 |
+
const body = document.getElementById("studio-body");
|
| 1423 |
+
body.innerHTML = "";
|
| 1424 |
+
|
| 1425 |
+
// Header sort indicators
|
| 1426 |
+
table.querySelectorAll("th[data-sort]").forEach(th => {
|
| 1427 |
+
th.querySelector(".sort-ind")?.remove();
|
| 1428 |
+
if (th.dataset.sort === studioSortKey) {
|
| 1429 |
+
th.insertAdjacentHTML("beforeend",
|
| 1430 |
+
`<span class="sort-ind">${studioSortDir === 1 ? "▲" : "▼"}</span>`);
|
| 1431 |
+
}
|
| 1432 |
+
});
|
| 1433 |
|
| 1434 |
+
const sessions = sortedStudioSessions();
|
| 1435 |
for (const s of sessions) {
|
| 1436 |
const total = totalMs(s);
|
| 1437 |
const tr = el("tr");
|
|
|
|
| 1459 |
}
|
| 1460 |
}
|
| 1461 |
|
| 1462 |
+
// Accuracy vs on-target latency — end-to-end per-image wall time, encoded
|
| 1463 |
+
// like the throughput chart: color = platform, shape = model family.
|
| 1464 |
function renderTiming() {
|
| 1465 |
const host = document.getElementById("timing-host");
|
| 1466 |
if (!host) return;
|
| 1467 |
const usable = (STUDIO?.sessions ?? []).filter(s =>
|
| 1468 |
+
s.task_key === "det" && totalMs(s) != null && typeof s.det_map_50_95 === "number"
|
|
|
|
| 1469 |
);
|
| 1470 |
if (usable.length === 0) {
|
| 1471 |
// leave the default placeholder copy
|
|
|
|
| 1473 |
}
|
| 1474 |
|
| 1475 |
host.innerHTML = `
|
| 1476 |
+
<div class="chart-host" style="height:420px"><canvas id="chart-timing"></canvas></div>
|
| 1477 |
<p style="font-family:var(--serif);color:var(--text-muted);font-size:0.82rem;margin-top:0.5rem">
|
| 1478 |
+
Each point is a public validation session: color = platform, shape = model family
|
| 1479 |
+
(● YOLOv5 · ■ YOLOv8 · ▲ YOLO11 · ◆ YOLO26). X axis is end-to-end per-image latency on a log
|
| 1480 |
+
scale — the sequential image load → decode → preprocess → inference → postprocess wall time, not
|
| 1481 |
+
bare inference. Throughput exceeds 1000 ÷ latency because stages pipeline across frames.
|
| 1482 |
</p>
|
| 1483 |
`;
|
| 1484 |
|
| 1485 |
+
const byPlatform = {};
|
| 1486 |
for (const s of usable) {
|
| 1487 |
+
const p = platformRowForSession(s);
|
| 1488 |
+
if (!p) continue;
|
| 1489 |
+
(byPlatform[p.key] ||= []).push(s);
|
|
|
|
|
|
|
| 1490 |
}
|
| 1491 |
+
|
| 1492 |
+
const datasets = PLATFORM_ROWS.filter(p => byPlatform[p.key]).map(p => {
|
| 1493 |
+
const pts = byPlatform[p.key];
|
| 1494 |
+
return {
|
| 1495 |
+
label: `${p.label} ${p.detail.includes("CoreML") ? p.detail.replace("ONNX + ", "") : ""}`.trim(),
|
| 1496 |
+
data: pts.map(s => ({
|
| 1497 |
+
x: totalMs(s),
|
| 1498 |
+
y: s.det_map_50_95,
|
| 1499 |
+
name: sessionModelName(s),
|
| 1500 |
+
flagged: isBelowExpectations(s),
|
| 1501 |
+
})),
|
| 1502 |
+
backgroundColor: p.color,
|
| 1503 |
+
borderColor: p.color,
|
| 1504 |
+
pointStyle: pts.map(s => FAMILY_SHAPES[s.version_key] ?? "circle"),
|
| 1505 |
+
pointRadius: 7, pointHoverRadius: 10,
|
| 1506 |
+
};
|
| 1507 |
+
});
|
| 1508 |
|
| 1509 |
destroyChart("timing");
|
| 1510 |
charts.timing = new Chart(document.getElementById("chart-timing"), {
|
|
|
|
| 1516 |
legend: { display: true, position: "bottom" },
|
| 1517 |
tooltip: {
|
| 1518 |
callbacks: {
|
| 1519 |
+
label: (ctx) => `${ctx.raw.name} on ${ctx.dataset.label}: ${ctx.parsed.y.toFixed(1)} mAP @ ${ctx.parsed.x.toFixed(1)} ms E2E${ctx.raw.flagged ? " ⚠" : ""}`,
|
| 1520 |
},
|
| 1521 |
},
|
| 1522 |
},
|
| 1523 |
scales: {
|
| 1524 |
+
x: { type: "logarithmic",
|
| 1525 |
+
title: { display: true, text: "End-to-end latency (ms, log scale — lower is better)" },
|
| 1526 |
+
ticks: { font: { family: "monospace", size: 10 },
|
| 1527 |
+
callback: (v) => ([1,2,5,10,20,50,100,200,500,1000,2000].includes(v) ? String(v) : null) } },
|
| 1528 |
y: { title: { display: true, text: "mAP@0.5-0.95 (%)" }, beginAtZero: false,
|
| 1529 |
ticks: { font: { family: "monospace", size: 10 } } },
|
| 1530 |
},
|