500 lines
15 KiB
HTML
500 lines
15 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>AgentDB - WASM Attention Demo</title>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
padding: 20px;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
header {
|
|
background: white;
|
|
padding: 30px;
|
|
border-radius: 10px;
|
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
h1 {
|
|
color: #667eea;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.subtitle {
|
|
color: #666;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.demo-section {
|
|
background: white;
|
|
padding: 30px;
|
|
border-radius: 10px;
|
|
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
h2 {
|
|
color: #333;
|
|
margin-bottom: 20px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 2px solid #667eea;
|
|
}
|
|
|
|
.status {
|
|
padding: 15px;
|
|
border-radius: 5px;
|
|
margin-bottom: 20px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.status.loading {
|
|
background: #fff3cd;
|
|
color: #856404;
|
|
}
|
|
|
|
.status.success {
|
|
background: #d4edda;
|
|
color: #155724;
|
|
}
|
|
|
|
.status.error {
|
|
background: #f8d7da;
|
|
color: #721c24;
|
|
}
|
|
|
|
button {
|
|
background: #667eea;
|
|
color: white;
|
|
border: none;
|
|
padding: 12px 24px;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
font-size: 16px;
|
|
margin-right: 10px;
|
|
margin-bottom: 10px;
|
|
transition: background 0.3s;
|
|
}
|
|
|
|
button:hover {
|
|
background: #5568d3;
|
|
}
|
|
|
|
button:disabled {
|
|
background: #ccc;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.results {
|
|
background: #f8f9fa;
|
|
padding: 20px;
|
|
border-radius: 5px;
|
|
margin-top: 20px;
|
|
font-family: 'Courier New', monospace;
|
|
font-size: 14px;
|
|
max-height: 400px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.metric {
|
|
display: inline-block;
|
|
background: #667eea;
|
|
color: white;
|
|
padding: 5px 15px;
|
|
border-radius: 20px;
|
|
margin: 5px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
gap: 20px;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.card {
|
|
background: #f8f9fa;
|
|
padding: 20px;
|
|
border-radius: 5px;
|
|
border-left: 4px solid #667eea;
|
|
}
|
|
|
|
.card h3 {
|
|
color: #667eea;
|
|
margin-bottom: 10px;
|
|
font-size: 18px;
|
|
}
|
|
|
|
.card p {
|
|
color: #666;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
code {
|
|
background: #f1f3f5;
|
|
padding: 2px 6px;
|
|
border-radius: 3px;
|
|
font-family: 'Courier New', monospace;
|
|
}
|
|
|
|
footer {
|
|
text-align: center;
|
|
color: white;
|
|
margin-top: 30px;
|
|
opacity: 0.9;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<header>
|
|
<h1>AgentDB WASM Attention Demo</h1>
|
|
<p class="subtitle">High-performance attention mechanisms in the browser</p>
|
|
<div style="margin-top: 15px;">
|
|
<span class="metric">Flash Attention</span>
|
|
<span class="metric">Hyperbolic Attention</span>
|
|
<span class="metric">Memory Consolidation</span>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Status Section -->
|
|
<div class="demo-section">
|
|
<h2>System Status</h2>
|
|
<div id="status" class="status loading">Initializing WASM module...</div>
|
|
<div id="features"></div>
|
|
</div>
|
|
|
|
<!-- Flash Attention Demo -->
|
|
<div class="demo-section">
|
|
<h2>Flash Attention</h2>
|
|
<p style="margin-bottom: 20px;">
|
|
O(N) memory complexity attention mechanism for efficient sequence processing.
|
|
Perfect for long sequences and memory-constrained environments.
|
|
</p>
|
|
<button id="runFlashAttention">Run Flash Attention</button>
|
|
<button id="benchmarkFlashAttention">Benchmark Performance</button>
|
|
<div id="flashResults" class="results" style="display: none;"></div>
|
|
</div>
|
|
|
|
<!-- Hyperbolic Attention Demo -->
|
|
<div class="demo-section">
|
|
<h2>Hyperbolic Attention</h2>
|
|
<p style="margin-bottom: 20px;">
|
|
Attention in hyperbolic space for hierarchical relationships.
|
|
Better representation of tree-like structures and taxonomies.
|
|
</p>
|
|
<button id="runHyperbolicAttention">Run Hyperbolic Attention</button>
|
|
<button id="visualizeHierarchy">Visualize Hierarchy</button>
|
|
<div id="hyperbolicResults" class="results" style="display: none;"></div>
|
|
</div>
|
|
|
|
<!-- Memory Consolidation Demo -->
|
|
<div class="demo-section">
|
|
<h2>Memory Consolidation</h2>
|
|
<p style="margin-bottom: 20px;">
|
|
Cluster and consolidate similar memories for efficient storage.
|
|
Reduces memory footprint while preserving important information.
|
|
</p>
|
|
<button id="runConsolidation">Run Consolidation</button>
|
|
<button id="compareMemory">Compare Memory Usage</button>
|
|
<div id="consolidationResults" class="results" style="display: none;"></div>
|
|
</div>
|
|
|
|
<!-- Feature Comparison -->
|
|
<div class="demo-section">
|
|
<h2>Feature Comparison</h2>
|
|
<div class="grid">
|
|
<div class="card">
|
|
<h3>Flash Attention</h3>
|
|
<p><strong>Memory:</strong> O(N) vs O(N²)</p>
|
|
<p><strong>Speed:</strong> 2-4x faster</p>
|
|
<p><strong>Use Case:</strong> Long sequences</p>
|
|
</div>
|
|
<div class="card">
|
|
<h3>Hyperbolic Attention</h3>
|
|
<p><strong>Space:</strong> Poincaré ball</p>
|
|
<p><strong>Benefit:</strong> Better hierarchies</p>
|
|
<p><strong>Use Case:</strong> Tree structures</p>
|
|
</div>
|
|
<div class="card">
|
|
<h3>Memory Consolidation</h3>
|
|
<p><strong>Compression:</strong> 5-10x</p>
|
|
<p><strong>Quality:</strong> Minimal loss</p>
|
|
<p><strong>Use Case:</strong> Large memory sets</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<footer>
|
|
<p>AgentDB v2.0 | Powered by WASM & RuVector</p>
|
|
</footer>
|
|
</div>
|
|
|
|
<script type="module">
|
|
import {
|
|
AttentionBrowser,
|
|
createAttention,
|
|
createFastAttention,
|
|
createAccurateAttention
|
|
} from '../../dist/agentdb.browser.js';
|
|
|
|
let attention = null;
|
|
|
|
// Initialize
|
|
async function initialize() {
|
|
const statusEl = document.getElementById('status');
|
|
const featuresEl = document.getElementById('features');
|
|
|
|
try {
|
|
// Create attention instance
|
|
attention = createAttention({
|
|
dimension: 384,
|
|
numHeads: 4,
|
|
blockSize: 64,
|
|
useWASM: true
|
|
});
|
|
|
|
// Initialize (lazy load WASM)
|
|
await attention.initialize();
|
|
|
|
const state = attention.getLoadingState();
|
|
const error = attention.getError();
|
|
|
|
if (state === 'loaded') {
|
|
statusEl.className = 'status success';
|
|
statusEl.textContent = '✓ WASM module loaded successfully!';
|
|
} else if (state === 'error') {
|
|
statusEl.className = 'status error';
|
|
statusEl.textContent = `⚠ WASM loading failed (using fallback): ${error?.message || 'Unknown error'}`;
|
|
}
|
|
|
|
// Display browser features
|
|
featuresEl.innerHTML = `
|
|
<div style="margin-top: 20px;">
|
|
<h3 style="margin-bottom: 10px;">Browser Capabilities:</h3>
|
|
<div class="grid">
|
|
<div class="card">
|
|
<h3>WebAssembly</h3>
|
|
<p>${typeof WebAssembly !== 'undefined' ? '✓ Supported' : '✗ Not supported'}</p>
|
|
</div>
|
|
<div class="card">
|
|
<h3>WASM SIMD</h3>
|
|
<p id="simdStatus">Detecting...</p>
|
|
</div>
|
|
<div class="card">
|
|
<h3>SharedArrayBuffer</h3>
|
|
<p>${typeof SharedArrayBuffer !== 'undefined' ? '✓ Supported' : '✗ Not supported'}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
// Detect SIMD
|
|
detectSIMD();
|
|
|
|
} catch (error) {
|
|
statusEl.className = 'status error';
|
|
statusEl.textContent = `✗ Initialization failed: ${error.message}`;
|
|
console.error(error);
|
|
}
|
|
}
|
|
|
|
async function detectSIMD() {
|
|
try {
|
|
const simdTest = new Uint8Array([
|
|
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
|
|
0x01, 0x05, 0x01, 0x60, 0x00, 0x01, 0x7b, 0x03,
|
|
0x02, 0x01, 0x00, 0x0a, 0x0a, 0x01, 0x08, 0x00,
|
|
0xfd, 0x0c, 0xfd, 0x0c, 0xfd, 0x54, 0x0b
|
|
]);
|
|
const module = await WebAssembly.instantiate(simdTest);
|
|
document.getElementById('simdStatus').textContent = '✓ Supported';
|
|
} catch {
|
|
document.getElementById('simdStatus').textContent = '✗ Not supported';
|
|
}
|
|
}
|
|
|
|
// Flash Attention Demo
|
|
document.getElementById('runFlashAttention').addEventListener('click', async () => {
|
|
const resultsEl = document.getElementById('flashResults');
|
|
resultsEl.style.display = 'block';
|
|
resultsEl.textContent = 'Running flash attention...';
|
|
|
|
try {
|
|
const dim = 384;
|
|
const seqLen = 10;
|
|
|
|
// Create sample data
|
|
const query = new Float32Array(dim);
|
|
const keys = new Float32Array(seqLen * dim);
|
|
const values = new Float32Array(seqLen * dim);
|
|
|
|
for (let i = 0; i < dim; i++) query[i] = Math.random() - 0.5;
|
|
for (let i = 0; i < seqLen * dim; i++) {
|
|
keys[i] = Math.random() - 0.5;
|
|
values[i] = Math.random() - 0.5;
|
|
}
|
|
|
|
const start = performance.now();
|
|
const output = await attention.flashAttention(query, keys, values);
|
|
const duration = performance.now() - start;
|
|
|
|
resultsEl.innerHTML = `
|
|
<strong>Flash Attention Results:</strong><br><br>
|
|
Sequence Length: ${seqLen}<br>
|
|
Dimension: ${dim}<br>
|
|
Time: ${duration.toFixed(2)}ms<br>
|
|
Output size: ${output.length} elements<br>
|
|
First 5 values: [${Array.from(output.slice(0, 5)).map(v => v.toFixed(4)).join(', ')}]<br><br>
|
|
<em>Memory complexity: O(N) instead of O(N²)</em>
|
|
`;
|
|
} catch (error) {
|
|
resultsEl.textContent = `Error: ${error.message}`;
|
|
}
|
|
});
|
|
|
|
// Benchmark Flash Attention
|
|
document.getElementById('benchmarkFlashAttention').addEventListener('click', async () => {
|
|
const resultsEl = document.getElementById('flashResults');
|
|
resultsEl.style.display = 'block';
|
|
resultsEl.textContent = 'Running benchmark...';
|
|
|
|
try {
|
|
const iterations = 100;
|
|
const dim = 384;
|
|
const seqLen = 10;
|
|
const times = [];
|
|
|
|
const query = new Float32Array(dim).map(() => Math.random() - 0.5);
|
|
const keys = new Float32Array(seqLen * dim).map(() => Math.random() - 0.5);
|
|
const values = new Float32Array(seqLen * dim).map(() => Math.random() - 0.5);
|
|
|
|
for (let i = 0; i < iterations; i++) {
|
|
const start = performance.now();
|
|
await attention.flashAttention(query, keys, values);
|
|
times.push(performance.now() - start);
|
|
}
|
|
|
|
times.sort((a, b) => a - b);
|
|
const avg = times.reduce((a, b) => a + b) / times.length;
|
|
const p50 = times[Math.floor(times.length * 0.5)];
|
|
const p95 = times[Math.floor(times.length * 0.95)];
|
|
|
|
resultsEl.innerHTML = `
|
|
<strong>Benchmark Results (${iterations} iterations):</strong><br><br>
|
|
Average: ${avg.toFixed(2)}ms<br>
|
|
Median (p50): ${p50.toFixed(2)}ms<br>
|
|
p95: ${p95.toFixed(2)}ms<br>
|
|
Min: ${times[0].toFixed(2)}ms<br>
|
|
Max: ${times[times.length - 1].toFixed(2)}ms<br><br>
|
|
<em>Throughput: ${(1000 / avg).toFixed(0)} operations/second</em>
|
|
`;
|
|
} catch (error) {
|
|
resultsEl.textContent = `Error: ${error.message}`;
|
|
}
|
|
});
|
|
|
|
// Hyperbolic Attention Demo
|
|
document.getElementById('runHyperbolicAttention').addEventListener('click', async () => {
|
|
const resultsEl = document.getElementById('hyperbolicResults');
|
|
resultsEl.style.display = 'block';
|
|
resultsEl.textContent = 'Running hyperbolic attention...';
|
|
|
|
try {
|
|
const dim = 384;
|
|
const numKeys = 5;
|
|
|
|
const query = new Float32Array(dim).map(() => Math.random() * 0.5);
|
|
const keys = new Float32Array(numKeys * dim).map(() => Math.random() * 0.5);
|
|
|
|
const start = performance.now();
|
|
const similarities = await attention.hyperbolicAttention(query, keys);
|
|
const duration = performance.now() - start;
|
|
|
|
resultsEl.innerHTML = `
|
|
<strong>Hyperbolic Attention Results:</strong><br><br>
|
|
Number of keys: ${numKeys}<br>
|
|
Dimension: ${dim}<br>
|
|
Time: ${duration.toFixed(2)}ms<br><br>
|
|
<strong>Similarities (Poincaré distance):</strong><br>
|
|
${Array.from(similarities).map((s, i) =>
|
|
`Key ${i}: ${s.toFixed(4)}`
|
|
).join('<br>')}<br><br>
|
|
<em>Using Poincaré ball model for hyperbolic space</em>
|
|
`;
|
|
} catch (error) {
|
|
resultsEl.textContent = `Error: ${error.message}`;
|
|
}
|
|
});
|
|
|
|
// Memory Consolidation Demo
|
|
document.getElementById('runConsolidation').addEventListener('click', async () => {
|
|
const resultsEl = document.getElementById('consolidationResults');
|
|
resultsEl.style.display = 'block';
|
|
resultsEl.textContent = 'Running memory consolidation...';
|
|
|
|
try {
|
|
const dim = 384;
|
|
const numMemories = 20;
|
|
|
|
// Create clustered memories
|
|
const memories = [];
|
|
for (let cluster = 0; cluster < 3; cluster++) {
|
|
const base = new Float32Array(dim).map(() => Math.random() - 0.5);
|
|
for (let i = 0; i < 6; i++) {
|
|
const memory = new Float32Array(dim);
|
|
for (let d = 0; d < dim; d++) {
|
|
memory[d] = base[d] + (Math.random() - 0.5) * 0.1;
|
|
}
|
|
memories.push(memory);
|
|
}
|
|
}
|
|
|
|
const start = performance.now();
|
|
const consolidated = await attention.consolidateMemories(memories, {
|
|
threshold: 0.85,
|
|
maxClusters: 5
|
|
});
|
|
const duration = performance.now() - start;
|
|
|
|
const totalMembers = consolidated.reduce((sum, c) => sum + c.count, 0);
|
|
|
|
resultsEl.innerHTML = `
|
|
<strong>Memory Consolidation Results:</strong><br><br>
|
|
Original memories: ${memories.length}<br>
|
|
Consolidated clusters: ${consolidated.length}<br>
|
|
Compression ratio: ${(memories.length / consolidated.length).toFixed(2)}x<br>
|
|
Time: ${duration.toFixed(2)}ms<br><br>
|
|
<strong>Clusters:</strong><br>
|
|
${consolidated.map((c, i) =>
|
|
`Cluster ${i}: ${c.count} members`
|
|
).join('<br>')}<br><br>
|
|
<em>Reduced from ${memories.length} to ${consolidated.length} memories</em>
|
|
`;
|
|
} catch (error) {
|
|
resultsEl.textContent = `Error: ${error.message}`;
|
|
}
|
|
});
|
|
|
|
// Initialize on load
|
|
initialize();
|
|
</script>
|
|
</body>
|
|
</html>
|