ameerazam08 commited on
Commit
2ebba09
·
verified ·
1 Parent(s): a895648

Upload 22 files

Browse files
Files changed (5) hide show
  1. css/styles.css +79 -3
  2. index.html +22 -14
  3. js/complete-drag-fix.js +155 -3
  4. js/layer-editor.js +123 -13
  5. js/main.js +335 -150
css/styles.css CHANGED
@@ -34,6 +34,12 @@
34
  --node-glow: 0 0 15px rgba(255, 255, 255, 0.8);
35
  --linear-node-color-1: #1abc9c;
36
  --linear-node-color-2: #16a085;
 
 
 
 
 
 
37
  }
38
 
39
  body {
@@ -719,10 +725,10 @@ footer p {
719
  margin-bottom: 1rem;
720
  }
721
 
722
- .setting-label {
723
  font-size: 0.9rem;
724
  color: #666;
725
- margin-bottom: 0.3rem;
726
  display: block;
727
  }
728
 
@@ -733,6 +739,7 @@ footer p {
733
  border-radius: 5px;
734
  background: #ddd;
735
  outline: none;
 
736
  }
737
 
738
  .range-slider::-webkit-slider-thumb {
@@ -751,7 +758,24 @@ footer p {
751
  box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.3);
752
  }
753
 
754
- .range-value {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
755
  font-size: 0.9rem;
756
  color: var(--primary-color);
757
  font-weight: 600;
@@ -818,6 +842,25 @@ select {
818
  margin-bottom: 1.5rem;
819
  }
820
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
821
  .layer-weights {
822
  display: flex;
823
  justify-content: center;
@@ -2038,4 +2081,37 @@ select {
2038
  #stats-container {
2039
  grid-template-columns: 1fr;
2040
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2041
  }
 
34
  --node-glow: 0 0 15px rgba(255, 255, 255, 0.8);
35
  --linear-node-color-1: #1abc9c;
36
  --linear-node-color-2: #16a085;
37
+ --lstm-node-color-1: #9c88ff;
38
+ --lstm-node-color-2: #8c7ae6;
39
+ --rnn-node-color-1: #00cec9;
40
+ --rnn-node-color-2: #00b894;
41
+ --gru-node-color-1: #fd79a8;
42
+ --gru-node-color-2: #e84393;
43
  }
44
 
45
  body {
 
725
  margin-bottom: 1rem;
726
  }
727
 
728
+ .setting-group label {
729
  font-size: 0.9rem;
730
  color: #666;
731
+ margin-bottom: 0.5rem;
732
  display: block;
733
  }
734
 
 
739
  border-radius: 5px;
740
  background: #ddd;
741
  outline: none;
742
+ margin: 10px 0;
743
  }
744
 
745
  .range-slider::-webkit-slider-thumb {
 
758
  box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.3);
759
  }
760
 
761
+ .range-slider::-moz-range-thumb {
762
+ width: 18px;
763
+ height: 18px;
764
+ border-radius: 50%;
765
+ background: var(--primary-color);
766
+ cursor: pointer;
767
+ transition: all 0.2s ease;
768
+ border: none;
769
+ }
770
+
771
+ .range-slider::-moz-range-thumb:hover {
772
+ background: #2980b9;
773
+ box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.3);
774
+ }
775
+
776
+ .setting-value {
777
+ display: flex;
778
+ justify-content: flex-end;
779
  font-size: 0.9rem;
780
  color: var(--primary-color);
781
  font-weight: 600;
 
842
  margin-bottom: 1.5rem;
843
  }
844
 
845
+ .activation-graph {
846
+ background: #f8f9fa;
847
+ border-radius: var(--border-radius);
848
+ padding: 1rem;
849
+ margin-bottom: 1.5rem;
850
+ width: 100%;
851
+ height: 150px;
852
+ position: relative;
853
+ overflow: hidden;
854
+ }
855
+
856
+ .activation-curve {
857
+ width: 100%;
858
+ height: 100%;
859
+ display: block;
860
+ background-color: #f8f9fa;
861
+ border-radius: var(--border-radius);
862
+ }
863
+
864
  .layer-weights {
865
  display: flex;
866
  justify-content: center;
 
2081
  #stats-container {
2082
  grid-template-columns: 1fr;
2083
  }
2084
+ }
2085
+
2086
+ .lstm-node {
2087
+ background: linear-gradient(135deg, var(--lstm-node-color-1), var(--lstm-node-color-2));
2088
+ border: 2px solid var(--lstm-node-color-1);
2089
+ color: white;
2090
+ }
2091
+
2092
+ .rnn-node {
2093
+ background: linear-gradient(135deg, var(--rnn-node-color-1), var(--rnn-node-color-2));
2094
+ border: 2px solid var(--rnn-node-color-1);
2095
+ color: white;
2096
+ }
2097
+
2098
+ .gru-node {
2099
+ background: linear-gradient(135deg, var(--gru-node-color-1), var(--gru-node-color-2));
2100
+ border: 2px solid var(--gru-node-color-1);
2101
+ color: white;
2102
+ }
2103
+
2104
+ .canvas-node[data-type="lstm"] {
2105
+ background: linear-gradient(135deg, var(--lstm-node-color-1), var(--lstm-node-color-2), var(--lstm-node-color-1));
2106
+ border: 2px solid var(--lstm-node-color-1);
2107
+ }
2108
+
2109
+ .canvas-node[data-type="rnn"] {
2110
+ background: linear-gradient(135deg, var(--rnn-node-color-1), var(--rnn-node-color-2), var(--rnn-node-color-1));
2111
+ border: 2px solid var(--rnn-node-color-1);
2112
+ }
2113
+
2114
+ .canvas-node[data-type="gru"] {
2115
+ background: linear-gradient(135deg, var(--gru-node-color-1), var(--gru-node-color-2), var(--gru-node-color-1));
2116
+ border: 2px solid var(--gru-node-color-1);
2117
  }
index.html CHANGED
@@ -53,16 +53,15 @@
53
  <div class="node-item" draggable="true" data-type="pool">
54
  <div class="node pool-node">Pooling</div>
55
  </div>
56
- <div class="node-item" draggable="true" data-type="linear">
57
- <div class="node linear-node">Linear Regression</div>
 
 
 
 
 
 
58
  </div>
59
- </div>
60
-
61
- <h3 class="section-title">Sample Data</h3>
62
- <div class="sample-data">
63
- <div class="sample-item" data-sample="1">5</div>
64
- <div class="sample-item" data-sample="2">7</div>
65
- <div class="sample-item" data-sample="3">3</div>
66
  </div>
67
 
68
  <div class="controls">
@@ -74,8 +73,10 @@
74
  <div class="network-settings">
75
  <div class="setting-group">
76
  <label for="learning-rate">Learning Rate:</label>
77
- <input type="range" id="learning-rate" min="0.001" max="1" step="0.001" value="0.1">
78
- <span class="setting-value" id="learning-rate-value">0.1</span>
 
 
79
  </div>
80
  <div class="setting-group">
81
  <label for="activation">Activation:</label>
@@ -85,6 +86,14 @@
85
  <option value="tanh">Tanh</option>
