ProCreations commited on
Commit
a2893e5
·
verified ·
1 Parent(s): e5ff8db

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +889 -37
index.html CHANGED
@@ -630,30 +630,31 @@
630
  left: 0;
631
  width: 100%;
632
  height: 100%;
633
- background: rgba(0, 0, 0, 0.8);
634
  z-index: 9999;
635
  display: none;
636
- backdrop-filter: blur(4px);
637
  }
638
 
639
  .walkthrough-highlight {
640
  position: absolute;
641
- border: 3px solid #10b981;
642
  border-radius: 0.5rem;
643
- box-shadow: 0 0 0 4px rgba(16, 185, 129, 0.2), 0 0 30px rgba(16, 185, 129, 0.4);
644
  pointer-events: none;
645
  animation: pulse 2s infinite;
646
  z-index: 10000;
 
647
  }
648
 
649
  .walkthrough-popup {
650
  position: absolute;
651
  background: #1f2937;
652
- border: 2px solid #10b981;
653
  border-radius: 1rem;
654
  padding: 1.5rem;
655
- max-width: 350px;
656
- box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
657
  z-index: 10001;
658
  color: white;
659
  }
@@ -773,7 +774,7 @@
773
  }
774
 
775
  .walkthrough-task-menu {
776
- display: none;
777
  padding: 2rem;
778
  max-width: 800px;
779
  margin: 0 auto;
@@ -821,6 +822,119 @@
821
  display: none;
822
  }
823
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
824
  /* Mobile-friendly adjustments */
825
  @media (max-width: 640px) {
826
  .walkthrough-popup {
@@ -846,6 +960,15 @@
846
  font-size: 0.8125rem;
847
  padding: 0.4rem 0.8rem;
848
  }
 
 
 
 
 
 
 
 
 
849
  }
850
  </style>
851
  </head>
@@ -956,25 +1079,48 @@
956
  <p class="task-subtitle">Learn step-by-step how neural networks work</p>
957
  </div>
958
 
 
 
 
 
 
 
 
959
  <div class="walkthrough-task-menu">
960
  <div class="walkthrough-task-card" onclick="startWalkthrough('basics')">
961
  <h3 class="walkthrough-task-title">🧠 Neural Network Basics</h3>
962
  <p class="walkthrough-task-description">Learn what neurons, layers, and connections are. Understand how information flows through the network.</p>
 
963
  </div>
964
 
965
  <div class="walkthrough-task-card" onclick="startWalkthrough('training')">
966
  <h3 class="walkthrough-task-title">🎯 How Training Works</h3>
967
  <p class="walkthrough-task-description">Discover how neural networks learn from data through forward propagation, loss calculation, and backpropagation.</p>
 
968
  </div>
969
 
970
  <div class="walkthrough-task-card" onclick="startWalkthrough('visualization')">
971
  <h3 class="walkthrough-task-title">📊 Understanding the Visualizations</h3>
972
  <p class="walkthrough-task-description">Learn to read the network diagram, loss chart, and output predictions to understand what's happening.</p>
 
973
  </div>
974
 
975
  <div class="walkthrough-task-card" onclick="startWalkthrough('logic')">
976
  <h3 class="walkthrough-task-title">🔗 Logic Gates Tutorial</h3>
977
  <p class="walkthrough-task-description">See how neural networks can learn simple AND, OR, and complex XOR logic gates step by step.</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
978
  </div>
979
  </div>
980
  </div>
@@ -1097,6 +1243,48 @@
1097
  </div>
1098
  </div>
1099
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1100
  <div class="card">
1101
  <h3 class="card-title">
1102
  <svg class="icon" fill="currentColor" viewBox="0 0 24 24">
@@ -1694,6 +1882,21 @@
1694
  let trainInterval = null;
1695
  let animationId = null;
1696
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1697
  // DOM elements
1698
  const mainMenu = document.getElementById('mainMenu');
1699
  const taskSelection = document.getElementById('taskSelection');
@@ -1725,6 +1928,15 @@
1725
  const vizTitle = document.getElementById('vizTitle');
1726
  const babyViz = document.getElementById('babyViz');
1727
 
 
 
 
 
 
 
 
 
 
1728
  // Developer mode elements
1729
  const devTaskName = document.getElementById('devTaskName');
1730
  const devArchitecture = document.getElementById('devArchitecture');
@@ -2067,19 +2279,63 @@
2067
  ctx.lineTo(x2, y2);
2068
  ctx.stroke();
2069
 
2070
- // Subtle gradient flow
2071
- if (isTraining && Math.abs(weight) > 0.3) {
2072
- const flowProgress = ((animationTime * 0.5) % 120) / 120;
2073
- const flowX = x1 + (x2 - x1) * flowProgress;
2074
- const flowY = y1 + (y2 - y1) * flowProgress;
2075
 
2076
- const flowIntensity = intensity * 0.3;
2077
- ctx.fillStyle = weight > 0 ?
2078
- `rgba(34, 197, 94, ${flowIntensity})` :
2079
- `rgba(239, 68, 68, ${flowIntensity})`;
2080
- ctx.beginPath();
2081
- ctx.arc(flowX, flowY, 2, 0, 2 * Math.PI);
2082
- ctx.fill();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2083
  }
2084
  }
2085
  }
@@ -2097,9 +2353,47 @@
2097
  const saturation = 50;
2098
  let lightness = 35 + activation * 25;
2099
 
2100
- if (isTraining && activation > 0.8) {
2101
- const pulse = Math.sin(animationTime * 0.05) * 0.1;
2102
- lightness += pulse * 10;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2103
  }
2104
 
2105
  ctx.fillStyle = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
@@ -2111,13 +2405,36 @@
2111
  ctx.lineWidth = 1.5;
2112
  ctx.stroke();
2113
 
 
2114
  ctx.fillStyle = '#ffffff';
2115
- ctx.font = `${Math.max(10, nodeRadius / 1.6)}px monospace`;
2116
  ctx.textAlign = 'center';
2117
  ctx.textBaseline = 'middle';
2118
  ctx.shadowColor = 'rgba(0, 0, 0, 0.9)';
2119
  ctx.shadowBlur = 2;
2120
- ctx.fillText(activation.toFixed(2), x, y);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2121
  ctx.shadowBlur = 0;
2122
  }
2123
  });
@@ -2202,6 +2519,310 @@
2202
  lossArea.setAttribute('points', points + ' 100,100 0,100');
2203
  }
2204
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2205
  // Training step
