softmaxfunction / index.html
oliverguhr's picture
genertaed by deepsite
5b8c940 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Softmax Function Visualizer</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.slider-container {
transition: all 0.3s ease;
}
.slider-container:hover {
transform: translateY(-3px);
}
.bar-container {
transition: all 0.5s ease;
}
.glow {
box-shadow: 0 0 15px rgba(59, 130, 246, 0.5);
}
.input-value {
min-width: 60px;
text-align: center;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen">
<div class="container mx-auto px-4 py-8">
<div class="max-w-4xl mx-auto">
<!-- Header -->
<div class="text-center mb-8">
<h1 class="text-4xl font-bold text-blue-600 mb-2">Softmax Function Visualizer</h1>
<p class="text-gray-600 text-lg">
Interactive visualization of the softmax activation function
</p>
</div>
<!-- Explanation Card -->
<div class="bg-white rounded-xl shadow-md p-6 mb-8">
<div class="flex items-start">
<div class="bg-blue-100 p-3 rounded-full mr-4">
<i class="fas fa-info-circle text-blue-600 text-xl"></i>
</div>
<div>
<h2 class="text-xl font-semibold text-gray-800 mb-2">About Softmax</h2>
<p class="text-gray-600 mb-2">
The softmax function converts a vector of real numbers into a probability distribution.
It's commonly used in machine learning for multi-class classification.
</p>
<p class="text-gray-600">
Formula: <code class="bg-gray-100 px-2 py-1 rounded">σ(z)_i = e^{z_i} / Σ_j e^{z_j}</code>
</p>
</div>
</div>
</div>
<!-- Controls -->
<div class="bg-white rounded-xl shadow-md p-6 mb-8">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-semibold text-gray-800">Input Values</h2>
<div class="flex space-x-2">
<button id="add-input" class="bg-green-500 hover:bg-green-600 text-white px-3 py-1 rounded-lg transition">
<i class="fas fa-plus mr-1"></i> Add
</button>
<button id="reset" class="bg-gray-500 hover:bg-gray-600 text-white px-3 py-1 rounded-lg transition">
<i class="fas fa-sync-alt mr-1"></i> Reset
</button>
</div>
</div>
<div id="sliders-container" class="space-y-4">
<!-- Sliders will be added here dynamically -->
</div>
</div>
<!-- Results -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
<!-- Input Values -->
<div class="bg-white rounded-xl shadow-md p-6">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Input Values</h2>
<div id="input-values" class="space-y-2">
<!-- Input values will be displayed here -->
</div>
</div>
<!-- Softmax Output -->
<div class="bg-white rounded-xl shadow-md p-6">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Softmax Output</h2>
<div id="output-values" class="space-y-2">
<!-- Output values will be displayed here -->
</div>
</div>
</div>
<!-- Summary -->
<div class="bg-blue-50 rounded-xl shadow-md p-6">
<div class="flex items-start">
<div class="bg-blue-100 p-3 rounded-full mr-4">
<i class="fas fa-lightbulb text-blue-600 text-xl"></i>
</div>
<div>
<h2 class="text-xl font-semibold text-gray-800 mb-2">Key Insights</h2>
<ul class="list-disc pl-5 text-gray-600 space-y-1">
<li>Softmax converts input values to probabilities that sum to 1</li>
<li>Higher input values get exponentially larger probabilities</li>
<li>The function is sensitive to differences between values</li>
<li>Adding a constant to all inputs doesn't change the output</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize with 3 inputs
let inputValues = [1, 2, 3];
// DOM elements
const slidersContainer = document.getElementById('sliders-container');
const inputValuesContainer = document.getElementById('input-values');
const outputValuesContainer = document.getElementById('output-values');
const addInputBtn = document.getElementById('add-input');
const resetBtn = document.getElementById('reset');
// Initialize the app
function init() {
renderSliders();
updateVisualization();
}
// Render sliders based on current input values
function renderSliders() {
slidersContainer.innerHTML = '';
inputValuesContainer.innerHTML = '';
inputValues.forEach((value, index) => {
// Create slider container
const sliderContainer = document.createElement('div');
sliderContainer.className = 'slider-container bg-gray-50 p-4 rounded-lg';
// Create label
const label = document.createElement('div');
label.className = 'flex justify-between items-center mb-2';
label.innerHTML = `
<span class="font-medium text-gray-700">Input ${index + 1}</span>
<div class="flex items-center">
<span class="input-value bg-blue-100 text-blue-800 font-mono px-2 py-1 rounded mr-2">${value.toFixed(2)}</span>
<button class="delete-btn text-red-500 hover:text-red-700 transition" data-index="${index}">
<i class="fas fa-trash"></i>
</button>
</div>
`;
// Create slider
const slider = document.createElement('input');
slider.type = 'range';
slider.min = '-5';
slider.max = '5';
slider.step = '0.1';
slider.value = value;
slider.className = 'w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer';
slider.dataset.index = index;
// Add event listener
slider.addEventListener('input', function() {
const index = parseInt(this.dataset.index);
const value = parseFloat(this.value);
inputValues[index] = value;
// Update the displayed value
this.parentNode.querySelector('.input-value').textContent = value.toFixed(2);
updateVisualization();
});
// Add delete button event listener
const deleteBtn = label.querySelector('.delete-btn');
deleteBtn.addEventListener('click', function() {
if (inputValues.length > 1) {
const index = parseInt(this.dataset.index);
inputValues.splice(index, 1);
renderSliders();
updateVisualization();
} else {
alert("You need at least one input!");
}
});
// Assemble slider container
sliderContainer.appendChild(label);
sliderContainer.appendChild(slider);
slidersContainer.appendChild(sliderContainer);
});
}
// Calculate softmax function
function softmax(values) {
const max = Math.max(...values);
const exps = values.map(x => Math.exp(x - max)); // Numerical stability
const sumExps = exps.reduce((a, b) => a + b, 0);
return exps.map(exp => exp / sumExps);
}
// Update all visualizations
function updateVisualization() {
const softmaxOutput = softmax(inputValues);
// Update input values display
inputValuesContainer.innerHTML = inputValues.map((value, index) => `
<div class="flex justify-between items-center py-2 px-3 rounded ${index % 2 === 0 ? 'bg-gray-50' : ''}">
<span class="font-medium">Input ${index + 1}</span>
<span class="font-mono text-blue-600">${value.toFixed(4)}</span>
</div>
`).join('');
// Update output values display
outputValuesContainer.innerHTML = softmaxOutput.map((value, index) => {
const percent = (value * 100).toFixed(2);
return `
<div class="bar-container">
<div class="flex justify-between items-center mb-1">
<span class="font-medium">Output ${index + 1}</span>
<span class="font-mono text-green-600">${value.toFixed(4)} <span class="text-gray-500">(${percent}%)</span></span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div class="bg-gradient-to-r from-blue-400 to-blue-600 h-2.5 rounded-full"
style="width: ${percent}%"></div>
</div>
</div>
`;
}).join('');
}
// Event listeners
addInputBtn.addEventListener('click', function() {
if (inputValues.length < 8) {
// Add a new input with value similar to the last one
const newValue = inputValues.length > 0 ? inputValues[inputValues.length - 1] : 0;
inputValues.push(newValue);
renderSliders();
updateVisualization();
} else {
alert("Maximum of 8 inputs reached!");
}
});
resetBtn.addEventListener('click', function() {
inputValues = [1, 2, 3];
renderSliders();
updateVisualization();
});
// Initialize the app
init();
});
</script>
</body>
</html>