86
  </select>
87
  </div>
 
 
 
 
 
 
 
 
88
  </div>
89
  </div>
90
 
@@ -432,9 +441,8 @@
432
  <footer>
433
  <p>Neural Network Playground - Learn and visualize neural networks interactively</p>
434
  <div class="footer-links">
435
- <a href="#" id="about-link">About</a>
436
- <a href="#" id="guide-link">User Guide</a>
437
- <a href="https://github.com/yourusername/neural-network-playground" target="_blank">GitHub</a>
438
  </div>
439
  </footer>
440
 
 
53
  <div class="node-item" draggable="true" data-type="pool">
54
  <div class="node pool-node">Pooling</div>
55
  </div>
56
+ <div class="node-item" draggable="true" data-type="lstm">
57
+ <div class="node lstm-node">LSTM</div>
58
+ </div>
59
+ <div class="node-item" draggable="true" data-type="rnn">
60
+ <div class="node rnn-node">RNN</div>
61
+ </div>
62
+ <div class="node-item" draggable="true" data-type="gru">
63
+ <div class="node gru-node">GRU</div>
64
  </div>
 
 
 
 
 
 
 
65
  </div>
66
 
67
  <div class="controls">
 
73
  <div class="network-settings">
74
  <div class="setting-group">
75
  <label for="learning-rate">Learning Rate:</label>
76
+ <input type="range" id="learning-rate" class="range-slider" min="0.001" max="1" step="0.001" value="0.1">
77
+ <div class="setting-value">
78
+ <span id="learning-rate-value">0.1</span>
79
+ </div>
80
  </div>
81
  <div class="setting-group">
82
  <label for="activation">Activation:</label>
 
86
  <option value="tanh">Tanh</option>
87
  </select>
88
  </div>
89
+ <div class="setting-group">
90
+ <label for="optimizer">Optimizer:</label>
91
+ <select id="optimizer">
92
+ <option value="sgd">SGD</option>
93
+ <option value="adam">Adam</option>
94
+ <option value="rmsprop">RMSProp</option>
95
+ </select>
96
+ </div>
97
  </div>
98
  </div>
99
 
 
441
  <footer>
442
  <p>Neural Network Playground - Learn and visualize neural networks interactively</p>
443
  <div class="footer-links">
444
+ <a href="https://x.com/Ameerazam18" id="about-link">Follow me on X</a>
445
+ <a href="https://github.com/Ameerazam08" target="_blank">GitHub</a>
 
446
  </div>
447
  </footer>
448
 
js/complete-drag-fix.js CHANGED
@@ -196,12 +196,37 @@
196
  };
197
  break;
198
 
199
- case 'linear':
200
  nodeConfig = {
201
  units: 64,
202
- activation: 'relu',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  useBias: true,
204
- outputShape: [64],
205
  parameters: 0
206
  };
207
  break;
@@ -268,6 +293,24 @@
268
  outputShape = 'Depends on input';
269
  parameters = `Pool size: ${nodeConfig.poolSize.join('×')}\nStride: ${nodeConfig.strides.join('×')}\nPadding: ${nodeConfig.padding}`;
270
  break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  default:
272
  nodeName = 'Unknown Layer';
273
  inputShape = 'N/A';
@@ -877,6 +920,115 @@
877
  }
878
  break;
879
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
880
  case 'conv':
881
  if (sourceConfig.outputShape && sourceConfig.outputShape.length >= 3) {
882
  // Very explicit type conversion - ensure all values are numbers
 
196
  };
197
  break;
198
 
199
+ case 'lstm':
200
  nodeConfig = {
201
  units: 64,
202
+ returnSequences: true,
203
+ activation: 'tanh',
204
+ recurrentActivation: 'sigmoid',
205
+ useBias: true,
206
+ outputShape: ['?', 64],
207
+ parameters: 0
208
+ };
209
+ break;
210
+
211
+ case 'rnn':
212
+ nodeConfig = {
213
+ units: 32,
214
+ returnSequences: true,
215
+ activation: 'tanh',
216
+ useBias: true,
217
+ outputShape: ['?', 32],
218
+ parameters: 0
219
+ };
220
+ break;
221
+
222
+ case 'gru':
223
+ nodeConfig = {
224
+ units: 48,
225
+ returnSequences: true,
226
+ activation: 'tanh',
227
+ recurrentActivation: 'sigmoid',
228
  useBias: true,
229
+ outputShape: ['?', 48],
230
  parameters: 0
231
  };
232
  break;
 
293
  outputShape = 'Depends on input';
294
  parameters = `Pool size: ${nodeConfig.poolSize.join('×')}\nStride: ${nodeConfig.strides.join('×')}\nPadding: ${nodeConfig.padding}`;
295
  break;
296
+ case 'lstm':
297
+ nodeName = `LSTM ${nodeCounter[nodeType]}`;
298
+ inputShape = 'Connect input';
299
+ outputShape = `[?, ${nodeConfig.units}]`;
300
+ parameters = `Units: ${nodeConfig.units}\nReturn Sequences: ${nodeConfig.returnSequences ? 'Yes' : 'No'}\nGates: 4`;
301
+ break;
302
+ case 'rnn':
303
+ nodeName = `RNN ${nodeCounter[nodeType]}`;
304
+ inputShape = 'Connect input';
305
+ outputShape = `[?, ${nodeConfig.units}]`;
306
+ parameters = `Units: ${nodeConfig.units}\nReturn Sequences: ${nodeConfig.returnSequences ? 'Yes' : 'No'}`;
307
+ break;
308
+ case 'gru':
309
+ nodeName = `GRU ${nodeCounter[nodeType]}`;
310
+ inputShape = 'Connect input';
311
+ outputShape = `[?, ${nodeConfig.units}]`;
312
+ parameters = `Units: ${nodeConfig.units}\nReturn Sequences: ${nodeConfig.returnSequences ? 'Yes' : 'No'}\nGates: 3`;
313
+ break;
314
  default:
315
  nodeName = 'Unknown Layer';
316
  inputShape = 'N/A';
 
920
  }
921
  break;
922
 