2206
  function trainStep() {
2207
  const result = network.trainBatch(currentTask.data);
@@ -2216,6 +2837,21 @@
2216
  lossHistory.push(result.loss);
2217
  if (lossHistory.length > 100) lossHistory.shift();
2218
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2219
  const newPredictions = currentTask.data.map(data => {
2220
  const output = network.forward(data.input);
2221
  const rawOutput = output[0];
@@ -2279,6 +2915,7 @@
2279
 
2280
  updateLossChart();
2281
  drawNetwork();
 
2282
  if (currentTask.hasVisualization) {
2283
  drawDataVisualization();
2284
  }
@@ -2315,6 +2952,7 @@
2315
  if (currentTask.isBabyMode) {
2316
  updateBabyVisualization();
2317
  }
 
2318
  }
2319
  animationId = requestAnimationFrame(animate);
2320
  }
@@ -2344,6 +2982,12 @@
2344
  accuracy = 0;
2345
  animationTime = 0;
2346
 
 
 
 
 
 
 
2347
  trainBtn.innerHTML = `
2348
  <svg class="icon" fill="currentColor" viewBox="0 0 24 24">
2349
  <path d="M8 5v14l11-7z"/>
@@ -2368,8 +3012,7 @@
2368
  `;
2369
  trainBtn.className = 'btn btn-pause';
2370
 
2371
- // Use slower speed in walkthrough mode
2372
- const trainingSpeed = walkthroughActive ? walkthroughTrainingSpeed : 100;
2373
  trainInterval = setInterval(trainStep, trainingSpeed);
2374
  } else {
2375
  trainBtn.innerHTML = `
@@ -2390,6 +3033,79 @@
2390
  // Developer mode event listeners
2391
  devArchitecture.addEventListener('input', updateParameterCount);
2392
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2393
  // Walkthrough Mode functionality
2394
  let walkthroughActive = false;
2395
  let walkthroughStep = 0;
@@ -2411,21 +3127,21 @@
2411
  content: 'This is the input layer (left side). It receives the raw data - like numbers, images, or text. Each circle represents one input neuron that holds a piece of information.',
2412
  element: '#networkCanvas',
2413
  position: 'right',
2414
- highlight: {x: 0, y: 0, width: 150, height: 300}
2415
  },
2416
  {
2417
  title: 'Hidden Layers',
2418
  content: 'These middle layers are where the "magic" happens! They transform the input data through mathematical operations, finding patterns and relationships.',
2419
  element: '#networkCanvas',
2420
  position: 'top',
2421
- highlight: {x: 150, y: 0, width: 100, height: 300}
2422
  },
2423
  {
2424
  title: 'Output Layer',
2425
  content: 'The final layer gives us the result - a prediction, classification, or decision based on what the network learned from the input.',
2426
  element: '#networkCanvas',
2427
  position: 'left',
2428
- highlight: {x: 250, y: 0, width: 150, height: 300}
2429
  },
2430
  {
2431
  title: 'Connections (Weights)',
@@ -2546,6 +3262,94 @@
2546
  position: 'right'
2547
  }
2548
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2549
  }
2550
  };
2551
 
@@ -2563,6 +3367,20 @@
2563
  taskSelection.style.display = 'block';
2564
  currentCategory = 'fundamentals';
2565
  showCategory('fundamentals');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2566
  }
2567
 
2568
  showWalkthroughStep();
@@ -2579,9 +3397,13 @@
2579
  document.getElementById('walkthroughStep').textContent = walkthroughStep + 1;
2580
  document.getElementById('walkthroughTotal').textContent = walkthroughTutorial.steps.length;
2581
 
2582
- // Show overlay
2583
  overlay.style.display = 'block';
2584
  progress.style.display = 'block';
 
 
 
 
2585
 
2586
  // Update popup content
2587
  document.getElementById('walkthroughTitle').textContent = step.title;
@@ -2593,7 +3415,7 @@
2593
  if (element) {
2594
  const rect = element.getBoundingClientRect();
2595
 
2596
- // Highlight element
2597
  if (step.highlight) {
2598
  const canvasRect = element.getBoundingClientRect();
2599
  highlight.style.left = (canvasRect.left + step.highlight.x) + 'px';
@@ -2601,12 +3423,18 @@
2601
  highlight.style.width = step.highlight.width + 'px';
2602
  highlight.style.height = step.highlight.height + 'px';
2603
  } else {
2604
- highlight.style.left = rect.left - 5 + 'px';
2605
- highlight.style.top = rect.top - 5 + 'px';
2606
- highlight.style.width = rect.width + 10 + 'px';
2607
- highlight.style.height = rect.height + 10 + 'px';
2608
  }
2609
  highlight.style.display = 'block';
 
 
 
 
 
 
2610
 
2611
  // Position popup
2612
  positionPopup(popup, rect, step.position);
@@ -2695,6 +3523,20 @@
2695
  document.getElementById('walkthroughPopup').style.display = 'none';
2696
  document.getElementById('walkthroughProgress').style.display = 'none';
2697
  document.getElementById('walkthroughIndicator').style.display = 'none';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2698
  }
2699
 
2700
  // Walkthrough event listeners
@@ -2704,7 +3546,17 @@
2704
 
2705
  // Initialize
2706
  startAnimation();
 
 
 
 
 
 
 
 
 
 
 
2707
  </script>
2708
- <script src="walkthrough-enhancement.js"></script>
2709
  </body>
2710
  </html>
 
630
  left: 0;
631
  width: 100%;
632
  height: 100%;
633
+ background: rgba(0, 0, 0, 0.3);
634
  z-index: 9999;
635
  display: none;
636
+ backdrop-filter: blur(2px);
637
  }
638
 
639
  .walkthrough-highlight {
640
  position: absolute;
641
+ border: 4px solid #10b981;
642
  border-radius: 0.5rem;
643
+ box-shadow: 0 0 0 8px rgba(16, 185, 129, 0.3), 0 0 40px rgba(16, 185, 129, 0.6);
644
  pointer-events: none;
645
  animation: pulse 2s infinite;
646
  z-index: 10000;
647
+ background: rgba(16, 185, 129, 0.1);
648
  }
649
 
650
  .walkthrough-popup {
651
  position: absolute;
652
  background: #1f2937;
653
+ border: 3px solid #10b981;
654
  border-radius: 1rem;
655
  padding: 1.5rem;
656
+ max-width: 400px;
657
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.8), 0 0 0 2px rgba(16, 185, 129, 0.2);
658
  z-index: 10001;
659
  color: white;
660
  }
 
774
  }
775
 
776
  .walkthrough-task-menu {
777
+ display: block;
778
  padding: 2rem;
779
  max-width: 800px;
780
  margin: 0 auto;
 
822
  display: none;
823
  }
824
 
825
+ /* Loss Landscape Visualization Styles */
826
+ .loss-landscape-container {
827
+ background: #1f2937;
828
+ border: 1px solid #374151;
829
+ border-radius: 0.5rem;
830
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
831
+ padding: 1.5rem;
832
+ margin-bottom: 1.5rem;
833
+ }
834
+
835
+ .loss-landscape-title {
836
+ font-size: 1.125rem;
837
+ font-weight: 600;
838
+ margin-bottom: 1rem;
839
+ color: white;
840
+ display: flex;
841
+ align-items: center;
842
+ gap: 0.5rem;
843
+ }
844
+
845
+ .loss-landscape-canvas {
846
+ width: 100%;
847
+ height: 400px;
848
+ border: 1px solid #4b5563;
849
+ border-radius: 0.5rem;
850
+ background: #111827;
851
+ cursor: grab;
852
+ }
853
+
854
+ .loss-landscape-canvas:active {
855
+ cursor: grabbing;
856
+ }
857
+
858
+ .landscape-controls {
859
+ display: flex;
860
+ flex-wrap: wrap;
861
+ gap: 1rem;
862
+ margin-top: 1rem;
863
+ align-items: center;
864
+ }
865
+
866
+ .landscape-control-group {
867
+ display: flex;
868
+ flex-direction: column;
869
+ gap: 0.25rem;
870
+ }
871
+
872
+ .landscape-control-label {
873
+ font-size: 0.875rem;
874
+ color: #9ca3af;
875
+ font-weight: 500;
876
+ }
877
+
878
+ .landscape-slider {
879
+ width: 100px;
880
+ height: 6px;
881
+ border-radius: 3px;
882
+ background: #4b5563;
883
+ outline: none;
884
+ cursor: pointer;
885
+ }
886
+
887
+ .landscape-toggle {
888
+ display: flex;
889
+ align-items: center;
890
+ gap: 0.5rem;
891
+ font-size: 0.875rem;
892
+ color: #d1d5db;
893
+ }
894
+
895
+ .landscape-checkbox {
896
+ width: 16px;
897
+ height: 16px;
898
+ border-radius: 3px;
899
+ border: 2px solid #4b5563;
900
+ background: #111827;
901
+ cursor: pointer;
902
+ }
903
+
904
+ .landscape-checkbox:checked {
905
+ background: #06b6d4;
906
+ border-color: #06b6d4;
907
+ }
908
+
909
+ .gradient-legend {
910
+ display: flex;
911
+ align-items: center;
912
+ gap: 1rem;
913
+ margin-top: 0.5rem;
914
+ font-size: 0.75rem;
915
+ color: #9ca3af;
916
+ }
917
+
918
+ .gradient-arrow {
919
+ display: inline-block;
920
+ width: 20px;
921
+ height: 3px;
922
+ background: linear-gradient(90deg, #ef4444, #f59e0b);
923
+ position: relative;
924
+ }
925
+
926
+ .gradient-arrow::after {
927
+ content: '';
928
+ position: absolute;
929
+ right: -3px;
930
+ top: -2px;
931
+ width: 0;
932
+ height: 0;
933
+ border-left: 5px solid #f59e0b;
934
+ border-top: 4px solid transparent;
935
+ border-bottom: 4px solid transparent;
936
+ }
937
+
938
  /* Mobile-friendly adjustments */
939
  @media (max-width: 640px) {
940
  .walkthrough-popup {
 
960
  font-size: 0.8125rem;
961
  padding: 0.4rem 0.8rem;
962
  }
963
+
964
+ .loss-landscape-canvas {
965
+ height: 300px;
966
+ }
967
+
968
+ .landscape-controls {
969
+ flex-direction: column;
970
+ align-items: flex-start;
971
+ }
972
  }
973
  </style>
974
  </head>
 
1079
  <p class="task-subtitle">Learn step-by-step how neural networks work</p>
1080
  </div>
1081
 
1082
+ <div class="walkthrough-intro">
1083
+ <div style="text-align: center; margin-bottom: 2rem; padding: 1.5rem; background: linear-gradient(135deg, #10b981, #059669); border-radius: 1rem; color: white;">
1084
+ <h3 style="margin: 0 0 0.5rem 0; font-size: 1.5rem;">🎓 Interactive AI Learning Journey</h3>
1085
+ <p style="margin: 0; opacity: 0.9;">Choose a tutorial below to start your guided exploration of neural networks. Each tutorial includes interactive demonstrations and step-by-step explanations.</p>
1086
+ </div>
1087
+ </div>
1088
+
1089
  <div class="walkthrough-task-menu">
1090
  <div class="walkthrough-task-card" onclick="startWalkthrough('basics')">
1091
  <h3 class="walkthrough-task-title">🧠 Neural Network Basics</h3>
1092
  <p class="walkthrough-task-description">Learn what neurons, layers, and connections are. Understand how information flows through the network.</p>
1093
+ <div style="font-size: 0.75rem; color: #9ca3af; margin-top: 0.5rem;">⏱️ 5 steps • 🎯 Beginner</div>
1094
  </div>
1095
 
1096
  <div class="walkthrough-task-card" onclick="startWalkthrough('training')">
1097
  <h3 class="walkthrough-task-title">🎯 How Training Works</h3>
1098
  <p class="walkthrough-task-description">Discover how neural networks learn from data through forward propagation, loss calculation, and backpropagation.</p>
1099
+ <div style="font-size: 0.75rem; color: #9ca3af; margin-top: 0.5rem;">⏱️ 5 steps • 🎯 Beginner</div>
1100
  </div>
1101
 
1102
  <div class="walkthrough-task-card" onclick="startWalkthrough('visualization')">
1103
  <h3 class="walkthrough-task-title">📊 Understanding the Visualizations</h3>
1104
  <p class="walkthrough-task-description">Learn to read the network diagram, loss chart, and output predictions to understand what's happening.</p>
1105
+ <div style="font-size: 0.75rem; color: #9ca3af; margin-top: 0.5rem;">⏱️ 4 steps • 🎯 Beginner</div>
1106
  </div>
1107
 
1108
  <div class="walkthrough-task-card" onclick="startWalkthrough('logic')">
1109
  <h3 class="walkthrough-task-title">🔗 Logic Gates Tutorial</h3>
1110
  <p class="walkthrough-task-description">See how neural networks can learn simple AND, OR, and complex XOR logic gates step by step.</p>
1111
+ <div style="font-size: 0.75rem; color: #9ca3af; margin-top: 0.5rem;">⏱️ 5 steps • 📈 Intermediate</div>
1112
+ </div>
1113
+
1114
+ <div class="walkthrough-task-card" onclick="startWalkthrough('landscape')">
1115
+ <h3 class="walkthrough-task-title">🗻 Loss Landscape & Gradients</h3>
1116
+ <p class="walkthrough-task-description">Explore the 3D loss landscape, understand gradients, and see how training navigates through parameter space.</p>
1117
+ <div style="font-size: 0.75rem; color: #9ca3af; margin-top: 0.5rem;">⏱️ 6 steps • 🔥 Advanced</div>
1118
+ </div>
1119
+
1120
+ <div class="walkthrough-task-card" onclick="startWalkthrough('advanced')">
1121
+ <h3 class="walkthrough-task-title">⚡ Advanced Visualizations</h3>
1122
+ <p class="walkthrough-task-description">Master gradient flows, weight changes, and understand what makes neural networks tick under the hood.</p>
1123
+ <div style="font-size: 0.75rem; color: #9ca3af; margin-top: 0.5rem;">⏱️ 7 steps • 🔥 Advanced</div>
1124
  </div>
1125
  </div>
1126
  </div>
 
1243
  </div>
1244
  </div>
1245
 
1246
+ <!-- Loss Landscape Visualization -->
1247
+ <div class="loss-landscape-container">
1248
+ <h3 class="loss-landscape-title">
1249
+ <svg class="icon icon-stroke" viewBox="0 0 24 24">
1250
+ <path d="M8 3l4 8 5-5 5 15H2L8 3z"/>
1251
+ </svg>
1252
+ Loss Landscape & Gradients
1253
+ </h3>
1254
+ <canvas id="lossLandscapeCanvas" class="loss-landscape-canvas" width="800" height="400"></canvas>
1255
+ <div class="landscape-controls">
1256
+ <div class="landscape-control-group">
1257
+ <label class="landscape-control-label">Rotation X</label>
1258
+ <input type="range" id="rotationX" class="landscape-slider" min="-90" max="90" value="-20">
1259
+ </div>
1260
+ <div class="landscape-control-group">
1261
+ <label class="landscape-control-label">Rotation Z</label>
1262
+ <input type="range" id="rotationZ" class="landscape-slider" min="0" max="360" value="45">
1263
+ </div>
1264
+ <div class="landscape-control-group">
1265
+ <label class="landscape-control-label">Zoom</label>
1266
+ <input type="range" id="zoomLevel" class="landscape-slider" min="0.5" max="3" step="0.1" value="1">
1267
+ </div>
1268
+ <div class="landscape-toggle">
1269
+ <input type="checkbox" id="showGradients" class="landscape-checkbox" checked>
1270
+ <label for="showGradients">Show Gradients</label>
1271
+ </div>
1272
+ <div class="landscape-toggle">
1273
+ <input type="checkbox" id="showContours" class="landscape-checkbox" checked>
1274
+ <label for="showContours">Show Contours</label>
1275
+ </div>
1276
+ <div class="landscape-toggle">
1277
+ <input type="checkbox" id="showPath" class="landscape-checkbox" checked>
1278
+ <label for="showPath">Show Training Path</label>
1279
+ </div>
1280
+ </div>
1281
+ <div class="gradient-legend">
1282
+ <span>Gradient Direction:</span>
1283
+ <span class="gradient-arrow"></span>
1284
+ <span>High → Low Loss</span>
1285
+ </div>
1286
+ </div>
1287
+
1288
  <div class="card">
1289
  <h3 class="card-title">
1290
  <svg class="icon" fill="currentColor" viewBox="0 0 24 24">
 
1882
  let trainInterval = null;
1883
  let animationId = null;
1884
 
1885
+ // Loss landscape variables
1886
+ let lossLandscape = [];
1887
+ let gradientField = [];
1888
+ let trainingPath = [];
1889
+ let landscapeResolution = 30;
1890
+ let rotationX = -20;
1891
+ let rotationZ = 45;
1892
+ let zoomLevel = 1;
1893
+ let showGradients = true;
1894
+ let showContours = true;
1895
+ let showPath = true;
1896
+ let mouseDown = false;
1897
+ let lastMouseX = 0;
1898
+ let lastMouseY = 0;
1899
+
1900
  // DOM elements
1901
  const mainMenu = document.getElementById('mainMenu');
1902
  const taskSelection = document.getElementById('taskSelection');
 
1928
  const vizTitle = document.getElementById('vizTitle');
1929
  const babyViz = document.getElementById('babyViz');
1930
 
1931
+ // Loss landscape elements
1932
+ const lossLandscapeCanvas = document.getElementById('lossLandscapeCanvas');
1933
+ const rotationXSlider = document.getElementById('rotationX');
1934
+ const rotationZSlider = document.getElementById('rotationZ');
1935
+ const zoomSlider = document.getElementById('zoomLevel');
1936
+ const gradientsCheckbox = document.getElementById('showGradients');
1937
+ const contoursCheckbox = document.getElementById('showContours');
1938
+ const pathCheckbox = document.getElementById('showPath');
1939
+
1940
  // Developer mode elements
1941
  const devTaskName = document.getElementById('devTaskName');
1942
  const devArchitecture = document.getElementById('devArchitecture');
 
2279
  ctx.lineTo(x2, y2);
2280
  ctx.stroke();
2281
 
2282
+ // Enhanced gradient flow visualization
2283
+ if (isTraining && Math.abs(weight) > 0.1) {
2284
+ // Multiple flowing particles for stronger gradients
2285
+ const numParticles = Math.min(3, Math.floor(Math.abs(weight) * 4));
 
2286
 
2287
+ for (let p = 0; p < numParticles; p++) {
2288
+ const offset = (p / numParticles) * 120;
2289
+ const flowProgress = ((animationTime * 0.8 + offset) % 120) / 120;
2290
+ const flowX = x1 + (x2 - x1) * flowProgress;
2291
+ const flowY = y1 + (y2 - y1) * flowProgress;
2292
+
2293
+ const particleSize = 2 + Math.abs(weight) * 2;
2294
+ const flowIntensity = intensity * 0.4;
2295
+
2296
+ // Gradient direction indicator
2297
+ const gradientStrength = weightChanges && weightChanges[i] && weightChanges[i][k] && weightChanges[i][k][j]
2298
+ ? Math.min(weightChanges[i][k][j] * 5, 1) : 0;
2299
+
2300
+ ctx.fillStyle = weight > 0 ?
2301
+ `rgba(34, 197, 94, ${flowIntensity + gradientStrength * 0.3})` :
2302
+ `rgba(239, 68, 68, ${flowIntensity + gradientStrength * 0.3})`;
2303
+
2304
+ ctx.beginPath();
2305
+ ctx.arc(flowX, flowY, particleSize, 0, 2 * Math.PI);
2306
+ ctx.fill();
2307
+
2308
+ // Add gradient direction arrow for strong changes
2309
+ if (gradientStrength > 0.5) {
2310
+ const arrowLength = 8;
2311
+ const angle = Math.atan2(y2 - y1, x2 - x1);
2312
+
2313
+ ctx.strokeStyle = weight > 0 ?
2314
+ `rgba(34, 197, 94, ${gradientStrength})` :
2315
+ `rgba(239, 68, 68, ${gradientStrength})`;
2316
+ ctx.lineWidth = 2;
2317
+
2318
+ ctx.beginPath();
2319
+ ctx.moveTo(flowX - arrowLength * Math.cos(angle),
2320
+ flowY - arrowLength * Math.sin(angle));
2321
+ ctx.lineTo(flowX + arrowLength * Math.cos(angle),
2322
+ flowY + arrowLength * Math.sin(angle));
2323
+ ctx.stroke();
2324
+
2325
+ // Arrow head
2326
+ const headSize = 3;
2327
+ ctx.beginPath();
2328
+ ctx.moveTo(flowX + arrowLength * Math.cos(angle),
2329
+ flowY + arrowLength * Math.sin(angle));
2330
+ ctx.lineTo(flowX + (arrowLength - headSize) * Math.cos(angle - 0.3),
2331
+ flowY + (arrowLength - headSize) * Math.sin(angle - 0.3));
2332
+ ctx.moveTo(flowX + arrowLength * Math.cos(angle),
2333
+ flowY + arrowLength * Math.sin(angle));
2334
+ ctx.lineTo(flowX + (arrowLength - headSize) * Math.cos(angle + 0.3),
2335
+ flowY + (arrowLength - headSize) * Math.sin(angle + 0.3));
2336
+ ctx.stroke();
2337
+ }
2338
+ }
2339
  }
2340
  }
2341
  }
 
2353
  const saturation = 50;
2354
  let lightness = 35 + activation * 25;
2355
 
2356
+ // Enhanced neuron visualization with gradient information
2357
+ if (isTraining) {
2358
+ if (activation > 0.8) {
2359
+ const pulse = Math.sin(animationTime * 0.05) * 0.1;
2360
+ lightness += pulse * 10;
2361
+ }
2362
+
2363
+ // Show gradient magnitude on neurons
2364
+ if (weightChanges && weightChanges.length > 0) {
2365
+ let neuronGradient = 0;
2366
+
2367
+ // Calculate average gradient affecting this neuron
2368
+ if (layerIndex < network.layers.length - 1 && weightChanges[layerIndex]) {
2369
+ for (let outIdx = 0; outIdx < weightChanges[layerIndex].length; outIdx++) {
2370
+ if (weightChanges[layerIndex][outIdx] && weightChanges[layerIndex][outIdx][nodeIndex]) {
2371
+ neuronGradient += Math.abs(weightChanges[layerIndex][outIdx][nodeIndex]);
2372
+ }
2373
+ }
2374
+ neuronGradient /= weightChanges[layerIndex].length || 1;
2375
+ }
2376
+
2377
+ // Add gradient ring around active neurons
2378
+ if (neuronGradient > 0.1) {
2379
+ const ringIntensity = Math.min(neuronGradient * 3, 1);
2380
+ ctx.strokeStyle = `rgba(255, 255, 0, ${ringIntensity * 0.7})`;
2381
+ ctx.lineWidth = 3;
2382
+ ctx.beginPath();
2383
+ ctx.arc(x, y, nodeRadius + 2, 0, 2 * Math.PI);
2384
+ ctx.stroke();
2385
+
2386
+ // Pulsing effect for high gradients
2387
+ if (neuronGradient > 0.5) {
2388
+ const gradientPulse = Math.sin(animationTime * 0.1) * 0.2 + 0.8;
2389
+ ctx.strokeStyle = `rgba(255, 255, 0, ${ringIntensity * gradientPulse * 0.3})`;
2390
+ ctx.lineWidth = 5;
2391
+ ctx.beginPath();
2392
+ ctx.arc(x, y, nodeRadius + 4, 0, 2 * Math.PI);
2393
+ ctx.stroke();
2394
+ }
2395
+ }
2396
+ }
2397
  }
2398
 
2399
  ctx.fillStyle = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
 
2405
  ctx.lineWidth = 1.5;
2406
  ctx.stroke();
2407
 
2408
+ // Enhanced text with gradient information
2409
  ctx.fillStyle = '#ffffff';
2410
+ ctx.font = `${Math.max(8, nodeRadius / 2)}px monospace`;
2411
  ctx.textAlign = 'center';
2412
  ctx.textBaseline = 'middle';
2413
  ctx.shadowColor = 'rgba(0, 0, 0, 0.9)';
2414
  ctx.shadowBlur = 2;
2415
+
2416
+ // Show activation value
2417
+ ctx.fillText(activation.toFixed(2), x, y - 2);
2418
+
2419
+ // Show gradient information for training neurons
2420
+ if (isTraining && weightChanges && weightChanges.length > 0) {
2421
+ let neuronGradient = 0;
2422
+ if (layerIndex < network.layers.length - 1 && weightChanges[layerIndex]) {
2423
+ for (let outIdx = 0; outIdx < weightChanges[layerIndex].length; outIdx++) {
2424
+ if (weightChanges[layerIndex][outIdx] && weightChanges[layerIndex][outIdx][nodeIndex]) {
2425
+ neuronGradient += Math.abs(weightChanges[layerIndex][outIdx][nodeIndex]);
2426
+ }
2427
+ }
2428
+ neuronGradient /= weightChanges[layerIndex].length || 1;
2429
+ }
2430
+
2431
+ if (neuronGradient > 0.01) {
2432
+ ctx.fillStyle = neuronGradient > 0.1 ? '#ffff00' : '#ffffff';
2433
+ ctx.font = `${Math.max(6, nodeRadius / 3)}px monospace`;
2434
+ ctx.fillText(`Δ${neuronGradient.toFixed(2)}`, x, y + 8);
2435
+ }
2436
+ }
2437
+
2438
  ctx.shadowBlur = 0;
2439
  }
2440
  });
 
2519
  lossArea.setAttribute('points', points + ' 100,100 0,100');
2520
  }
2521
 
2522
+ // Loss landscape functions
2523
+ function calculateLossLandscape() {
2524
+ if (!network || !currentTask) return;
2525
+
2526
+ const range = 2;
2527
+ lossLandscape = [];
2528
+ gradientField = [];
2529
+
2530
+ // Sample key weights from the first layer for visualization
2531
+ const originalWeights = JSON.parse(JSON.stringify(network.weights));
2532
+
2533
+ for (let i = 0; i < landscapeResolution; i++) {
2534
+ lossLandscape[i] = [];
2535
+ gradientField[i] = [];
2536
+
2537
+ for (let j = 0; j < landscapeResolution; j++) {
2538
+ // Perturb the first two weights
2539
+ const w1 = (i / (landscapeResolution - 1) - 0.5) * range;
2540
+ const w2 = (j / (landscapeResolution - 1) - 0.5) * range;
2541
+
2542
+ if (network.weights[0] && network.weights[0][0]) {
2543
+ network.weights[0][0][0] = originalWeights[0][0][0] + w1;
2544
+ if (network.weights[0][0][1] !== undefined) {
2545
+ network.weights[0][0][1] = originalWeights[0][0][1] + w2;
2546
+ }
2547
+ }
2548
+
2549
+ // Calculate loss at this point
2550
+ let totalLoss = 0;
2551
+ let gradX = 0, gradY = 0;
2552
+
2553
+ const epsilon = 0.001;
2554
+
2555
+ // Calculate loss
2556
+ for (const sample of currentTask.data) {
2557
+ const output = network.forward(sample.input);
2558
+ const loss = sample.target.reduce((sum, t, idx) =>
2559
+ sum + Math.pow(t - output[idx], 2), 0) / sample.target.length;
2560
+ totalLoss += loss;
2561
+ }
2562
+ totalLoss /= currentTask.data.length;
2563
+
2564
+ // Calculate numerical gradients
2565
+ if (network.weights[0] && network.weights[0][0]) {
2566
+ // Gradient in x direction
2567
+ network.weights[0][0][0] = originalWeights[0][0][0] + w1 + epsilon;
2568
+ let lossPlus = 0;
2569
+ for (const sample of currentTask.data) {
2570
+ const output = network.forward(sample.input);
2571
+ const loss = sample.target.reduce((sum, t, idx) =>
2572
+ sum + Math.pow(t - output[idx], 2), 0) / sample.target.length;
2573
+ lossPlus += loss;
2574
+ }
2575
+ lossPlus /= currentTask.data.length;
2576
+ gradX = (lossPlus - totalLoss) / epsilon;
2577
+
2578
+ // Reset and calculate gradient in y direction
2579
+ network.weights[0][0][0] = originalWeights[0][0][0] + w1;
2580
+ if (network.weights[0][0][1] !== undefined) {
2581
+ network.weights[0][0][1] = originalWeights[0][0][1] + w2 + epsilon;
2582
+ let lossPlusY = 0;
2583
+ for (const sample of currentTask.data) {
2584
+ const output = network.forward(sample.input);
2585
+ const loss = sample.target.reduce((sum, t, idx) =>
2586
+ sum + Math.pow(t - output[idx], 2), 0) / sample.target.length;
2587
+ lossPlusY += loss;
2588
+ }
2589
+ lossPlusY /= currentTask.data.length;
2590
+ gradY = (lossPlusY - totalLoss) / epsilon;
2591
+ }
2592
+ }
2593
+
2594
+ lossLandscape[i][j] = totalLoss;
2595
+ gradientField[i][j] = { x: gradX, y: gradY };
2596
+ }
2597
+ }
2598
+
2599
+ // Restore original weights
2600
+ network.weights = originalWeights;
2601
+ }
2602
+
2603
+ function drawLossLandscape() {
2604
+ const canvas = lossLandscapeCanvas;
2605
+ const ctx = canvas.getContext('2d');
2606
+ const width = canvas.width;
2607
+ const height = canvas.height;
2608
+
2609
+ ctx.clearRect(0, 0, width, height);
2610
+
2611
+ if (lossLandscape.length === 0) {
2612
+ ctx.fillStyle = '#9ca3af';
2613
+ ctx.font = '16px system-ui';
2614
+ ctx.textAlign = 'center';
2615
+ ctx.fillText('Training to generate loss landscape...', width/2, height/2);
2616
+ return;
2617
+ }
2618
+
2619
+ // Transform and projection parameters
2620
+ const centerX = width / 2;
2621
+ const centerY = height / 2;
2622
+ const scale = 200 * zoomLevel;
2623
+
2624
+ const radX = (rotationX * Math.PI) / 180;
2625
+ const radZ = (rotationZ * Math.PI) / 180;
2626
+
2627
+ // Find min/max loss for normalization
2628
+ let minLoss = Infinity, maxLoss = -Infinity;
2629
+ for (let i = 0; i < landscapeResolution; i++) {
2630
+ for (let j = 0; j < landscapeResolution; j++) {
2631
+ minLoss = Math.min(minLoss, lossLandscape[i][j]);
2632
+ maxLoss = Math.max(maxLoss, lossLandscape[i][j]);
2633
+ }
2634
+ }
2635
+
2636
+ const lossRange = maxLoss - minLoss || 1;
2637
+
2638
+ // Create projected points
2639
+ const projectedPoints = [];
2640
+ for (let i = 0; i < landscapeResolution; i++) {
2641
+ projectedPoints[i] = [];
2642
+ for (let j = 0; j < landscapeResolution; j++) {
2643
+ const x = (i / (landscapeResolution - 1) - 0.5) * 2;
2644
+ const y = (j / (landscapeResolution - 1) - 0.5) * 2;
2645
+ const z = ((lossLandscape[i][j] - minLoss) / lossRange - 0.5) * 1.5;
2646
+
2647
+ // 3D rotation
2648
+ const y1 = y * Math.cos(radX) - z * Math.sin(radX);
2649
+ const z1 = y * Math.sin(radX) + z * Math.cos(radX);
2650
+ const x2 = x * Math.cos(radZ) - y1 * Math.sin(radZ);
2651
+ const y2 = x * Math.sin(radZ) + y1 * Math.cos(radZ);
2652
+
2653
+ projectedPoints[i][j] = {
2654
+ x: centerX + x2 * scale,
2655
+ y: centerY + y2 * scale,
2656
+ z: z1,
2657
+ loss: lossLandscape[i][j]
2658
+ };
2659
+ }
2660
+ }
2661
+
2662
+ // Draw contour lines if enabled
2663
+ if (showContours) {
2664
+ const contourLevels = 8;
2665
+ for (let level = 0; level < contourLevels; level++) {
2666
+ const targetLoss = minLoss + (level / contourLevels) * lossRange;
2667
+ ctx.strokeStyle = `hsla(${240 - level * 30}, 70%, 60%, 0.3)`;
2668
+ ctx.lineWidth = 1;
2669
+
2670
+ for (let i = 0; i < landscapeResolution - 1; i++) {
2671
+ for (let j = 0; j < landscapeResolution - 1; j++) {
2672
+ const corners = [
2673
+ projectedPoints[i][j],
2674
+ projectedPoints[i+1][j],
2675
+ projectedPoints[i+1][j+1],
2676
+ projectedPoints[i][j+1]
2677
+ ];
2678
+
2679
+ // Simple contour drawing
2680
+ for (let k = 0; k < 4; k++) {
2681
+ const p1 = corners[k];
2682
+ const p2 = corners[(k + 1) % 4];
2683
+
2684
+ if ((p1.loss <= targetLoss && p2.loss >= targetLoss) ||
2685
+ (p1.loss >= targetLoss && p2.loss <= targetLoss)) {
2686
+ const t = (targetLoss - p1.loss) / (p2.loss - p1.loss);
2687
+ const x = p1.x + t * (p2.x - p1.x);
2688
+ const y = p1.y + t * (p2.y - p1.y);
2689
+
2690
+ ctx.beginPath();
2691
+ ctx.arc(x, y, 1, 0, 2 * Math.PI);
2692
+ ctx.stroke();
2693
+ }
2694
+ }
2695
+ }
2696
+ }
2697
+ }
2698
+ }
2699
+
2700
+ // Draw surface mesh
2701
+ for (let i = 0; i < landscapeResolution - 1; i++) {
2702
+ for (let j = 0; j < landscapeResolution - 1; j++) {
2703
+ const corners = [
2704
+ projectedPoints[i][j],
2705
+ projectedPoints[i+1][j],
2706
+ projectedPoints[i+1][j+1],
2707
+ projectedPoints[i][j+1]
2708
+ ];
2709
+
2710
+ // Color based on loss value
2711
+ const avgLoss = corners.reduce((sum, p) => sum + p.loss, 0) / 4;
2712
+ const normalizedLoss = (avgLoss - minLoss) / lossRange;
2713
+ const hue = 240 - normalizedLoss * 120; // Blue to red
2714
+ const alpha = 0.6;
2715
+
2716
+ ctx.fillStyle = `hsla(${hue}, 70%, 50%, ${alpha})`;
2717
+ ctx.strokeStyle = `hsla(${hue}, 70%, 30%, 0.8)`;
2718
+ ctx.lineWidth = 0.5;
2719
+
2720
+ ctx.beginPath();
2721
+ ctx.moveTo(corners[0].x, corners[0].y);
2722
+ for (let k = 1; k < corners.length; k++) {
2723
+ ctx.lineTo(corners[k].x, corners[k].y);
2724
+ }
2725
+ ctx.closePath();
2726
+ ctx.fill();
2727
+ ctx.stroke();
2728
+ }
2729
+ }
2730
+
2731
+ // Draw gradient arrows if enabled
2732
+ if (showGradients) {
2733
+ const step = Math.max(1, Math.floor(landscapeResolution / 15));
2734
+ for (let i = 0; i < landscapeResolution; i += step) {
2735
+ for (let j = 0; j < landscapeResolution; j += step) {
2736
+ const point = projectedPoints[i][j];
2737
+ const grad = gradientField[i][j];
2738
+
2739
+ if (grad && (Math.abs(grad.x) > 0.01 || Math.abs(grad.y) > 0.01)) {
2740
+ const arrowLength = 30;
2741
+ const gradMagnitude = Math.sqrt(grad.x * grad.x + grad.y * grad.y);
2742
+ const normalizedGradX = (grad.x / gradMagnitude) * arrowLength;
2743
+ const normalizedGradY = (grad.y / gradMagnitude) * arrowLength;
2744
+
2745
+ // Transform gradient direction
2746
+ const gx1 = normalizedGradX * Math.cos(radZ) - normalizedGradY * Math.sin(radZ);
2747
+ const gy1 = normalizedGradX * Math.sin(radZ) + normalizedGradY * Math.cos(radZ);
2748
+
2749
+ ctx.strokeStyle = '#f59e0b';
2750
+ ctx.lineWidth = 2;
2751
+ ctx.beginPath();
2752
+ ctx.moveTo(point.x, point.y);
2753
+ ctx.lineTo(point.x - gx1, point.y - gy1);
2754
+ ctx.stroke();
2755
+
2756
+ // Arrow head
2757
+ const headLength = 6;
2758
+ const angle = Math.atan2(-gy1, -gx1);
2759
+ ctx.beginPath();
2760
+ ctx.moveTo(point.x - gx1, point.y - gy1);
2761
+ ctx.lineTo(
2762
+ point.x - gx1 + headLength * Math.cos(angle - Math.PI/6),
2763
+ point.y - gy1 + headLength * Math.sin(angle - Math.PI/6)
2764
+ );
2765
+ ctx.moveTo(point.x - gx1, point.y - gy1);
2766
+ ctx.lineTo(
2767
+ point.x - gx1 + headLength * Math.cos(angle + Math.PI/6),
2768
+ point.y - gy1 + headLength * Math.sin(angle + Math.PI/6)
2769
+ );
2770
+ ctx.stroke();
2771
+ }
2772
+ }
2773
+ }
2774
+ }
2775
+
2776
+ // Draw training path if enabled
2777
+ if (showPath && trainingPath.length > 1) {
2778
+ ctx.strokeStyle = '#06b6d4';
2779
+ ctx.lineWidth = 3;
2780
+ ctx.beginPath();
2781
+
2782
+ for (let i = 0; i < trainingPath.length; i++) {
2783
+ const pathPoint = trainingPath[i];
2784
+ // Project path point to screen coordinates
2785
+ const x = (pathPoint.w1 / 2 + 0.5) * (landscapeResolution - 1);
2786
+ const y = (pathPoint.w2 / 2 + 0.5) * (landscapeResolution - 1);
2787
+
2788
+ if (x >= 0 && x < landscapeResolution && y >= 0 && y < landscapeResolution) {
2789
+ const xi = Math.floor(x);
2790
+ const yi = Math.floor(y);
2791
+
2792
+ if (xi < landscapeResolution && yi < landscapeResolution && projectedPoints[xi] && projectedPoints[xi][yi]) {
2793
+ const point = projectedPoints[xi][yi];
2794
+ if (i === 0) {
2795
+ ctx.moveTo(point.x, point.y);
2796
+ } else {
2797
+ ctx.lineTo(point.x, point.y);
2798
+ }
2799
+ }
2800
+ }
2801
+ }
2802
+ ctx.stroke();
2803
+
2804
+ // Mark current position
2805
+ if (trainingPath.length > 0) {
2806
+ const current = trainingPath[trainingPath.length - 1];
2807
+ const x = (current.w1 / 2 + 0.5) * (landscapeResolution - 1);
2808
+ const y = (current.w2 / 2 + 0.5) * (landscapeResolution - 1);
2809
+
2810
+ if (x >= 0 && x < landscapeResolution && y >= 0 && y < landscapeResolution) {
2811
+ const xi = Math.floor(x);
2812
+ const yi = Math.floor(y);
2813
+
2814
+ if (xi < landscapeResolution && yi < landscapeResolution && projectedPoints[xi] && projectedPoints[xi][yi]) {
2815
+ const point = projectedPoints[xi][yi];
2816
+ ctx.fillStyle = '#06b6d4';
2817
+ ctx.beginPath();
2818
+ ctx.arc(point.x, point.y, 5, 0, 2 * Math.PI);
2819
+ ctx.fill();
2820
+ }
2821
+ }
2822
+ }
2823
+ }
2824
+ }
2825
+
2826
  // Training step
2827
  function trainStep() {
2828
  const result = network.trainBatch(currentTask.data);
 
2837
  lossHistory.push(result.loss);
2838
  if (lossHistory.length > 100) lossHistory.shift();
2839
 
2840
+ // Track training path for loss landscape
2841
+ if (network.weights[0] && network.weights[0][0] && trainingPath.length < 1000) {
2842
+ trainingPath.push({
2843
+ w1: network.weights[0][0][0] || 0,
2844
+ w2: network.weights[0][0][1] || 0,
2845
+ loss: result.loss,
2846
+ epoch: epoch
2847
+ });
2848
+ }
2849
+
2850
+ // Recalculate loss landscape periodically
2851
+ if (epoch % 10 === 0) {
2852
+ calculateLossLandscape();
2853
+ }
2854
+
2855
  const newPredictions = currentTask.data.map(data => {
2856
  const output = network.forward(data.input);
2857
  const rawOutput = output[0];
 
2915
 
2916
  updateLossChart();
2917
  drawNetwork();
2918
+ drawLossLandscape();
2919
  if (currentTask.hasVisualization) {
2920
  drawDataVisualization();
2921
  }
 
2952
  if (currentTask.isBabyMode) {
2953
  updateBabyVisualization();
2954
  }
2955
+ drawLossLandscape();
2956
  }
2957
  animationId = requestAnimationFrame(animate);
2958
  }
 
2982
  accuracy = 0;
2983
  animationTime = 0;
2984
 
2985
+ // Reset loss landscape
2986
+ lossLandscape = [];
2987
+ gradientField = [];
2988
+ trainingPath = [];
2989
+ calculateLossLandscape();
2990
+
2991
  trainBtn.innerHTML = `
2992
  <svg class="icon" fill="currentColor" viewBox="0 0 24 24">
2993
  <path d="M8 5v14l11-7z"/>
 
3012
  `;
3013
  trainBtn.className = 'btn btn-pause';
3014
 
3015
+ const trainingSpeed = 100;
 
3016
  trainInterval = setInterval(trainStep, trainingSpeed);
3017
  } else {
3018
  trainBtn.innerHTML = `
 
3033
  // Developer mode event listeners
3034
  devArchitecture.addEventListener('input', updateParameterCount);
3035
 
3036
+ // Loss landscape event listeners
3037
+ rotationXSlider.addEventListener('input', (e) => {
3038
+ rotationX = parseFloat(e.target.value);
3039
+ drawLossLandscape();
3040
+ });
3041
+
3042
+ rotationZSlider.addEventListener('input', (e) => {
3043
+ rotationZ = parseFloat(e.target.value);
3044
+ drawLossLandscape();
3045
+ });
3046
+
3047
+ zoomSlider.addEventListener('input', (e) => {
3048
+ zoomLevel = parseFloat(e.target.value);
3049
+ drawLossLandscape();
3050
+ });
3051
+
3052
+ gradientsCheckbox.addEventListener('change', (e) => {
3053
+ showGradients = e.target.checked;
3054
+ drawLossLandscape();
3055
+ });
3056
+
3057
+ contoursCheckbox.addEventListener('change', (e) => {
3058
+ showContours = e.target.checked;
3059
+ drawLossLandscape();
3060
+ });
3061
+
3062
+ pathCheckbox.addEventListener('change', (e) => {
3063
+ showPath = e.target.checked;
3064
+ drawLossLandscape();
3065
+ });
3066
+
3067
+ // Mouse interaction for loss landscape
3068
+ lossLandscapeCanvas.addEventListener('mousedown', (e) => {
3069
+ mouseDown = true;
3070
+ lastMouseX = e.clientX;
3071
+ lastMouseY = e.clientY;
3072
+ });
3073
+
3074
+ lossLandscapeCanvas.addEventListener('mousemove', (e) => {
3075
+ if (mouseDown) {
3076
+ const deltaX = e.clientX - lastMouseX;
3077
+ const deltaY = e.clientY - lastMouseY;
3078
+
3079
+ rotationZ = (rotationZ + deltaX * 0.5) % 360;
3080
+ rotationX = Math.max(-90, Math.min(90, rotationX - deltaY * 0.5));
3081
+
3082
+ rotationXSlider.value = rotationX;
3083
+ rotationZSlider.value = rotationZ;
3084
+
3085
+ drawLossLandscape();
3086
+
3087
+ lastMouseX = e.clientX;
3088
+ lastMouseY = e.clientY;
3089
+ }
3090
+ });
3091
+
3092
+ lossLandscapeCanvas.addEventListener('mouseup', () => {
3093
+ mouseDown = false;
3094
+ });
3095
+
3096
+ lossLandscapeCanvas.addEventListener('mouseleave', () => {
3097
+ mouseDown = false;
3098
+ });
3099
+
3100
+ // Wheel zoom for loss landscape
3101
+ lossLandscapeCanvas.addEventListener('wheel', (e) => {
3102
+ e.preventDefault();
3103
+ const delta = e.deltaY > 0 ? 0.9 : 1.1;
3104
+ zoomLevel = Math.max(0.5, Math.min(3, zoomLevel * delta));
3105
+ zoomSlider.value = zoomLevel;
3106
+ drawLossLandscape();
3107
+ });
3108
+
3109
  // Walkthrough Mode functionality
3110
  let walkthroughActive = false;
3111
  let walkthroughStep = 0;
 
3127
  content: 'This is the input layer (left side). It receives the raw data - like numbers, images, or text. Each circle represents one input neuron that holds a piece of information.',
3128
  element: '#networkCanvas',
3129
  position: 'right',
3130
+ highlight: {x: 0, y: 0, width: 130, height: 300}
3131
  },
