Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Dropout Neural Network Visualization</title> | |
| <style> | |
| body { | |
| font-family: 'Arial', sans-serif; | |
| margin: 0; | |
| padding: 20px; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| color: white; | |
| } | |
| .container { | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| background: rgba(255, 255, 255, 0.1); | |
| backdrop-filter: blur(10px); | |
| border-radius: 20px; | |
| padding: 30px; | |
| box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37); | |
| } | |
| h1 { | |
| text-align: center; | |
| margin-bottom: 30px; | |
| font-size: 2.5em; | |
| text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); | |
| } | |
| .controls { | |
| display: flex; | |
| justify-content: center; | |
| gap: 20px; | |
| margin-bottom: 30px; | |
| flex-wrap: wrap; | |
| } | |
| .control-group { | |
| background: rgba(255, 255, 255, 0.2); | |
| padding: 15px; | |
| border-radius: 10px; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| label { | |
| font-weight: bold; | |
| font-size: 14px; | |
| } | |
| input[type="range"] { | |
| width: 120px; | |
| } | |
| button { | |
| background: linear-gradient(45deg, #ff6b6b, #ee5a24); | |
| color: white; | |
| border: none; | |
| padding: 12px 24px; | |
| border-radius: 25px; | |
| cursor: pointer; | |
| font-weight: bold; | |
| font-size: 16px; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 4px 15px rgba(238, 90, 36, 0.3); | |
| } | |
| button:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 6px 20px rgba(238, 90, 36, 0.4); | |
| } | |
| button:disabled { | |
| background: #666; | |
| cursor: not-allowed; | |
| transform: none; | |
| box-shadow: none; | |
| } | |
| .visualization { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: flex-start; | |
| gap: 30px; | |
| } | |
| .network-container { | |
| flex: 2; | |
| background: rgba(0, 0, 0, 0.3); | |
| border-radius: 15px; | |
| padding: 20px; | |
| position: relative; | |
| } | |
| .loss-chart { | |
| margin-top: 20px; | |
| background: rgba(255, 255, 255, 0.1); | |
| border-radius: 10px; | |
| padding: 15px; | |
| height: 250px; | |
| } | |
| .chart-title { | |
| text-align: center; | |
| margin-bottom: 15px; | |
| font-weight: bold; | |
| color: white; | |
| } | |
| .info-panel { | |
| flex: 1; | |
| background: rgba(255, 255, 255, 0.2); | |
| border-radius: 15px; | |
| padding: 20px; | |
| height: fit-content; | |
| } | |
| .epoch-info { | |
| text-align: center; | |
| margin-bottom: 20px; | |
| font-size: 18px; | |
| font-weight: bold; | |
| } | |
| .stats { | |
| margin-bottom: 20px; | |
| } | |
| .stat-item { | |
| display: flex; | |
| justify-content: space-between; | |
| margin-bottom: 10px; | |
| padding: 8px; | |
| background: rgba(255, 255, 255, 0.1); | |
| border-radius: 5px; | |
| } | |
| .legend { | |
| margin-top: 20px; | |
| } | |
| .legend-item { | |
| display: flex; | |
| align-items: center; | |
| margin-bottom: 10px; | |
| } | |
| .legend-color { | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 50%; | |
| margin-right: 10px; | |
| } | |
| .progress-bar { | |
| width: 100%; | |
| height: 20px; | |
| background: rgba(255, 255, 255, 0.2); | |
| border-radius: 10px; | |
| overflow: hidden; | |
| margin-top: 10px; | |
| } | |
| .progress-fill { | |
| height: 100%; | |
| background: linear-gradient(90deg, #00d2ff, #3a7bd5); | |
| width: 0%; | |
| transition: width 0.3s ease; | |
| } | |
| #networkSvg { | |
| width: 100%; | |
| height: 500px; | |
| background: rgba(255, 255, 255, 0.05); | |
| border-radius: 10px; | |
| } | |
| .mode-toggle { | |
| text-align: center; | |
| margin-bottom: 20px; | |
| } | |
| .mode-toggle button { | |
| margin: 0 10px; | |
| padding: 8px 16px; | |
| font-size: 14px; | |
| } | |
| .mode-toggle button.active { | |
| background: linear-gradient(45deg, #3a7bd5, #00d2ff); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>🧠 Dropout Neural Network Visualization</h1> | |
| <div class="controls"> | |
| <div class="control-group"> | |
| <label for="dropoutRate">Dropout Rate</label> | |
| <input type="range" id="dropoutRate" min="0" max="0.8" step="0.1" value="0.5"> | |
| <span id="dropoutValue">0.5</span> | |
| </div> | |
| <div class="control-group"> | |
| <label for="learningRate">Learning Rate</label> | |
| <input type="range" id="learningRate" min="0.01" max="0.5" step="0.01" value="0.1"> | |
| <span id="learningValue">0.1</span> | |
| </div> | |
| <div class="control-group"> | |
| <label for="epochs">Epochs</label> | |
| <input type="range" id="epochs" min="10" max="200" step="10" value="50"> | |
| <span id="epochsValue">50</span> | |
| </div> | |
| </div> | |
| <div class="mode-toggle"> | |
| <button id="trainMode" class="active">Training Mode</button> | |
| <button id="testMode">Testing Mode</button> | |
| </div> | |
| <div class="controls"> | |
| <button id="startBtn">🚀 Start Training</button> | |
| <button id="stopBtn" disabled>⏹️ Stop</button> | |
| <button id="resetBtn">🔄 Reset</button> | |
| </div> | |
| <div class="visualization"> | |
| <div class="network-container"> | |
| <svg id="networkSvg"></svg> | |
| <div class="loss-chart"> | |
| <div class="chart-title">📊 Training & Validation Loss</div> | |
| <canvas id="lossChart" width="550" height="180"></canvas> | |
| </div> | |
| </div> | |
| <div class="info-panel"> | |
| <div class="epoch-info"> | |
| <div>Epoch: <span id="currentEpoch">0</span> / <span id="totalEpochs">50</span></div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" id="progressFill"></div> | |
| </div> | |
| </div> | |
| <div class="stats"> | |
| <div class="stat-item"> | |
| <span>Mode:</span> | |
| <span id="currentMode">Training</span> | |
| </div> | |
| <div class="stat-item"> | |
| <span>Active Neurons:</span> | |
| <span id="activeNeurons">12/12</span> | |
| </div> | |
| <div class="stat-item"> | |
| <span>Dropped Neurons:</span> | |
| <span id="droppedNeurons">0/12</span> | |
| </div> | |
| <div class="stat-item"> | |
| <span>Train Loss:</span> | |
| <span id="trainLoss">1.000</span> | |
| </div> | |
| <div class="stat-item"> | |
| <span>Val Loss:</span> | |
| <span id="valLoss">1.000</span> | |
| </div> | |
| <div class="stat-item"> | |
| <span>Loss:</span> | |
| <span id="currentLoss">1.000</span> | |
| </div> | |
| <div class="stat-item"> | |
| <span>Accuracy:</span> | |
| <span id="currentAccuracy">50%</span> | |
| </div> | |
| </div> | |
| <div class="legend"> | |
| <h3>Legend:</h3> | |
| <div class="legend-item"> | |
| <div class="legend-color" style="background: #4CAF50;"></div> | |
| <span>Active Neuron</span> | |
| </div> | |
| <div class="legend-item"> | |
| <div class="legend-color" style="background: #f44336; opacity: 0.3;"></div> | |
| <span>Dropped Neuron</span> | |
| </div> | |
| <div class="legend-item"> | |
| <div class="legend-color" style="background: #2196F3;"></div> | |
| <span>Input Layer</span> | |
| </div> | |
| <div class="legend-item"> | |
| <div class="legend-color" style="background: #FF9800;"></div> | |
| <span>Output Layer</span> | |
| </div> | |
| </div> | |
| <div style="margin-top: 20px; font-size: 14px; line-height: 1.4;"> | |
| <strong>How Dropout Works:</strong><br> | |
| • During training, neurons are randomly "turned off"<br> | |
| • Prevents over-reliance on specific neurons<br> | |
| • Reduces overfitting and improves generalization<br> | |
| • During testing, all neurons are active | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| class DropoutNeuralNetwork { | |
| constructor() { | |
| this.svg = document.getElementById('networkSvg'); | |
| this.lossCanvas = document.getElementById('lossChart'); | |
| this.lossCtx = this.lossCanvas.getContext('2d'); | |
| this.layers = [3, 4, 4, 2]; // Input, Hidden1, Hidden2, Output | |
| this.neurons = []; | |
| this.connections = []; | |
| this.isTraining = false; | |
| this.currentEpoch = 0; | |
| this.totalEpochs = 50; | |
| this.mode = 'training'; // 'training' or 'testing' | |
| this.trainLoss = 1.0; | |
| this.valLoss = 1.0; | |
| this.accuracy = 0.5; | |
| // Loss history for plotting | |
| this.trainLossHistory = []; | |
| this.valLossHistory = []; | |
| this.initializeNetwork(); | |
| this.setupEventListeners(); | |
| this.updateDisplay(); | |
| this.initializeLossChart(); | |
| } | |
| initializeNetwork() { | |
| const svgRect = this.svg.getBoundingClientRect(); | |
| const width = 600; | |
| const height = 500; | |
| this.svg.setAttribute('viewBox', `0 0 ${width} ${height}`); | |
| // Clear existing content | |
| this.svg.innerHTML = ''; | |
| this.neurons = []; | |
| this.connections = []; | |
| // Create neurons | |
| var layerSpacing = width / (this.layers.length + 1); | |
| for (var layerIdx = 0; layerIdx < this.layers.length; layerIdx++) { | |
| var layerSize = this.layers[layerIdx]; | |
| var neuronSpacing = height / (layerSize + 1); | |
| for (var neuronIdx = 0; neuronIdx < layerSize; neuronIdx++) { | |
| var x = layerSpacing * (layerIdx + 1); | |
| var y = neuronSpacing * (neuronIdx + 1); | |
| var neuron = { | |
| id: 'neuron_' + layerIdx + '_' + neuronIdx, | |
| layer: layerIdx, | |
| index: neuronIdx, | |
| x: x, | |
| y: y, | |
| active: true, | |
| element: null | |
| }; | |
| this.neurons.push(neuron); | |
| } | |
| } | |
| // Create connections | |
| for (var layerIdx2 = 0; layerIdx2 < this.layers.length - 1; layerIdx2++) { | |
| var currentLayerNeurons = this.neurons.filter(function(n) { return n.layer === layerIdx2; }); | |
| var nextLayerNeurons = this.neurons.filter(function(n) { return n.layer === layerIdx2 + 1; }); | |
| for (var i = 0; i < currentLayerNeurons.length; i++) { | |
| var currentNeuron = currentLayerNeurons[i]; | |
| for (var j = 0; j < nextLayerNeurons.length; j++) { | |
| var nextNeuron = nextLayerNeurons[j]; | |
| var connection = { | |
| id: 'conn_' + currentNeuron.id + '_' + nextNeuron.id, | |
| from: currentNeuron, | |
| to: nextNeuron, | |
| weight: Math.random() * 2 - 1, | |
| element: null | |
| }; | |
| this.connections.push(connection); | |
| } | |
| } | |
| } | |
| this.renderNetwork(); | |
| } | |
| renderNetwork() { | |
| // Render connections first (so they appear behind neurons) | |
| for (let conn of this.connections) { | |
| const line = document.createElementNS('http://www.w3.org/2000/svg', 'line'); | |
| line.setAttribute('x1', conn.from.x); | |
| line.setAttribute('y1', conn.from.y); | |
| line.setAttribute('x2', conn.to.x); | |
| line.setAttribute('y2', conn.to.y); | |
| line.setAttribute('stroke', this.getConnectionColor(conn)); | |
| line.setAttribute('stroke-width', Math.abs(conn.weight) * 2 + 0.5); | |
| line.setAttribute('opacity', this.getConnectionOpacity(conn)); | |
| line.setAttribute('id', conn.id); | |
| this.svg.appendChild(line); | |
| conn.element = line; | |
| } | |
| // Render neurons | |
| for (let neuron of this.neurons) { | |
| const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); | |
| circle.setAttribute('cx', neuron.x); | |
| circle.setAttribute('cy', neuron.y); | |
| circle.setAttribute('r', 15); | |
| circle.setAttribute('fill', this.getNeuronColor(neuron)); | |
| circle.setAttribute('stroke', '#fff'); | |
| circle.setAttribute('stroke-width', 2); | |
| circle.setAttribute('opacity', neuron.active ? 1 : 0.3); | |
| circle.setAttribute('id', neuron.id); | |
| // Add pulsing animation for active neurons | |
| if (neuron.active && this.isTraining) { | |
| const animate = document.createElementNS('http://www.w3.org/2000/svg', 'animate'); | |
| animate.setAttribute('attributeName', 'r'); | |
| animate.setAttribute('values', '15;18;15'); | |
| animate.setAttribute('dur', '2s'); | |
| animate.setAttribute('repeatCount', 'indefinite'); | |
| circle.appendChild(animate); | |
| } | |
| this.svg.appendChild(circle); | |
| neuron.element = circle; | |
| // Add layer labels | |
| if (neuron.index === 0) { | |
| const label = document.createElementNS('http://www.w3.org/2000/svg', 'text'); | |
| label.setAttribute('x', neuron.x); | |
| label.setAttribute('y', neuron.y - 40); | |
| label.setAttribute('text-anchor', 'middle'); | |
| label.setAttribute('fill', 'white'); | |
| label.setAttribute('font-size', '14'); | |
| label.setAttribute('font-weight', 'bold'); | |
| const layerNames = ['Input', 'Hidden 1', 'Hidden 2', 'Output']; | |
| label.textContent = layerNames[neuron.layer]; | |
| this.svg.appendChild(label); | |
| } | |
| } | |
| } | |
| initializeLossChart() { | |
| this.lossCtx.fillStyle = '#1a1a2e'; | |
| this.lossCtx.fillRect(0, 0, this.lossCanvas.width, this.lossCanvas.height); | |
| // Draw axes | |
| this.lossCtx.strokeStyle = '#ffffff'; | |
| this.lossCtx.lineWidth = 1; | |
| this.lossCtx.beginPath(); | |
| // Y-axis | |
| this.lossCtx.moveTo(50, 20); | |
| this.lossCtx.lineTo(50, 160); | |
| // X-axis | |
| this.lossCtx.moveTo(50, 160); | |
| this.lossCtx.lineTo(530, 160); | |
| this.lossCtx.stroke(); | |
| // Labels | |
| this.lossCtx.fillStyle = '#ffffff'; | |
| this.lossCtx.font = '12px Arial'; | |
| this.lossCtx.fillText('Loss', 10, 15); | |
| this.lossCtx.fillText('Epochs', 490, 175); | |
| // Y-axis labels | |
| for (var i = 0; i <= 10; i++) { | |
| var y = 160 - (i * 14); | |
| var value = (i / 10).toFixed(1); | |
| this.lossCtx.fillText(value, 15, y + 3); | |
| // Grid lines | |
| this.lossCtx.strokeStyle = '#333'; | |
| this.lossCtx.lineWidth = 0.5; | |
| this.lossCtx.beginPath(); | |
| this.lossCtx.moveTo(50, y); | |
| this.lossCtx.lineTo(530, y); | |
| this.lossCtx.stroke(); | |
| } | |
| } | |
| updateLossChart() { | |
| // Clear and redraw background | |
| this.initializeLossChart(); | |
| if (this.trainLossHistory.length < 2) return; | |
| var maxEpochs = this.totalEpochs; | |
| var chartWidth = 480; // 530 - 50 | |
| var chartHeight = 140; // 160 - 20 | |
| // Draw training loss | |
| this.lossCtx.strokeStyle = '#ff6b6b'; | |
| this.lossCtx.lineWidth = 2; | |
| this.lossCtx.beginPath(); | |
| for (var i = 0; i < this.trainLossHistory.length; i++) { | |
| var x = 50 + (i / maxEpochs) * chartWidth; | |
| var y = 160 - (this.trainLossHistory[i] * chartHeight); | |
| if (i === 0) { | |
| this.lossCtx.moveTo(x, y); | |
| } else { | |
| this.lossCtx.lineTo(x, y); | |
| } | |
| } | |
| this.lossCtx.stroke(); | |
| // Draw validation loss | |
| this.lossCtx.strokeStyle = '#4ecdc4'; | |
| this.lossCtx.lineWidth = 2; | |
| this.lossCtx.beginPath(); | |
| for (var j = 0; j < this.valLossHistory.length; j++) { | |
| var x2 = 50 + (j / maxEpochs) * chartWidth; | |
| var y2 = 160 - (this.valLossHistory[j] * chartHeight); | |
| if (j === 0) { | |
| this.lossCtx.moveTo(x2, y2); | |
| } else { | |
| this.lossCtx.lineTo(x2, y2); | |
| } | |
| } | |
| this.lossCtx.stroke(); | |
| // Draw legend | |
| this.lossCtx.fillStyle = '#ff6b6b'; | |
| this.lossCtx.fillRect(350, 25, 15, 3); | |
| this.lossCtx.fillStyle = '#ffffff'; | |
| this.lossCtx.font = '12px Arial'; | |
| this.lossCtx.fillText('Train Loss', 370, 30); | |
| this.lossCtx.fillStyle = '#4ecdc4'; | |
| this.lossCtx.fillRect(450, 25, 15, 3); | |
| this.lossCtx.fillStyle = '#ffffff'; | |
| this.lossCtx.fillText('Val Loss', 470, 30); | |
| } | |
| getNeuronColor(neuron) { | |
| if (neuron.layer === 0) return '#2196F3'; // Input - Blue | |
| if (neuron.layer === this.layers.length - 1) return '#FF9800'; // Output - Orange | |
| return neuron.active ? '#4CAF50' : '#f44336'; // Hidden - Green/Red | |
| } | |
| getConnectionColor(conn) { | |
| const opacity = this.getConnectionOpacity(conn); | |
| if (opacity < 0.5) return '#666'; | |
| return conn.weight > 0 ? '#4CAF50' : '#f44336'; | |
| } | |
| getConnectionOpacity(conn) { | |
| if (this.mode === 'testing') return 1; | |
| // Connection is active if both neurons are active | |
| const bothActive = conn.from.active && conn.to.active; | |
| return bothActive ? 1 : 0.2; | |
| } | |
| applyDropout() { | |
| if (this.mode === 'testing') { | |
| // In testing mode, all neurons are active | |
| for (var i = 0; i < this.neurons.length; i++) { | |
| this.neurons[i].active = true; | |
| } | |
| return; | |
| } | |
| var dropoutRate = parseFloat(document.getElementById('dropoutRate').value); | |
| // Apply dropout independently per hidden layer | |
| for (var layerIdx = 1; layerIdx < this.layers.length - 1; layerIdx++) { | |
| // Get all neurons in this hidden layer | |
| var layerNeurons = this.neurons.filter(function(n) { | |
| return n.layer === layerIdx; | |
| }); | |
| // Apply dropout to each neuron independently | |
| var activeCount = 0; | |
| for (var i = 0; i < layerNeurons.length; i++) { | |
| layerNeurons[i].active = Math.random() > dropoutRate; | |
| if (layerNeurons[i].active) activeCount++; | |
| } | |
| // Safety check: ensure at least one neuron remains active per layer | |
| // This prevents complete layer dropout which would break information flow | |
| if (activeCount === 0 && layerNeurons.length > 0) { | |
| // Randomly activate one neuron to maintain connectivity | |
| var randomIdx = Math.floor(Math.random() * layerNeurons.length); | |
| layerNeurons[randomIdx].active = true; | |
| } | |
| } | |
| // Input and output layers are always active | |
| for (var j = 0; j < this.neurons.length; j++) { | |
| var neuron = this.neurons[j]; | |
| if (neuron.layer === 0 || neuron.layer === this.layers.length - 1) { | |
| neuron.active = true; | |
| } | |
| } | |
| } | |
| updateNetwork() { | |
| for (var i = 0; i < this.neurons.length; i++) { | |
| var neuron = this.neurons[i]; | |
| if (neuron.element) { | |
| neuron.element.setAttribute('fill', this.getNeuronColor(neuron)); | |
| neuron.element.setAttribute('opacity', neuron.active ? 1 : 0.3); | |
| } | |
| } | |
| for (var j = 0; j < this.connections.length; j++) { | |
| var conn = this.connections[j]; | |
| if (conn.element) { | |
| conn.element.setAttribute('stroke', this.getConnectionColor(conn)); | |
| conn.element.setAttribute('opacity', this.getConnectionOpacity(conn)); | |
| } | |
| } | |
| } | |
| simulateTraining() { | |
| if (!this.isTraining) return; | |
| // Apply dropout | |
| this.applyDropout(); | |
| // Simulate loss decrease and accuracy increase with realistic patterns | |
| var progress = this.currentEpoch / this.totalEpochs; | |
| // Training loss decreases faster initially, then plateaus | |
| var baseLoss = Math.max(0.05, 1.0 - progress * 0.85); | |
| this.trainLoss = baseLoss + Math.random() * 0.08 - 0.04; | |
| // Validation loss decreases slower and may fluctuate more | |
| var valBaseLoss = Math.max(0.08, 1.0 - progress * 0.75); | |
| this.valLoss = valBaseLoss + Math.random() * 0.12 - 0.06; | |
| // Sometimes validation loss increases slightly (overfitting simulation) | |
| if (progress > 0.6 && Math.random() < 0.3) { | |
| this.valLoss += 0.05; | |
| } | |
| // Accuracy increases | |
| this.accuracy = Math.min(0.95, 0.5 + progress * 0.4 + Math.random() * 0.05); | |
| // Store loss history | |
| this.trainLossHistory.push(Math.max(0, Math.min(1, this.trainLoss))); | |
| this.valLossHistory.push(Math.max(0, Math.min(1, this.valLoss))); | |
| // Update network visualization | |
| this.updateNetwork(); | |
| this.updateLossChart(); | |
| this.updateDisplay(); | |
| this.currentEpoch++; | |
| if (this.currentEpoch <= this.totalEpochs) { | |
| setTimeout(() => this.simulateTraining(), 500); | |
| } else { | |
| this.stopTraining(); | |
| } | |
| } | |
| startTraining() { | |
| this.isTraining = true; | |
| this.currentEpoch = 0; | |
| this.totalEpochs = parseInt(document.getElementById('epochs').value); | |
| this.trainLossHistory = []; | |
| this.valLossHistory = []; | |
| document.getElementById('startBtn').disabled = true; | |
| document.getElementById('stopBtn').disabled = false; | |
| this.simulateTraining(); | |
| } | |
| stopTraining() { | |
| this.isTraining = false; | |
| document.getElementById('startBtn').disabled = false; | |
| document.getElementById('stopBtn').disabled = true; | |
| // Reset all neurons to active state after training | |
| for (var i = 0; i < this.neurons.length; i++) { | |
| this.neurons[i].active = true; | |
| } | |
| this.updateNetwork(); | |
| this.updateDisplay(); | |
| } | |
| reset() { | |
| this.stopTraining(); | |
| this.currentEpoch = 0; | |
| this.trainLoss = 1.0; | |
| this.valLoss = 1.0; | |
| this.accuracy = 0.5; | |
| this.trainLossHistory = []; | |
| this.valLossHistory = []; | |
| // Reset all neurons to active state | |
| for (var i = 0; i < this.neurons.length; i++) { | |
| this.neurons[i].active = true; | |
| } | |
| this.updateNetwork(); | |
| this.initializeLossChart(); | |
| this.updateDisplay(); | |
| } | |
| setMode(mode) { | |
| this.mode = mode; | |
| this.applyDropout(); | |
| this.updateNetwork(); | |
| this.updateDisplay(); | |
| } | |
| updateDisplay() { | |
| document.getElementById('currentEpoch').textContent = this.currentEpoch; | |
| document.getElementById('totalEpochs').textContent = this.totalEpochs; | |
| document.getElementById('currentMode').textContent = this.mode === 'training' ? 'Training' : 'Testing'; | |
| document.getElementById('trainLoss').textContent = this.trainLoss.toFixed(3); | |
| document.getElementById('valLoss').textContent = this.valLoss.toFixed(3); | |
| document.getElementById('currentLoss').textContent = ((this.trainLoss + this.valLoss) / 2).toFixed(3); | |
| document.getElementById('currentAccuracy').textContent = (this.accuracy * 100).toFixed(1) + '%'; | |
| // Count active and dropped neurons (excluding input/output layers) | |
| var hiddenNeurons = this.neurons.filter(function(n) { | |
| return n.layer > 0 && n.layer < this.layers.length - 1; | |
| }.bind(this)); | |
| var activeHidden = hiddenNeurons.filter(function(n) { return n.active; }).length; | |
| var totalHidden = hiddenNeurons.length; | |
| document.getElementById('activeNeurons').textContent = `${activeHidden}/${totalHidden}`; | |
| document.getElementById('droppedNeurons').textContent = `${totalHidden - activeHidden}/${totalHidden}`; | |
| // Update progress bar | |
| var progress = this.totalEpochs > 0 ? (this.currentEpoch / this.totalEpochs) * 100 : 0; | |
| document.getElementById('progressFill').style.width = progress + '%'; | |
| } | |
| setupEventListeners() { | |
| // Control sliders | |
| document.getElementById('dropoutRate').addEventListener('input', (e) => { | |
| document.getElementById('dropoutValue').textContent = e.target.value; | |
| }); | |
| document.getElementById('learningRate').addEventListener('input', (e) => { | |
| document.getElementById('learningValue').textContent = e.target.value; | |
| }); | |
| document.getElementById('epochs').addEventListener('input', (e) => { | |
| document.getElementById('epochsValue').textContent = e.target.value; | |
| }); | |
| // Buttons | |
| document.getElementById('startBtn').addEventListener('click', () => { | |
| this.startTraining(); | |
| }); | |
| document.getElementById('stopBtn').addEventListener('click', () => { | |
| this.stopTraining(); | |
| }); | |
| document.getElementById('resetBtn').addEventListener('click', () => { | |
| this.reset(); | |
| }); | |
| // Mode toggle | |
| document.getElementById('trainMode').addEventListener('click', () => { | |
| document.getElementById('trainMode').classList.add('active'); | |
| document.getElementById('testMode').classList.remove('active'); | |
| this.setMode('training'); | |
| }); | |
| document.getElementById('testMode').addEventListener('click', () => { | |
| document.getElementById('testMode').classList.add('active'); | |
| document.getElementById('trainMode').classList.remove('active'); | |
| this.setMode('testing'); | |
| }); | |
| } | |
| } | |
| // Initialize the application | |
| const network = new DropoutNeuralNetwork(); | |
| </script> | |
| </body> | |
| </html> | |