|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8" /> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
|
|
<title>CTM Training Dashboard</title> |
|
|
<style> |
|
|
:root { |
|
|
--bg-color: #f4f4f9; |
|
|
--card-bg: #ffffff; |
|
|
--text-color: #333; |
|
|
--accent-color: #4a90e2; |
|
|
--success-color: #2ecc71; |
|
|
--font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; |
|
|
} |
|
|
|
|
|
body { |
|
|
font-family: var(--font-family); |
|
|
background-color: var(--bg-color); |
|
|
color: var(--text-color); |
|
|
margin: 0; |
|
|
padding: 20px; |
|
|
line-height: 1.6; |
|
|
} |
|
|
|
|
|
.container { |
|
|
max-width: 1200px; |
|
|
margin: 0 auto; |
|
|
} |
|
|
|
|
|
header { |
|
|
text-align: center; |
|
|
margin-bottom: 40px; |
|
|
} |
|
|
|
|
|
h1 { |
|
|
color: var(--accent-color); |
|
|
margin-bottom: 10px; |
|
|
} |
|
|
|
|
|
.status-card { |
|
|
background: var(--card-bg); |
|
|
padding: 20px; |
|
|
border-radius: 8px; |
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|
|
margin-bottom: 30px; |
|
|
display: grid; |
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); |
|
|
gap: 20px; |
|
|
text-align: center; |
|
|
} |
|
|
|
|
|
.metric { |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
} |
|
|
|
|
|
.metric-label { |
|
|
font-size: 0.9em; |
|
|
color: #666; |
|
|
} |
|
|
|
|
|
.metric-value { |
|
|
font-size: 1.5em; |
|
|
font-weight: bold; |
|
|
color: var(--text-color); |
|
|
} |
|
|
|
|
|
.plots-grid { |
|
|
display: grid; |
|
|
grid-template-columns: repeat(auto-fit, minmax(500px, 1fr)); |
|
|
gap: 20px; |
|
|
margin-bottom: 30px; |
|
|
} |
|
|
|
|
|
.plot-card { |
|
|
background: var(--card-bg); |
|
|
padding: 15px; |
|
|
border-radius: 8px; |
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|
|
} |
|
|
|
|
|
.plot-card img { |
|
|
width: 100%; |
|
|
height: auto; |
|
|
border-radius: 4px; |
|
|
} |
|
|
|
|
|
.artifacts-section { |
|
|
background: var(--card-bg); |
|
|
padding: 20px; |
|
|
border-radius: 8px; |
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|
|
text-align: center; |
|
|
margin-bottom: 30px; |
|
|
} |
|
|
|
|
|
.btn { |
|
|
display: inline-block; |
|
|
padding: 10px 20px; |
|
|
background-color: var(--accent-color); |
|
|
color: white; |
|
|
text-decoration: none; |
|
|
border-radius: 5px; |
|
|
margin: 0 10px; |
|
|
transition: background-color 0.3s; |
|
|
} |
|
|
|
|
|
.btn:hover { |
|
|
background-color: #357abd; |
|
|
} |
|
|
|
|
|
.gallery { |
|
|
display: grid; |
|
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); |
|
|
gap: 15px; |
|
|
margin-top: 20px; |
|
|
} |
|
|
|
|
|
.gallery img { |
|
|
width: 100%; |
|
|
border-radius: 4px; |
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); |
|
|
} |
|
|
|
|
|
footer { |
|
|
text-align: center; |
|
|
margin-top: 50px; |
|
|
color: #888; |
|
|
font-size: 0.9em; |
|
|
} |
|
|
|
|
|
#last-updated { |
|
|
font-size: 0.8em; |
|
|
color: #999; |
|
|
margin-top: 5px; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
<div class="container"> |
|
|
<header> |
|
|
<h1>CTM Training Dashboard</h1> |
|
|
<p>Real-time monitoring of Energy-Based Halting Experiment</p> |
|
|
<div id="last-updated">Waiting for data...</div> |
|
|
</header> |
|
|
|
|
|
<div class="status-card" id="metrics-container"> |
|
|
<div class="metric"> |
|
|
<span class="metric-label">Iteration</span> |
|
|
<span class="metric-value" id="iter">--</span> |
|
|
</div> |
|
|
<div class="metric"> |
|
|
<span class="metric-label">Epoch</span> |
|
|
<span class="metric-value" id="epoch">--</span> |
|
|
</div> |
|
|
<div class="metric"> |
|
|
<span class="metric-label">Train Loss</span> |
|
|
<span class="metric-value" id="train-loss">--</span> |
|
|
</div> |
|
|
<div class="metric"> |
|
|
<span class="metric-label">Test Loss</span> |
|
|
<span class="metric-value" id="test-loss">--</span> |
|
|
</div> |
|
|
<div class="metric"> |
|
|
<span class="metric-label">Train Acc</span> |
|
|
<span class="metric-value" id="train-acc">--</span> |
|
|
</div> |
|
|
<div class="metric"> |
|
|
<span class="metric-label">Test Acc</span> |
|
|
<span class="metric-value" id="test-acc">--</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="plots-grid"> |
|
|
<div class="plot-card"> |
|
|
<h3>Loss History</h3> |
|
|
<img |
|
|
id="loss-plot" |
|
|
src="logs/scratch/losses.png" |
|
|
alt="Loss Plot" |
|
|
onerror="this.src='https://via.placeholder.com/600x400?text=Waiting+for+Plots'" |
|
|
/> |
|
|
</div> |
|
|
<div class="plot-card"> |
|
|
<h3>Accuracy History</h3> |
|
|
<img |
|
|
id="acc-plot" |
|
|
src="logs/scratch/accuracies.png" |
|
|
alt="Accuracy Plot" |
|
|
onerror="this.src='https://via.placeholder.com/600x400?text=Waiting+for+Plots'" |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="artifacts-section"> |
|
|
<h2>Artifacts & Downloads</h2> |
|
|
<p>Download the latest model checkpoints and full logs.</p> |
|
|
<a href="logs/scratch/artifacts.zip" class="btn" |
|
|
>Download All Artifacts (.zip)</a |
|
|
> |
|
|
<a href="logs/scratch/checkpoint.pt" class="btn" |
|
|
>Download Checkpoint (.pt)</a |
|
|
> |
|
|
</div> |
|
|
|
|
|
<div class="artifacts-section"> |
|
|
<h2>Attention Visualization</h2> |
|
|
<p>Latest generated attention maps from the model.</p> |
|
|
<div class="gallery" id="gif-gallery"> |
|
|
|
|
|
<img |
|
|
src="logs/scratch/0_attention.gif" |
|
|
onerror="this.style.display='none'" |
|
|
alt="Attention Map" |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<footer> |
|
|
<p>Continuous Thought Machine Experiment</p> |
|
|
</footer> |
|
|
|
|
|
<script> |
|
|
const LOG_DIR = "logs/scratch"; |
|
|
|
|
|
async function updateDashboard() { |
|
|
try { |
|
|
|
|
|
const response = await fetch( |
|
|
`${LOG_DIR}/status.json?t=${new Date().getTime()}` |
|
|
); |
|
|
if (!response.ok) throw new Error("Status file not found"); |
|
|
|
|
|
const data = await response.json(); |
|
|
|
|
|
|
|
|
document.getElementById( |
|
|
"iter" |
|
|
).textContent = `${data.iteration} / ${data.total_iterations}`; |
|
|
document.getElementById("epoch").textContent = data.epoch; |
|
|
document.getElementById("train-loss").textContent = parseFloat( |
|
|
data.train_loss |
|
|
).toFixed(4); |
|
|
document.getElementById("test-loss").textContent = parseFloat( |
|
|
data.test_loss |
|
|
).toFixed(4); |
|
|
|
|
|
|
|
|
const formatAcc = (acc) => { |
|
|
if (Array.isArray(acc)) { |
|
|
return (acc[acc.length - 1] * 100).toFixed(2) + "%"; |
|
|
} |
|
|
return (acc * 100).toFixed(2) + "%"; |
|
|
}; |
|
|
|
|
|
document.getElementById("train-acc").textContent = formatAcc( |
|
|
data.train_accuracy |
|
|
); |
|
|
document.getElementById("test-acc").textContent = formatAcc( |
|
|
data.test_accuracy |
|
|
); |
|
|
|
|
|
|
|
|
document.getElementById( |
|
|
"last-updated" |
|
|
).textContent = `Last updated: ${new Date().toLocaleTimeString()}`; |
|
|
|
|
|
|
|
|
const timestamp = new Date().getTime(); |
|
|
document.getElementById( |
|
|
"loss-plot" |
|
|
).src = `${LOG_DIR}/losses.png?t=${timestamp}`; |
|
|
document.getElementById( |
|
|
"acc-plot" |
|
|
).src = `${LOG_DIR}/accuracies.png?t=${timestamp}`; |
|
|
|
|
|
|
|
|
const gallery = document.getElementById("gif-gallery"); |
|
|
gallery.innerHTML = `<img src="${LOG_DIR}/0_attention.gif?t=${timestamp}" onerror="this.style.display='none'" alt="Attention Map">`; |
|
|
} catch (error) { |
|
|
console.log("Waiting for training to start...", error); |
|
|
document.getElementById("last-updated").textContent = |
|
|
"Waiting for training to start..."; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
setInterval(updateDashboard, 30000); |
|
|
|
|
|
|
|
|
updateDashboard(); |
|
|
</script> |
|
|
</body> |
|
|
</html> |
|
|
|