3132
  {
3133
  title: 'Hidden Layers',
3134
  content: 'These middle layers are where the "magic" happens! They transform the input data through mathematical operations, finding patterns and relationships.',
3135
  element: '#networkCanvas',
3136
  position: 'top',
3137
+ highlight: {x: 130, y: 0, width: 140, height: 300}
3138
  },
3139
  {
3140
  title: 'Output Layer',
3141
  content: 'The final layer gives us the result - a prediction, classification, or decision based on what the network learned from the input.',
3142
  element: '#networkCanvas',
3143
  position: 'left',
3144
+ highlight: {x: 270, y: 0, width: 130, height: 300}
3145
  },
3146
  {
3147
  title: 'Connections (Weights)',
 
3262
  position: 'right'
3263
  }
3264
  ]
3265
+ },
3266
+ landscape: {
3267
+ title: 'Loss Landscape & Gradients',
3268
+ steps: [
3269
+ {
3270
+ title: 'Welcome to Loss Landscapes!',
3271
+ content: 'The loss landscape shows how the error changes as we adjust the network\'s weights. Think of it like a 3D mountain range where we want to find the lowest valley.',
3272
+ element: null,
3273
+ position: 'center'
3274
+ },
3275
+ {
3276
+ title: 'The 3D Loss Surface',
3277
+ content: 'This 3D visualization shows the loss landscape. Blue areas are low loss (good), red areas are high loss (bad). The network tries to \'roll downhill\' to find the minimum.',
3278
+ element: '#lossLandscapeCanvas',
3279
+ position: 'right'
3280
+ },
3281
+ {
3282
+ title: 'Gradient Arrows',
3283
+ content: 'The yellow arrows show gradients - they point in the direction of steepest increase in loss. The network moves OPPOSITE to these arrows to reduce loss.',
3284
+ element: '.landscape-toggle',
3285
+ position: 'top'
3286
+ },
3287
+ {
3288
+ title: 'Training Path',
3289
+ content: 'The blue line shows the path the network takes during training. It starts somewhere random and gradually finds its way to low-loss regions.',
3290
+ element: '#lossLandscapeCanvas',
3291
+ position: 'bottom'
3292
+ },
3293
+ {
3294
+ title: 'Interactive Controls',
3295
+ content: 'Use these controls to rotate, zoom, and toggle different visualizations. Try dragging on the landscape to rotate it around!',
3296
+ element: '.landscape-controls',
3297
+ position: 'bottom'
3298
+ },
3299
+ {
3300
+ title: 'Start Training to See It Live',
3301
+ content: 'Now start training a task and watch how the loss landscape guides the learning process. The path will update in real-time!',
3302
+ element: '#trainBtn',
3303
+ position: 'bottom'
3304
+ }
3305
+ ]
3306
+ },
3307
+ advanced: {
3308
+ title: 'Advanced Visualizations',
3309
+ steps: [
3310
+ {
3311
+ title: 'Advanced Neural Network Insights',
3312
+ content: 'Now let\'s explore the advanced visualizations that show exactly what happens inside the neural network during training.',
3313
+ element: null,
3314
+ position: 'center'
3315
+ },
3316
+ {
3317
+ title: 'Gradient Flow in Connections',
3318
+ content: 'Watch the animated particles flowing along connections. More particles = stronger gradients. Green flows are positive weights, red are negative.',
3319
+ element: '#networkCanvas',
3320
+ position: 'right'
3321
+ },
3322
+ {
3323
+ title: 'Neuron Gradient Rings',
3324
+ content: 'Yellow rings around neurons show gradient magnitude. Bright, pulsing rings mean the neuron is changing rapidly during training.',
3325
+ element: '#networkCanvas',
3326
+ position: 'left'
3327
+ },
3328
+ {
3329
+ title: 'Weight Change Indicators',
3330
+ content: 'The thickness and brightness of connections show how much each weight is changing. Thicker, brighter lines = more learning happening.',
3331
+ element: '#networkCanvas',
3332
+ position: 'top'
3333
+ },
3334
+ {
3335
+ title: 'Loss Landscape Contours',
3336
+ content: 'Contour lines on the loss landscape are like elevation lines on a topographic map - they show areas of equal loss value.',
3337
+ element: '#lossLandscapeCanvas',
3338
+ position: 'right'
3339
+ },
3340
+ {
3341
+ title: 'Real-time Training Visualization',
3342
+ content: 'All these visualizations update in real-time as the network trains. You can see the exact moment when the network \'gets it\'!',
3343
+ element: '.control-panel',
3344
+ position: 'bottom'
3345
+ },
3346
+ {
3347
+ title: 'Understanding Convergence',
3348
+ content: 'Watch how the training path in the loss landscape eventually stops moving - this means the network has converged to a solution.',
3349
+ element: '#lossLandscapeCanvas',
3350
+ position: 'bottom'
3351
+ }
3352
+ ]
3353
  }
