Neural_Network / index.html
jake2004's picture
Update index.html
10b371e verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Neural Network Visualization</title>
<style>
body {
margin: 0;
overflow: hidden;
font-family: Arial, sans-serif;
color: white;
background-color: #111;
}
#canvas-container {
position: absolute;
width: 100%;
height: 100%;
}
#info-panel {
position: absolute;
top: 10px;
left: 10px;
background-color: rgba(0, 0, 0, 0.7);
padding: 15px;
border-radius: 5px;
max-width: 300px;
z-index: 100;
}
#controls {
position: absolute;
bottom: 10px;
left: 10px;
background-color: rgba(0, 0, 0, 0.7);
padding: 15px;
border-radius: 5px;
z-index: 100;
}
button, input {
margin: 5px;
padding: 8px;
background-color: #444;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
}
button:hover {
background-color: #666;
}
h1 {
margin-top: 0;
font-size: 1.2em;
}
</style>
</head>
<body>
<div id="canvas-container"></div>
<div id="info-panel">
<h1>3D Neural Network</h1>
<p>This visualization represents a simple feedforward neural network with multiple layers.</p>
<p>The connections between neurons light up when data flows through the network.</p>
<p><strong>Controls:</strong> Drag to rotate, scroll to zoom.</p>
</div>
<div id="controls">
<button id="toggle-animation">Pause Animation</button>
<button id="reset-view">Reset View</button>
<label for="layer-count">Layers: </label>
<input type="range" id="layer-count" min="2" max="7" value="4">
<span id="layer-count-value">4</span>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// Main configuration for the network
const config = {
neuronSize: 0.15,
layerDistance: 1.5,
neuronsPerLayer: [8, 12, 10, 6], // Default structure
neuronColors: {
input: 0x4286f4,
hidden: 0x42b0f4,
output: 0xf442a7
},
animationSpeed: 0.01,
connectionOpacity: 0.3,
activeConnectionOpacity: 0.8,
activeConnectionColor: 0xffffff,
pulseDuration: 100, // Number of frames for a complete pulse
};
// Global variables
let scene, camera, renderer, neurons = [], connections = [], animationActive = true;
let networkGroup, frame = 0;
// Initialize the scene
function init() {
// Create scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111);
// Create camera
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
// Create renderer
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('canvas-container').appendChild(renderer.domElement);
// Add lights
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
// Create a group for the entire network
networkGroup = new THREE.Group();
scene.add(networkGroup);
// Create the neural network
createNeuralNetwork();
// Set up controls for orbiting
setupOrbitControls();
// Event listeners
window.addEventListener('resize', onWindowResize);
document.getElementById('toggle-animation').addEventListener('click', toggleAnimation);
document.getElementById('reset-view').addEventListener('click', resetView);
const layerSlider = document.getElementById('layer-count');
const layerCountDisplay = document.getElementById('layer-count-value');
layerSlider.addEventListener('input', function() {
layerCountDisplay.textContent = this.value;
updateNetworkStructure(parseInt(this.value));
});
// Start animation loop
animate();
}
// Create a neural network with specified layers
function createNeuralNetwork() {
neurons = [];
connections = [];
// Remove existing network if any
while(networkGroup.children.length > 0) {
networkGroup.remove(networkGroup.children[0]);
}
// Material for neurons
const inputMaterial = new THREE.MeshPhongMaterial({ color: config.neuronColors.input });
const hiddenMaterial = new THREE.MeshPhongMaterial({ color: config.neuronColors.hidden });
const outputMaterial = new THREE.MeshPhongMaterial({ color: config.neuronColors.output });
// Geometry for neurons
const neuronGeometry = new THREE.SphereGeometry(config.neuronSize, 16, 16);
// Create neurons for each layer
for (let layerIndex = 0; layerIndex < config.neuronsPerLayer.length; layerIndex++) {
const layerNeurons = [];
const neuronsInLayer = config.neuronsPerLayer[layerIndex];
let material;
if (layerIndex === 0) material = inputMaterial;
else if (layerIndex === config.neuronsPerLayer.length - 1) material = outputMaterial;
else material = hiddenMaterial;
// Calculate vertical spacing
const layerHeight = (neuronsInLayer - 1) * 0.6;
for (let neuronIndex = 0; neuronIndex < neuronsInLayer; neuronIndex++) {
const neuron = new THREE.Mesh(neuronGeometry, material);
// Position each neuron
neuron.position.x = layerIndex * config.layerDistance - (config.neuronsPerLayer.length - 1) * config.layerDistance / 2;
neuron.position.y = neuronIndex * 0.6 - layerHeight / 2;
neuron.layerIndex = layerIndex;
neuron.neuronIndex = neuronIndex;
networkGroup.add(neuron);
layerNeurons.push(neuron);
}
neurons.push(layerNeurons);
}
// Create connections between neurons
for (let layerIndex = 0; layerIndex < neurons.length - 1; layerIndex++) {
const currentLayer = neurons[layerIndex];
const nextLayer = neurons[layerIndex + 1];
for (let i = 0; i < currentLayer.length; i++) {
for (let j = 0; j < nextLayer.length; j++) {
const startNeuron = currentLayer[i];
const endNeuron = nextLayer[j];
const connectionGeometry = new THREE.BufferGeometry();
const lineMaterial = new THREE.LineBasicMaterial({
color: 0xaaaaaa,
transparent: true,
opacity: config.connectionOpacity
});
// Create a line between neurons
const points = [
startNeuron.position,
endNeuron.position
];
connectionGeometry.setFromPoints(points);
const connection = new THREE.Line(connectionGeometry, lineMaterial);
// Store connections for animation
connection.startNeuron = startNeuron;
connection.endNeuron = endNeuron;
connection.originalColor = 0xaaaaaa;
connection.activationTime = -1;
networkGroup.add(connection);
connections.push(connection);
}
}
}
}
// Update the network when layer count changes
function updateNetworkStructure(layerCount) {
// Generate a new structure with the specified number of layers
config.neuronsPerLayer = [];
// Input layer has 8 neurons
config.neuronsPerLayer.push(8);
// Generate hidden layers with varying sizes
for (let i = 0; i < layerCount - 2; i++) {
const layerSize = Math.round(6 + Math.sin(i * Math.PI / (layerCount - 2)) * 6);
config.neuronsPerLayer.push(layerSize);
}
// Output layer has 6 neurons
config.neuronsPerLayer.push(6);
// Recreate the network
createNeuralNetwork();
}
// Animation loop
function animate() {
requestAnimationFrame(animate);
if (animationActive) {
// Increment frame counter
frame += 1;
// Trigger activations
if (frame % 30 === 0) {
triggerNetworkActivation();
}
// Update all connections
updateConnections();
}
renderer.render(scene, camera);
}
// Trigger a new activation wave through the network
function triggerNetworkActivation() {
// Activate a random neuron in the input layer
const inputLayer = neurons[0];
const randomNeuronIndex = Math.floor(Math.random() * inputLayer.length);
// Get all connections from this neuron
for (let i = 0; i < connections.length; i++) {
const connection = connections[i];
if (connection.startNeuron === inputLayer[randomNeuronIndex]) {
connection.activationTime = frame;
connection.material.opacity = config.activeConnectionOpacity;
connection.material.color.set(config.activeConnectionColor);
}
}
}
// Update connection animations
function updateConnections() {
const activationLayerDuration = config.pulseDuration / (config.neuronsPerLayer.length - 1);
for (let i = 0; i < connections.length; i++) {
const connection = connections[i];
// If connection is active
if (connection.activationTime > 0) {
const elapsedFrames = frame - connection.activationTime;
// If this connection has been active long enough, propagate to next layer
if (elapsedFrames >= activationLayerDuration &&
connection.endNeuron.layerIndex < config.neuronsPerLayer.length - 1) {
// Find connections from the end neuron
for (let j = 0; j < connections.length; j++) {
const nextConnection = connections[j];
if (nextConnection.startNeuron === connection.endNeuron &&
nextConnection.activationTime < connection.activationTime) {
nextConnection.activationTime = frame;
nextConnection.material.opacity = config.activeConnectionOpacity;
nextConnection.material.color.set(config.activeConnectionColor);
}
}
}
// Fade out connection over time
if (elapsedFrames >= config.pulseDuration) {
connection.material.opacity = config.connectionOpacity;
connection.material.color.set(connection.originalColor);
connection.activationTime = -1;
}
}
}
}
// Toggle animation state
function toggleAnimation() {
animationActive = !animationActive;
document.getElementById('toggle-animation').textContent =
animationActive ? 'Pause Animation' : 'Resume Animation';
}
// Reset the camera view
function resetView() {
camera.position.set(0, 0, 5);
camera.lookAt(0, 0, 0);
}
// Handle window resize
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
// Basic orbit controls implementation
function setupOrbitControls() {
let isDragging = false;
let previousMousePosition = { x: 0, y: 0 };
const rotationSpeed = 0.01;
renderer.domElement.addEventListener('mousedown', function(e) {
isDragging = true;
previousMousePosition = { x: e.clientX, y: e.clientY };
});
renderer.domElement.addEventListener('mousemove', function(e) {
if (isDragging) {
const deltaMove = {
x: e.clientX - previousMousePosition.x,
y: e.clientY - previousMousePosition.y
};
networkGroup.rotation.y += deltaMove.x * rotationSpeed;
networkGroup.rotation.x += deltaMove.y * rotationSpeed;
previousMousePosition = { x: e.clientX, y: e.clientY };
}
});
renderer.domElement.addEventListener('mouseup', function() {
isDragging = false;
});
renderer.domElement.addEventListener('mouseleave', function() {
isDragging = false;
});
// Zoom functionality
renderer.domElement.addEventListener('wheel', function(e) {
e.preventDefault();
if (e.deltaY < 0) {
// Zoom in
camera.position.z = Math.max(2, camera.position.z - 0.5);
} else {
// Zoom out
camera.position.z = Math.min(10, camera.position.z + 0.5);
}
});
}
// Initialize the visualization when page loads
window.onload = init;
</script>
</body>
</html>