923
+ case 'rnn':
924
+ // Get units and check if returning sequences
925
+ const rnnUnits = parseInt(targetConfig.units) || 32;
926
+ const rnnReturnSequences = targetConfig.returnSequences === 'true' || targetConfig.returnSequences === true;
927
+
928
+ // Set output shape based on return_sequences setting
929
+ if (rnnReturnSequences && sourceConfig.outputShape && sourceConfig.outputShape.length > 0) {
930
+ // If return_sequences is true, output is [sequence_length, units]
931
+ outputShape = [sourceConfig.outputShape[0], rnnUnits];
932
+ } else {
933
+ // If return_sequences is false, output is just [units]
934
+ outputShape = [rnnUnits];
935
+ }
936
+
937
+ // Calculate parameters if we have input shape
938
+ if (sourceConfig.outputShape && sourceConfig.outputShape.length > 0) {
939
+ // Get the last dimension of the input as input_features
940
+ const inputFeatures = sourceConfig.outputShape[sourceConfig.outputShape.length - 1];
941
+ const useBias = targetConfig.useBias !== 'false' && targetConfig.useBias !== false;
942
+
943
+ // Formula: input_features * units + units * units + units (bias)
944
+ const inputParams = inputFeatures * rnnUnits;
945
+ const recurrentParams = rnnUnits * rnnUnits;
946
+ const biasParams = useBias ? rnnUnits : 0;
947
+
948
+ parameters = inputParams + recurrentParams + biasParams;
949
+
950
+ console.log(`RNN parameter calculation:
951
+ Input features: ${inputFeatures}
952
+ Units: ${rnnUnits}
953
+ Input weights: ${inputParams}
954
+ Recurrent weights: ${recurrentParams}
955
+ Bias: ${biasParams}
956
+ Total: ${parameters}`);
957
+ }
958
+ break;
959
+
960
+ case 'lstm':
961
+ // Get units and check if returning sequences
962
+ const lstmUnits = parseInt(targetConfig.units) || 64;
963
+ const lstmReturnSequences = targetConfig.returnSequences === 'true' || targetConfig.returnSequences === true;
964
+
965
+ // Set output shape based on return_sequences setting
966
+ if (lstmReturnSequences && sourceConfig.outputShape && sourceConfig.outputShape.length > 0) {
967
+ outputShape = [sourceConfig.outputShape[0], lstmUnits];
968
+ } else {
969
+ outputShape = [lstmUnits];
970
+ }
971
+
972
+ // Calculate parameters if we have input shape
973
+ if (sourceConfig.outputShape && sourceConfig.outputShape.length > 0) {
974
+ // LSTM has 4 gates, each with its own weights and biases
975
+ const inputFeatures = sourceConfig.outputShape[sourceConfig.outputShape.length - 1];
976
+ const useBias = targetConfig.useBias !== 'false' && targetConfig.useBias !== false;
977
+
978
+ // Formula: 4 * (input_features * units + units * units + units (bias))
979
+ const inputParams = 4 * (inputFeatures * lstmUnits);
980
+ const recurrentParams = 4 * (lstmUnits * lstmUnits);
981
+ const biasParams = useBias ? 4 * lstmUnits : 0;
982
+
983
+ parameters = inputParams + recurrentParams + biasParams;
984
+
985
+ console.log(`LSTM parameter calculation:
986
+ Input features: ${inputFeatures}
987
+ Units: ${lstmUnits}
988
+ Gates: 4 (input, forget, cell, output)
989
+ Input weights: ${inputParams}
990
+ Recurrent weights: ${recurrentParams}
991
+ Bias: ${biasParams}
992
+ Total: ${parameters}`);
993
+ }
994
+ break;
995
+
996
+ case 'gru':
997
+ // Get units and check if returning sequences
998
+ const gruUnits = parseInt(targetConfig.units) || 48;
999
+ const gruReturnSequences = targetConfig.returnSequences === 'true' || targetConfig.returnSequences === true;
1000
+
1001
+ // Set output shape based on return_sequences setting
1002
+ if (gruReturnSequences && sourceConfig.outputShape && sourceConfig.outputShape.length > 0) {
1003
+ outputShape = [sourceConfig.outputShape[0], gruUnits];
1004
+ } else {
1005
+ outputShape = [gruUnits];
1006
+ }
1007
+
1008
+ // Calculate parameters if we have input shape
1009
+ if (sourceConfig.outputShape && sourceConfig.outputShape.length > 0) {
1010
+ // GRU has 3 gates, each with its own weights and biases
1011
+ const inputFeatures = sourceConfig.outputShape[sourceConfig.outputShape.length - 1];
1012
+ const useBias = targetConfig.useBias !== 'false' && targetConfig.useBias !== false;
1013
+
1014
+ // Formula: 3 * (input_features * units + units * units + units (bias))
1015
+ const inputParams = 3 * (inputFeatures * gruUnits);
1016
+ const recurrentParams = 3 * (gruUnits * gruUnits);
1017
+ const biasParams = useBias ? 3 * gruUnits : 0;
1018
+
1019
+ parameters = inputParams + recurrentParams + biasParams;
1020
+
1021
+ console.log(`GRU parameter calculation:
1022
+ Input features: ${inputFeatures}
1023
+ Units: ${gruUnits}
1024
+ Gates: 3 (update, reset, new)
1025
+ Input weights: ${inputParams}
1026
+ Recurrent weights: ${recurrentParams}
1027
+ Bias: ${biasParams}
1028
+ Total: ${parameters}`);
1029
+ }
1030
+ break;
1031
+
1032
  case 'conv':
1033
  if (sourceConfig.outputShape && sourceConfig.outputShape.length >= 3) {
1034
  // Very explicit type conversion - ensure all values are numbers
js/layer-editor.js CHANGED
@@ -639,19 +639,123 @@
639
  }
640
  break;
641
 
642
- case 'linear':
643
- const linearUnits = parseInt(config.units) || 1;
644
  if (!manualOutputShape) {
645
- outputShape = [linearUnits];
 
 
 
 
 
 
 
 
 
646
  }
