document.addEventListener('DOMContentLoaded', () => { if (typeof Chart === 'undefined') { console.error('Chart.js is not loaded.'); return; } const colorPrimary = '#1e3a8a'; const colorSuccess = '#10b981'; const colorWarning = '#f59e0b'; const colorDanger = '#ef4444'; const colorBorder = '#e5e7eb'; const colorPrimaryLight = '#3b82f6'; const fontFamily = "'Inter', sans-serif"; if (Chart.defaults && Chart.defaults.font) { Chart.defaults.font.family = fontFamily; } if (Chart.defaults) { Chart.defaults.color = '#6b7280'; } // ================================================================= // CHART 1: Training Loss per Step (data RIIL dari notebook) // 2523 steps, 3 epoch, sampled every 50 steps for readability // ================================================================= const canvasLoss = document.getElementById('lossChart'); if (canvasLoss) { // Data riil dari log training notebook (diambil setiap 50 steps) const realSteps = [10,50,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,841, 900,950,1000,1050,1100,1150,1200,1250,1300,1350,1400,1450,1500,1550,1600,1650,1682, 1750,1800,1850,1900,1950,2000,2050,2100,2150,2200,2250,2300,2350,2400,2450,2500,2523]; const realLoss = [4.8127,2.8853,2.3493,1.6928,0.9643,0.9488,0.8374,0.7111,0.4475,0.4417,0.4857,0.3596,0.3565,0.3267,0.3244,0.3280,0.2946,0.2821, 0.2810,0.3034,0.2860,0.2676,0.2576,0.2720,0.2680,0.2777,0.2646,0.2511,0.2587,0.2467,0.2462,0.2448,0.2456,0.2375,0.2404, 0.2416,0.2385,0.2265,0.2259,0.2335,0.2343,0.2313,0.2248,0.2353,0.2177,0.2229,0.2238,0.2254,0.2303,0.2259,0.2199,0.2226]; // Epoch boundary markers (steps 841 = epoch 1 end, 1682 = epoch 2 end, 2523 = epoch 3 end) new Chart(canvasLoss.getContext('2d'), { type: 'line', data: { labels: realSteps, datasets: [ { label: 'Training Loss (per step)', data: realLoss, borderColor: colorWarning, backgroundColor: 'rgba(245, 158, 11, 0.1)', borderWidth: 2, tension: 0.4, fill: true, pointRadius: 0, pointHoverRadius: 5 } ] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top' }, tooltip: { callbacks: { label: ctx => ` Loss: ${ctx.parsed.y.toFixed(4)}` } }, annotation: {} }, scales: { y: { beginAtZero: true, grid: { color: colorBorder }, title: { display: true, text: 'Training Loss' } }, x: { grid: { display: false }, title: { display: true, text: 'Step' }, ticks: { maxTicksLimit: 10, callback: function(val, idx) { const step = this.getLabelForValue(val); // Mark epoch boundaries if (step == 841) return 'Ep.1 End'; if (step == 1682) return 'Ep.2 End'; if (step == 2523) return 'Ep.3 End'; return step; } } } } } }); } // ================================================================= // CHART 2: Training Loss per Epoch (rata-rata) // Epoch 1 avg: ~1.86, Epoch 2 avg: ~0.27, Epoch 3 avg: ~0.23 // ================================================================= const canvasScore = document.getElementById('scoreChart'); if (canvasScore) { new Chart(canvasScore.getContext('2d'), { type: 'bar', data: { labels: ['Epoch 1', 'Epoch 2', 'Epoch 3'], datasets: [ { label: 'Rata-rata Training Loss per Epoch', data: [1.86, 0.27, 0.23], backgroundColor: [ 'rgba(239, 68, 68, 0.7)', 'rgba(245, 158, 11, 0.7)', 'rgba(16, 185, 129, 0.7)' ], borderColor: [colorDanger, colorWarning, colorSuccess], borderWidth: 2, borderRadius: 8 } ] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top' }, tooltip: { callbacks: { label: ctx => ` Avg Loss: ${ctx.parsed.y.toFixed(4)}` } } }, scales: { y: { beginAtZero: true, grid: { color: colorBorder }, title: { display: true, text: 'Training Loss' } }, x: { grid: { display: false } } } } }); } });