3354
  };
3355
 
 
3367
  taskSelection.style.display = 'block';
3368
  currentCategory = 'fundamentals';
3369
  showCategory('fundamentals');
3370
+ } else if (tutorialId === 'landscape' || tutorialId === 'advanced') {
3371
+ document.getElementById('walkthroughMode').style.display = 'none';
3372
+ taskSelection.style.display = 'block';
3373
+ currentCategory = 'fundamentals';
3374
+ showCategory('fundamentals');
3375
+ // Auto-select XOR for better landscape visualization
3376
+ setTimeout(() => selectTask('xor'), 500);
3377
+ } else if (tutorialId === 'basics' || tutorialId === 'training' || tutorialId === 'visualization') {
3378
+ // For basic tutorials, start with a simple task for better understanding
3379
+ document.getElementById('walkthroughMode').style.display = 'none';
3380
+ taskSelection.style.display = 'block';
3381
+ currentCategory = 'fundamentals';
3382
+ showCategory('fundamentals');
3383
+ setTimeout(() => selectTask('and'), 500);
3384
  }
3385
 
3386
  showWalkthroughStep();
 
3397
  document.getElementById('walkthroughStep').textContent = walkthroughStep + 1;
3398
  document.getElementById('walkthroughTotal').textContent = walkthroughTutorial.steps.length;