647
- if (inputShape) {
648
- const inputSize = inputShape.reduce((a, b) => a * b, 1);
649
- const useBias = config.useBias !== 'false';
650
- parameters = inputSize * linearUnits + (useBias ? linearUnits : 0);
651
- console.log(`Linear layer params: ${inputSize} inputs × ${linearUnits} units + ${useBias ? linearUnits : 0} biases = ${parameters}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
652
  } else {
653
- console.log('No input shape available for linear layer parameter calculation');
654
- parameters = linearUnits; // Just biases if we don't know input size
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
655
  }
656
  break;
657
  }
@@ -680,8 +784,14 @@
680
  case 'input':
681
  paramsDetails = `Shape: ${(config.shape || [28, 28, 1]).join('×')}`;
682
  break;
683
- case 'linear':
684
- paramsDetails = `Units: ${config.units}<br>Use Bias: ${config.useBias !== 'false' ? 'Yes' : 'No'}`;
 
 
 
 
 
 
685
  break;
686
  }
687
 
@@ -750,7 +860,7 @@
750
 
751
  if (dimensionsDisplay && outputShape) {
752
  let dimensionsText = '';
753
- if (nodeType === 'hidden' || nodeType === 'output' || nodeType === 'linear') {
754
  dimensionsText = config.units || '';
755
  } else if (nodeType === 'conv' || nodeType === 'pool') {
756
  if (Array.isArray(outputShape)) {
 
639
  }
640
  break;
641
 
642
+ case 'rnn':
643
+ const rnnUnits = parseInt(config.units) || 32;
644
  if (!manualOutputShape) {
645
+ // Output shape depends on return_sequences
646
+ // If return_sequences is true, output is [input_sequence_length, units]
647
+ // If return_sequences is false, output is [units]
648
+ const returnSequences = config.returnSequences === 'true' || config.returnSequences === true;
649
+ if (returnSequences && inputShape && inputShape.length > 0) {
650
+ // If we have an input shape, use the first dimension as sequence length
651
+ outputShape = [inputShape[0], rnnUnits];
652
+ } else {
653
+ outputShape = [rnnUnits];
654
+ }
655
  }
656
+ if (inputShape && inputShape.length > 0) {
657
+ // For RNN, parameters = (input_features * units + units * units + units)
658
+ // Where:
659
+ // - input_features * units: weights from input to hidden
660
+ // - units * units: recurrent weights
661
+ // - units: bias terms (if using bias)
662
+
663
+ // Get input features (last dimension of input shape)
664
+ const inputFeatures = inputShape[inputShape.length - 1];
665
+ const useBias = config.useBias !== 'false' && config.useBias !== false;
666
+
667
+ const inputToHiddenParams = inputFeatures * rnnUnits;
668
+ const recurrentParams = rnnUnits * rnnUnits;
669
+ const biasParams = useBias ? rnnUnits : 0;
670
+
671
+ parameters = inputToHiddenParams + recurrentParams + biasParams;
672
+
673
+ console.log(`RNN parameters calculation:
674
+ Input features: ${inputFeatures}
675
+ RNN units: ${rnnUnits}
676
+ Input-to-hidden params: ${inputFeatures} * ${rnnUnits} = ${inputToHiddenParams}
677
+ Recurrent params: ${rnnUnits} * ${rnnUnits} = ${recurrentParams}
678
+ Bias params: ${biasParams}
679
+ Total: ${parameters}`);
680
  } else {
681
+ console.log('No input shape available for RNN parameter calculation');
682
+ parameters = rnnUnits * 2; // Just a rough estimate if input shape is unknown
683
+ }
684
+ break;
685
+
686
+ case 'lstm':
687
+ const lstmUnits = parseInt(config.units) || 64;
688
+ if (!manualOutputShape) {
689
+ // Output shape depends on return_sequences
690
+ const returnSequences = config.returnSequences === 'true' || config.returnSequences === true;
691
+ if (returnSequences && inputShape && inputShape.length > 0) {
692
+ outputShape = [inputShape[0], lstmUnits];
693
+ } else {
694
+ outputShape = [lstmUnits];
695
+ }
696
+ }
697
+ if (inputShape && inputShape.length > 0) {
698
+ // For LSTM, we have 4 gates (input, forget, cell, output)
699
+ // parameters = 4 * (input_features * units + units * units + units)
700
+
701
+ const inputFeatures = inputShape[inputShape.length - 1];
702
+ const useBias = config.useBias !== 'false' && config.useBias !== false;
703
+
704
+ const inputToHiddenParams = 4 * (inputFeatures * lstmUnits);
705
+ const recurrentParams = 4 * (lstmUnits * lstmUnits);
706
+ const biasParams = useBias ? 4 * lstmUnits : 0;
707
+
708
+ parameters = inputToHiddenParams + recurrentParams + biasParams;
709
+
710
+ console.log(`LSTM parameters calculation:
711
+ Input features: ${inputFeatures}
712
+ LSTM units: ${lstmUnits}
713
+ Gates: 4 (input, forget, cell, output)
714
+ Input-to-hidden params: 4 * (${inputFeatures} * ${lstmUnits}) = ${inputToHiddenParams}
715
+ Recurrent params: 4 * (${lstmUnits} * ${lstmUnits}) = ${recurrentParams}
716
+ Bias params: ${biasParams}
717
+ Total: ${parameters}`);
718
+ } else {
719
+ console.log('No input shape available for LSTM parameter calculation');
720
+ parameters = lstmUnits * 8; // Rough estimate
721
+ }
722
+ break;
723
+
724
+ case 'gru':
725
+ const gruUnits = parseInt(config.units) || 48;
726
+ if (!manualOutputShape) {
727
+ // Output shape depends on return_sequences
728
+ const returnSequences = config.returnSequences === 'true' || config.returnSequences === true;
729
+ if (returnSequences && inputShape && inputShape.length > 0) {
730
+ outputShape = [inputShape[0], gruUnits];
731
+ } else {
732
+ outputShape = [gruUnits];
733
+ }
734
+ }
735
+ if (inputShape && inputShape.length > 0) {
736
+ // For GRU, we have 3 gates (update, reset, new)
737
+ // parameters = 3 * (input_features * units + units * units + units)
738
+
739
+ const inputFeatures = inputShape[inputShape.length - 1];
740
+ const useBias = config.useBias !== 'false' && config.useBias !== false;
741
+
742
+ const inputToHiddenParams = 3 * (inputFeatures * gruUnits);
743
+ const recurrentParams = 3 * (gruUnits * gruUnits);
744
+ const biasParams = useBias ? 3 * gruUnits : 0;
745
+
746
+ parameters = inputToHiddenParams + recurrentParams + biasParams;
747
+
748
+ console.log(`GRU parameters calculation:
749
+ Input features: ${inputFeatures}
750
+ GRU units: ${gruUnits}
751
+ Gates: 3 (update, reset, new)
752
+ Input-to-hidden params: 3 * (${inputFeatures} * ${gruUnits}) = ${inputToHiddenParams}
753
+ Recurrent params: 3 * (${gruUnits} * ${gruUnits}) = ${recurrentParams}
754
+ Bias params: ${biasParams}
755
+ Total: ${parameters}`);
756
+ } else {
757
+ console.log('No input shape available for GRU parameter calculation');
758
+ parameters = gruUnits * 6; // Rough estimate
759
  }
760
  break;
761
  }
 
784
  case 'input':
785
  paramsDetails = `Shape: ${(config.shape || [28, 28, 1]).join('×')}`;
786
  break;
787
+ case 'rnn':
788
+ paramsDetails = `Units: ${config.units}<br>Return Sequences: ${config.returnSequences === 'true' ? 'Yes' : 'No'}`;
789
+ break;
790
+ case 'lstm':
791
+ paramsDetails = `Units: ${config.units}<br>Return Sequences: ${config.returnSequences === 'true' ? 'Yes' : 'No'}`;
792
+ break;
793
+ case 'gru':
794
+ paramsDetails = `Units: ${config.units}<br>Return Sequences: ${config.returnSequences === 'true' ? 'Yes' : 'No'}`;
795
  break;
796
  }
797
 
 
860
 
861
  if (dimensionsDisplay && outputShape) {
862
  let dimensionsText = '';
863
+ if (nodeType === 'hidden' || nodeType === 'output' || nodeType === 'rnn' || nodeType === 'lstm' || nodeType === 'gru') {
864
  dimensionsText = config.units || '';
865
  } else if (nodeType === 'conv' || nodeType === 'pool') {
866
  if (Array.isArray(outputShape)) {
js/main.js CHANGED
@@ -13,19 +13,36 @@ document.addEventListener('DOMContentLoaded', () => {
13
  document.body.appendChild(tooltip);
14
 
15
  // Initialize drag and drop functionality
16
- initializeDragAndDrop();
 
 
 
 
17
 
18
  // Network configuration (from UI controls)
19
- let networkConfig = {
20
- learningRate: 0.01,
21
  activation: 'relu',
22
  batchSize: 32,
23
- epochs: 10
 
24
  };
25
 
 
 
 
 
 
26
  // Initialize UI controls
27
  setupUIControls();
28
 
 
 
 
 
 
 
 
29
  // Layer editor modal
30
  setupLayerEditor();
31
 
@@ -97,56 +114,120 @@ document.addEventListener('DOMContentLoaded', () => {
97
 
98
  // Setup UI controls and event listeners
99
  function setupUIControls() {
 
 
100
  // Learning rate slider
101
  const learningRateSlider = document.getElementById('learning-rate');
102
  const learningRateValue = document.getElementById('learning-rate-value');
103
 
104
  if (learningRateSlider && learningRateValue) {
105
- learningRateSlider.value = networkConfig.learningRate;
106
- learningRateValue.textContent = networkConfig.learningRate.toFixed(3);
 
 
107
 
108
  learningRateSlider.addEventListener('input', (e) => {
109
- networkConfig.learningRate = parseFloat(e.target.value);
110
- learningRateValue.textContent = networkConfig.learningRate.toFixed(3);
 
 
 
 
 
 
 
 
 
111
  });
 
 
 
 
112
  }
113
 
114
  // Activation function dropdown
115
  const activationSelect = document.getElementById('activation');
116
  if (activationSelect) {
117
- activationSelect.value = networkConfig.activation;
 
 
118
 
119
  activationSelect.addEventListener('change', (e) => {
120
- networkConfig.activation = e.target.value;
121
- updateActivationFunctionGraph(networkConfig.activation);
 
 
 
 
 
 
 
 
 
 
 
122
  });
 
 
 
 
 
 
 
123
  }
124
 
125
- // Initialize activation function graph
126
- updateActivationFunctionGraph(networkConfig.activation);
127
-
128
- // Sample data event handlers
129
- const sampleItems = document.querySelectorAll('.sample-item');
130
- sampleItems.forEach(item => {
131
- item.addEventListener('click', () => {
132
- const sampleId = item.getAttribute('data-sample');
133
- handleSampleSelection(sampleId);
 
 
 
 
 
 
 
 
 
134
  });
135
- });
 
 
 
 
136
 
137
  // Button event listeners
138
  const runButton = document.getElementById('run-network');
139
  if (runButton) {
140
- runButton.addEventListener('click', runNetwork);
 
 
 
 
 
 
141
  }
142
 
143
  const clearButton = document.getElementById('clear-canvas');
144
  if (clearButton) {
145
- clearButton.addEventListener('click', clearCanvas);
 
 
 
 
 
 
146
  }
147
 
148
  // Modal handlers
149
  setupModals();
 
 
150
  }
151
 
152
  // Setup modal handlers
@@ -1244,192 +1325,296 @@ document.addEventListener('DOMContentLoaded', () => {
1244
 
1245
  // Function to run the neural network simulation
1246
  function runNetwork() {
1247
- console.log('Running neural network simulation with config:', networkConfig);
1248
 
1249
- // Get the current network architecture
1250
- const networkLayers = window.dragDrop.getNetworkArchitecture();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1251
 
1252
  // Check if we have a valid network
1253
  if (networkLayers.layers.length === 0) {
1254
- alert('Please add some nodes to the network first!');
1255
- return;
 
 
 
 
 
 
1256
  }
1257
 
1258
- // Validate the network
1259
- const validationResult = window.neuralNetwork.validateNetwork(
1260
- networkLayers.layers,
1261
- networkLayers.connections
1262
- );
1263
 
1264
- if (!validationResult.valid) {
1265
- alert('Network is not valid: ' + validationResult.errors.join('\n'));
1266
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1267
  }
1268
 
1269
  // Add animation class to all nodes
1270
- document.querySelectorAll('.canvas-node').forEach(node => {
 
1271
  node.classList.add('highlight-pulse');
 
 
 
 
 
1272
  });
1273
 
1274
  // Animate connections to show data flow
1275
- document.querySelectorAll('.connection').forEach((connection, index) => {
 
1276
  setTimeout(() => {
1277
- connection.style.background = 'linear-gradient(90deg, var(--primary-color), var(--accent-color))';
 
1278
 
1279
- // Reset after animation
1280
  setTimeout(() => {
1281
- connection.style.background = '';
1282
- }, 800);
1283
- }, 300 * index);
1284
  });
1285
 
1286
- // Simulate training
1287
- simulateTraining();
1288
 
1289
- // Reset animations after completion
1290
- setTimeout(() => {
1291
- document.querySelectorAll('.canvas-node').forEach(node => {
1292
- node.classList.remove('highlight-pulse');
1293
- });
1294
- }, 3000);
1295
  }
1296
 
1297
- // Simulate training progress
1298
- function simulateTraining() {
1299
  const progressBar = document.querySelector('.progress-bar');
1300
  const lossValue = document.getElementById('loss-value');
1301
  const accuracyValue = document.getElementById('accuracy-value');
1302
 
1303
- if (!progressBar || !lossValue || !accuracyValue) return;
1304
-
1305
- // Reset progress
1306
- progressBar.style.width = '0%';
1307
- lossValue.textContent = '2.3021';
1308
- accuracyValue.textContent = '0.12';
1309
-
1310
- // Simulate progress over time
1311
- let progress = 0;
1312
- let loss = 2.3021;
1313
- let accuracy = 0.12;
1314
-
1315
- const interval = setInterval(() => {
1316
- progress += 10;
1317
- loss *= 0.85; // Decrease loss over time
1318
- accuracy = Math.min(0.99, accuracy * 1.2); // Increase accuracy over time
1319
 
1320
- progressBar.style.width = `${progress}%`;
1321
- lossValue.textContent = loss.toFixed(4);
1322
- accuracyValue.textContent = accuracy.toFixed(2);
 
1323
 
1324
- if (progress >= 100) {
1325
- clearInterval(interval);
1326
- }
1327
- }, 300);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1328
  }
1329
 
1330
  // Function to clear all nodes from the canvas
1331
  function clearCanvas() {
1332
- if (window.dragDrop && typeof window.dragDrop.clearAllNodes === 'function') {
1333
- window.dragDrop.clearAllNodes();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1334
  }
1335
-
1336
- // Reset progress indicators
1337
- const progressBar = document.querySelector('.progress-bar');
1338
- const lossValue = document.getElementById('loss-value');
1339
- const accuracyValue = document.getElementById('accuracy-value');
1340
-
1341
- if (progressBar) progressBar.style.width = '0%';
1342
- if (lossValue) lossValue.textContent = '-';
1343
- if (accuracyValue) accuracyValue.textContent = '-';
1344
  }
1345
 
1346
  // Update activation function graph
1347
  function updateActivationFunctionGraph(activationType) {
1348
- const activationGraph = document.querySelector('.activation-function');
1349
  if (!activationGraph) return;
1350
 
1351
- // Clear previous graph
1352
- let canvas = activationGraph.querySelector('canvas');
1353
- if (!canvas) {
1354
- canvas = document.createElement('canvas');
1355
- canvas.width = 200;
1356
- canvas.height = 100;
1357
- activationGraph.appendChild(canvas);
1358
- }
1359
-
1360
- const ctx = canvas.getContext('2d');
1361
 
1362
- // Clear canvas
1363
- ctx.clearRect(0, 0, canvas.width, canvas.height);
 
 
1364
 
1365
- // Set background
1366
- ctx.fillStyle = '#f8f9fa';
1367
- ctx.fillRect(0, 0, canvas.width, canvas.height);
 
 
1368
 
1369
  // Draw axes
1370
- ctx.strokeStyle = '#ccc';
1371
- ctx.lineWidth = 1;
1372
- ctx.beginPath();
1373
- ctx.moveTo(0, canvas.height / 2);
1374
- ctx.lineTo(canvas.width, canvas.height / 2);
1375
- ctx.moveTo(canvas.width / 2, 0);
1376
- ctx.lineTo(canvas.width / 2, canvas.height);
1377
- ctx.stroke();
1378
-
1379
- // Draw function
1380
- ctx.strokeStyle = 'var(--primary-color)';
1381
- ctx.lineWidth = 2;
1382
- ctx.beginPath();
 
 
 
 
 
 
 
 
 
1383
 
1384
  switch(activationType) {
1385
  case 'relu':
1386
- ctx.moveTo(0, canvas.height / 2);
1387
- ctx.lineTo(canvas.width / 2, canvas.height / 2);
1388
- ctx.lineTo(canvas.width, 0);
1389
  break;
1390
 
1391
  case 'sigmoid':
1392
- for (let x = 0; x < canvas.width; x++) {
1393
- const normalizedX = (x / canvas.width - 0.5) * 10;
1394
- const sigmoidY = 1 / (1 + Math.exp(-normalizedX));
1395
- const y = canvas.height - sigmoidY * canvas.height;
1396
- if (x === 0) ctx.moveTo(x, y);
1397
- else ctx.lineTo(x, y);
1398
- }
1399
  break;
1400
 
1401
  case 'tanh':
1402
- for (let x = 0; x < canvas.width; x++) {
1403
- const normalizedX = (x / canvas.width - 0.5) * 6;
1404
- const tanhY = Math.tanh(normalizedX);
1405
- const y = canvas.height / 2 - tanhY * canvas.height / 2;
1406
- if (x === 0) ctx.moveTo(x, y);
1407
- else ctx.lineTo(x, y);
1408
- }
1409
- break;
1410
-
1411
- case 'softmax':
1412
- // Just a representative curve for softmax
1413
- ctx.moveTo(0, canvas.height * 0.8);
1414
- ctx.bezierCurveTo(
1415
- canvas.width * 0.3, canvas.height * 0.7,
1416
- canvas.width * 0.6, canvas.height * 0.3,
1417
- canvas.width, canvas.height * 0.2
1418
- );
1419
  break;
1420
 
1421
  default: // Linear
1422
- ctx.moveTo(0, canvas.height * 0.8);
1423
- ctx.lineTo(canvas.width, canvas.height * 0.2);
1424
  }
1425
 
1426
- ctx.stroke();
 
1427
 
1428
  // Add label
1429
- ctx.fillStyle = 'var(--text-color)';
1430
- ctx.font = '12px Arial';
1431
- ctx.textAlign = 'center';
1432
- ctx.fillText(activationType, canvas.width / 2, canvas.height - 10);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1433
  }
1434
 
1435
  // Setup node hover effects for tooltips
 
13
  document.body.appendChild(tooltip);
14
 
15
  // Initialize drag and drop functionality
16
+ if (typeof initializeDragAndDrop === 'function') {
17
+ initializeDragAndDrop();
18
+ } else {
19
+ console.warn('initializeDragAndDrop function not found');
20
+ }
21
 
22
  // Network configuration (from UI controls)
23
+ window.networkConfig = {
24
+ learningRate: 0.1,
25
  activation: 'relu',
26
  batchSize: 32,
27
+ epochs: 10,
28
+ optimizer: 'sgd'
29
  };
30
 
31
+ // Make sure window.networkConfig is available globally for other scripts
32
+ if (!window.networkConfig) {
33
+ window.networkConfig = networkConfig;
34
+ }
35
+
36
  // Initialize UI controls
37
  setupUIControls();
38
 
39
+ // Force activation function graph update
40
+ setTimeout(() => {
41
+ const activationType = document.getElementById('activation')?.value || 'relu';
42
+ console.log('Ensuring activation function graph is rendered:', activationType);
43
+ updateActivationFunctionGraph(activationType);
44
+ }, 200);
45
+
46
  // Layer editor modal
47
  setupLayerEditor();
48
 
 
114
 
115
  // Setup UI controls and event listeners
116
  function setupUIControls() {
117
+ console.log('Setting up UI controls...');
118
+
119
  // Learning rate slider
120
  const learningRateSlider = document.getElementById('learning-rate');
121
  const learningRateValue = document.getElementById('learning-rate-value');
122
 
123
  if (learningRateSlider && learningRateValue) {
124
+ // Set initial value - default to 0.1 if not set in networkConfig
125
+ window.networkConfig.learningRate = window.networkConfig.learningRate || 0.1;
126
+ learningRateSlider.value = window.networkConfig.learningRate;
127
+ learningRateValue.textContent = window.networkConfig.learningRate.toFixed(3);
128
 
129
  learningRateSlider.addEventListener('input', (e) => {
130
+ window.networkConfig.learningRate = parseFloat(e.target.value);
131
+ learningRateValue.textContent = window.networkConfig.learningRate.toFixed(3);
132
+ console.log(`Learning rate updated: ${window.networkConfig.learningRate}`);
133
+
134
+ // Trigger network configuration update event
135
+ document.dispatchEvent(new CustomEvent('networkConfigUpdated', {
136
+ detail: {
137
+ type: 'learningRate',
138
+ value: window.networkConfig.learningRate
139
+ }
140
+ }));
141
  });
142
+
143
+ console.log('Learning rate slider initialized with value:', window.networkConfig.learningRate);
144
+ } else {
145
+ console.warn('Learning rate controls not found in the DOM');
146
  }
147
 
148
  // Activation function dropdown
149
  const activationSelect = document.getElementById('activation');
150
  if (activationSelect) {
151
+ // Set initial value - default to 'relu' if not set in networkConfig
152
+ window.networkConfig.activation = window.networkConfig.activation || 'relu';
153
+ activationSelect.value = window.networkConfig.activation;
154
 
155
  activationSelect.addEventListener('change', (e) => {
156
+ window.networkConfig.activation = e.target.value;
157
+ console.log(`Activation function updated: ${window.networkConfig.activation}`);
158
+
159
+ // Update activation function graph
160
+ updateActivationFunctionGraph(window.networkConfig.activation);
161
+
162
+ // Trigger network configuration update event
163
+ document.dispatchEvent(new CustomEvent('networkConfigUpdated', {
164
+ detail: {
165
+ type: 'activation',
166
+ value: window.networkConfig.activation
167
+ }
168
+ }));
169
  });
170
+
171
+ console.log('Activation select initialized with value:', window.networkConfig.activation);
172
+
173
+ // Initialize activation function graph with current value
174
+ updateActivationFunctionGraph(window.networkConfig.activation);
175
+ } else {
176
+ console.warn('Activation select not found in the DOM');
177
  }
178
 
179
+ // Optimizer dropdown
180
+ const optimizerSelect = document.getElementById('optimizer');
181
+ if (optimizerSelect) {
182
+ // Set initial value - default to 'sgd' if not set in networkConfig
183
+ window.networkConfig.optimizer = window.networkConfig.optimizer || 'sgd';
184
+ optimizerSelect.value = window.networkConfig.optimizer;
185
+
186
+ optimizerSelect.addEventListener('change', (e) => {
187
+ window.networkConfig.optimizer = e.target.value;
188
+ console.log(`Optimizer updated: ${window.networkConfig.optimizer}`);
189
+
190
+ // Trigger network configuration update event
191
+ document.dispatchEvent(new CustomEvent('networkConfigUpdated', {
192
+ detail: {
193
+ type: 'optimizer',
194
+ value: window.networkConfig.optimizer
195
+ }
196
+ }));
197
  });
198
+
199
+ console.log('Optimizer select initialized with value:', window.networkConfig.optimizer);
200
+ } else {
201
+ console.warn('Optimizer select not found in the DOM');
202
+ }
203
 
204
  // Button event listeners
205
  const runButton = document.getElementById('run-network');
206
  if (runButton) {
207
+ runButton.addEventListener('click', () => {
208
+ console.log('Run network button clicked');
209
+ runNetwork();
210
+ });
211
+ console.log('Run network button initialized');
212
+ } else {
213
+ console.warn('Run network button not found in the DOM');
214
  }
215
 
216
  const clearButton = document.getElementById('clear-canvas');
217
  if (clearButton) {
218
+ clearButton.addEventListener('click', () => {
219
+ console.log('Clear canvas button clicked');
220
+ clearCanvas();
221
+ });
222
+ console.log('Clear canvas button initialized');
223
+ } else {
224
+ console.warn('Clear canvas button not found in the DOM');
225
  }
226
 
227
  // Modal handlers
228
  setupModals();
229
+
230
+ console.log('UI controls setup complete');
231
  }
232
 
233
  // Setup modal handlers
 
1325
 
1326
  // Function to run the neural network simulation
1327
  function runNetwork() {
1328
+ console.log('Running neural network simulation with config:', window.networkConfig);
1329
 
1330
+ // Get the current network architecture if possible
1331
+ let networkLayers = { layers: [], connections: [] };
1332
+
1333
+ if (window.dragDrop && typeof window.dragDrop.getNetworkArchitecture === 'function') {
1334
+ try {
1335
+ networkLayers = window.dragDrop.getNetworkArchitecture();
1336
+ console.log('Network architecture retrieved:', networkLayers);
1337
+ } catch (error) {
1338
+ console.error('Error getting network architecture:', error);
1339
+ }
1340
+ } else {
1341
+ console.warn('dragDrop.getNetworkArchitecture is not available, using fallback');
1342
+
1343
+ // Fallback: Get nodes and connections manually
1344
+ const canvas = document.getElementById('network-canvas');
1345
+ if (canvas) {
1346
+ const nodes = canvas.querySelectorAll('.canvas-node');
1347
+ const connections = canvas.querySelectorAll('.connection');
1348
+
1349
+ if (nodes.length === 0) {
1350
+ alert('Please add some nodes to the network first!');
1351
+ return;
1352
+ }
1353
+
1354
+ // Just animate what's visible on the canvas
1355
+ console.log(`Found ${nodes.length} nodes and ${connections.length} connections on canvas`);
1356
+ }
1357
+ }
1358
 
1359
  // Check if we have a valid network
1360
  if (networkLayers.layers.length === 0) {
1361
+ // Check for nodes on the canvas directly
1362
+ const canvas = document.getElementById('network-canvas');
1363
+ const nodes = canvas ? canvas.querySelectorAll('.canvas-node') : [];
1364
+
1365
+ if (nodes.length === 0) {
1366
+ alert('Please add some nodes to the network first!');
1367
+ return;
1368
+ }
1369
  }
1370
 
1371
+ // Validate the network if possible
1372
+ let validationResult = { valid: true, errors: [] };
 
 
 
1373
 
1374
+ if (window.neuralNetwork && typeof window.neuralNetwork.validateNetwork === 'function') {
1375
+ try {
1376
+ validationResult = window.neuralNetwork.validateNetwork(
1377
+ networkLayers.layers,
1378
+ networkLayers.connections
1379
+ );
1380
+
1381
+ if (!validationResult.valid) {
1382
+ alert('Network is not valid: ' + validationResult.errors.join('\n'));
1383
+ return;
1384
+ }
1385
+ } catch (error) {
1386
+ console.error('Error validating network:', error);
1387
+ // Continue anyway since we'll just animate
1388
+ }
1389
+ } else {
1390
+ console.warn('neuralNetwork.validateNetwork is not available, skipping validation');
1391
  }
1392
 
1393
  // Add animation class to all nodes
1394
+ const nodes = document.querySelectorAll('.canvas-node');
1395
+ nodes.forEach(node => {
1396
  node.classList.add('highlight-pulse');
1397
+
1398
+ // Add a delay to remove the animation class
1399
+ setTimeout(() => {
1400
+ node.classList.remove('highlight-pulse');
1401
+ }, 1500);
1402
  });
1403
 
1404
  // Animate connections to show data flow
1405
+ document.querySelectorAll('.connection').forEach((conn, index) => {
1406
+ // Apply sequential animation to show data flow direction
1407
  setTimeout(() => {
1408
+ conn.style.transition = 'box-shadow 0.3s ease-in-out';
1409
+ conn.style.boxShadow = '0 0 15px rgba(52, 152, 219, 0.8)';
1410
 
1411
+ // Add a delay to remove the highlight
1412
  setTimeout(() => {
1413
+ conn.style.boxShadow = '0 0 8px rgba(52, 152, 219, 0.5)';
1414
+ }, 600);
1415
+ }, index * 150); // Stagger the animations
1416
  });
1417
 
1418
+ // Update training progress visualization
1419
+ simulateTrainingProgress();
1420
 
1421
+ console.log('Network animation complete');
 
 
 
 
 
1422
  }
1423
 
1424
+ // Simulate training progress for visualization
1425
+ function simulateTrainingProgress() {
1426
  const progressBar = document.querySelector('.progress-bar');
1427
  const lossValue = document.getElementById('loss-value');
1428
  const accuracyValue = document.getElementById('accuracy-value');
1429
 
1430
+ if (progressBar && lossValue && accuracyValue) {
1431
+ // Reset progress bar
1432
+ progressBar.style.width = '0%';
1433
+ lossValue.textContent = '1.0000';
1434
+ accuracyValue.textContent = '0%';
 
 
 
 
 
 
 
 
 
 
 
1435
 
1436
+ // Simulate training progress with animation
1437
+ let progress = 0;
1438
+ let loss = 1.0;
1439
+ let accuracy = 0.0;
1440
 
1441
+ const interval = setInterval(() => {
1442
+ progress += 2;
1443
+ loss = Math.max(0.05, loss * 0.95);
1444
+ accuracy = Math.min(99, accuracy + 2);
1445
+
1446
+ progressBar.style.width = `${progress}%`;
1447
+ lossValue.textContent = loss.toFixed(4);
1448
+ accuracyValue.textContent = `${accuracy.toFixed(1)}%`;
1449
+
1450
+ if (progress >= 100) {
1451
+ clearInterval(interval);
1452
+
1453
+ // Final values
1454
+ lossValue.textContent = '0.0342';
1455
+ accuracyValue.textContent = '98.7%';
1456
+
1457
+ console.log('Training simulation complete');
1458
+ }
1459
+ }, 50);
1460
+ }
1461
  }
1462
 
1463
  // Function to clear all nodes from the canvas
1464
  function clearCanvas() {
1465
+ // Show confirmation dialog
1466
+ if (confirm('Are you sure you want to clear the canvas? This will remove all nodes and connections.')) {
1467
+ // Use the drag-drop module's clear function if available
1468
+ if (window.dragDrop && typeof window.dragDrop.clearAllNodes === 'function') {
1469
+ window.dragDrop.clearAllNodes();
1470
+ } else {
1471
+ // Fallback: manually remove all canvas nodes
1472
+ const canvas = document.getElementById('network-canvas');
1473
+ const nodes = canvas.querySelectorAll('.canvas-node');
1474
+ const connections = canvas.querySelectorAll('.connection');
1475
+
1476
+ // Remove all connections
1477
+ connections.forEach(conn => conn.remove());
1478
+
1479
+ // Remove all nodes
1480
+ nodes.forEach(node => node.remove());
1481
+
1482
+ // Add canvas hint
1483
+ if (canvas.querySelector('.canvas-hint') === null) {
1484
+ const hint = document.createElement('div');
1485
+ hint.className = 'canvas-hint';
1486
+ hint.innerHTML = `
1487
+ <strong>Build Your Neural Network</strong>
1488
+ Drag components from the left panel and drop them here.
1489
+ <br>Connect them by dragging from output (right) to input (left) ports.
1490
+ `;
1491
+ canvas.appendChild(hint);
1492
+ }
1493
+
1494
+ console.log('Canvas cleared manually');
1495
+ }
1496
+
1497
+ // Reset progress indicators
1498
+ const progressBar = document.querySelector('.progress-bar');
1499
+ const lossValue = document.getElementById('loss-value');
1500
+ const accuracyValue = document.getElementById('accuracy-value');
1501
+
1502
+ if (progressBar) progressBar.style.width = '0%';
1503
+ if (lossValue) lossValue.textContent = '-';
1504
+ if (accuracyValue) accuracyValue.textContent = '-';
1505
+
1506
+ console.log('Canvas cleared and progress indicators reset');
1507
  }
 
 
 
 
 
 
 
 
 
1508
  }
1509
 
1510
  // Update activation function graph
1511
  function updateActivationFunctionGraph(activationType) {
1512
+ const activationGraph = document.querySelector('.activation-graph');
1513
  if (!activationGraph) return;
1514
 
1515
+ // Get SVG element
1516
+ const svg = activationGraph.querySelector('.activation-curve');
1517
+ if (!svg) return;
 
 
 
 
 
 
 
1518
 
1519
+ // Clear previous paths
1520
+ while (svg.firstChild) {
1521
+ svg.removeChild(svg.firstChild);
1522
+ }
1523
 
1524
+ // Create path for the activation function
1525
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
1526
+ path.setAttribute('stroke', '#3498db');
1527
+ path.setAttribute('stroke-width', '2');
1528
+ path.setAttribute('fill', 'none');
1529
 
1530
  // Draw axes
1531
+ const xAxis = document.createElementNS('http://www.w3.org/2000/svg', 'line');
1532
+ xAxis.setAttribute('x1', '0');
1533
+ xAxis.setAttribute('y1', '50');
1534
+ xAxis.setAttribute('x2', '100');
1535
+ xAxis.setAttribute('y2', '50');
1536
+ xAxis.setAttribute('stroke', '#ccc');
1537
+ xAxis.setAttribute('stroke-width', '1');
1538
+
1539
+ const yAxis = document.createElementNS('http://www.w3.org/2000/svg', 'line');
1540
+ yAxis.setAttribute('x1', '50');
1541
+ yAxis.setAttribute('y1', '0');
1542
+ yAxis.setAttribute('x2', '50');
1543
+ yAxis.setAttribute('y2', '100');
1544
+ yAxis.setAttribute('stroke', '#ccc');
1545
+ yAxis.setAttribute('stroke-width', '1');
1546
+
1547
+ // Add axes to SVG
1548
+ svg.appendChild(xAxis);
1549
+ svg.appendChild(yAxis);
1550
+
1551
+ // Calculate path based on activation type
1552
+ let pathData = '';
1553
 
1554
  switch(activationType) {
1555
  case 'relu':
1556
+ pathData = 'M0,50 L50,50 L100,0';
 
 
1557
  break;
1558
 
1559
  case 'sigmoid':
1560
+ pathData = generateSigmoidPath();
 
 
 
 
 
 
1561
  break;
1562
 
1563
  case 'tanh':
1564
+ pathData = generateTanhPath();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1565
  break;
1566
 
1567
  default: // Linear
1568
+ pathData = 'M0,80 L100,20';
 
1569
  }
1570
 
1571
+ path.setAttribute('d', pathData);
1572
+ svg.appendChild(path);
1573
 
1574
  // Add label
1575
+ const label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
1576
+ label.setAttribute('x', '50');
1577
+ label.setAttribute('y', '95');
1578
+ label.setAttribute('text-anchor', 'middle');
1579
+ label.setAttribute('font-size', '10');
1580
+ label.setAttribute('fill', '#333');
1581
+ label.textContent = activationType.charAt(0).toUpperCase() + activationType.slice(1);
1582
+
1583
+ svg.appendChild(label);
1584
+
1585
+ console.log(`Activation function graph updated: ${activationType}`);
1586
+ }
1587
+
1588
+ // Generate path data for sigmoid function
1589
+ function generateSigmoidPath() {
1590
+ let pathData = '';
1591
+
1592
+ for (let x = 0; x <= 100; x += 2) {
1593
+ const normalizedX = (x / 100 - 0.5) * 10;
1594
+ const sigmoidY = 1 / (1 + Math.exp(-normalizedX));
1595
+ const y = 100 - sigmoidY * 100;
1596
+
1597
+ if (x === 0) pathData += `M${x},${y}`;
1598
+ else pathData += ` L${x},${y}`;
1599
+ }
1600
+
1601
+ return pathData;
1602
+ }
1603
+
1604
+ // Generate path data for tanh function
1605
+ function generateTanhPath() {
1606
+ let pathData = '';
1607
+
1608
+ for (let x = 0; x <= 100; x += 2) {
1609
+ const normalizedX = (x / 100 - 0.5) * 6;
1610
+ const tanhY = Math.tanh(normalizedX);
1611
+ const y = 50 - tanhY * 50;
1612
+
1613
+ if (x === 0) pathData += `M${x},${y}`;
1614
+ else pathData += ` L${x},${y}`;
1615
+ }
1616
+
1617
+ return pathData;
1618
  }
1619
 
1620
  // Setup node hover effects for tooltips