3399
 
3400
+ // Show overlay with reduced opacity for better visibility
3401
  overlay.style.display = 'block';
3402
  progress.style.display = 'block';
3403
+
3404
+ // Ensure all content is visible by adjusting z-index
3405
+ document.getElementById('trainingInterface').style.position = 'relative';
3406
+ document.getElementById('trainingInterface').style.zIndex = '1';
3407
 
3408
  // Update popup content
3409
  document.getElementById('walkthroughTitle').textContent = step.title;
 
3415
  if (element) {
3416
  const rect = element.getBoundingClientRect();
3417
 
3418
+ // Highlight element with better visibility
3419
  if (step.highlight) {
3420
  const canvasRect = element.getBoundingClientRect();
3421
  highlight.style.left = (canvasRect.left + step.highlight.x) + 'px';
 
3423
  highlight.style.width = step.highlight.width + 'px';
3424
  highlight.style.height = step.highlight.height + 'px';
3425
  } else {
3426
+ highlight.style.left = rect.left - 8 + 'px';
3427
+ highlight.style.top = rect.top - 8 + 'px';
3428
+ highlight.style.width = rect.width + 16 + 'px';
3429
+ highlight.style.height = rect.height + 16 + 'px';
3430
  }
3431
  highlight.style.display = 'block';
3432
+
3433
+ // Bring highlighted element to front
3434
+ if (element) {
3435
+ element.style.position = 'relative';
3436
+ element.style.zIndex = '10002';
3437
+ }
3438
 
3439
  // Position popup
3440
  positionPopup(popup, rect, step.position);
 
3523
  document.getElementById('walkthroughPopup').style.display = 'none';
3524
  document.getElementById('walkthroughProgress').style.display = 'none';
3525
  document.getElementById('walkthroughIndicator').style.display = 'none';
3526
+
3527
+ // Reset z-index values
3528
+ const trainingInterface = document.getElementById('trainingInterface');
3529
+ if (trainingInterface) {
3530
+ trainingInterface.style.zIndex = '';
3531
+ trainingInterface.style.position = '';
3532
+ }
3533
+
3534
+ // Reset any highlighted elements
3535
+ const networkCanvas = document.getElementById('networkCanvas');
3536
+ if (networkCanvas) {
3537
+ networkCanvas.style.zIndex = '';
3538
+ networkCanvas.style.position = '';
3539
+ }
3540
  }
3541
 
3542
  // Walkthrough event listeners
 
3546
 
3547
  // Initialize
3548
  startAnimation();
3549
+
3550
+ // Initialize loss landscape on page load
3551
+ setTimeout(() => {
3552
+ if (lossLandscapeCanvas) {
3553
+ const ctx = lossLandscapeCanvas.getContext('2d');
3554
+ ctx.fillStyle = '#9ca3af';
3555
+ ctx.font = '16px system-ui';
3556
+ ctx.textAlign = 'center';
3557
+ ctx.fillText('Select a task to view loss landscape', lossLandscapeCanvas.width/2, lossLandscapeCanvas.height/2);
3558
+ }
3559
+ }, 100);
3560
  </script>
 
3561
  </body>
3562
  </html>