git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
379 lines
11 KiB
Rust
379 lines
11 KiB
Rust
//! Learning Mechanism Performance Benchmarks
|
|
//!
|
|
//! Benchmarks for MicroLoRA, SONA, and adaptive learning.
|
|
//! Focus on parameter efficiency and training speed.
|
|
//!
|
|
//! Run with: cargo bench --bench learning_performance
|
|
|
|
use criterion::{criterion_group, criterion_main, Criterion, BenchmarkId, Throughput};
|
|
|
|
/// Generate random f32 vector
|
|
fn random_vector(dim: usize, seed: u64) -> Vec<f32> {
|
|
(0..dim)
|
|
.map(|i| {
|
|
let x = ((seed.wrapping_mul(i as u64 + 1).wrapping_mul(0x5DEECE66D)) % 1000) as f32;
|
|
(x / 500.0) - 1.0
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
fn bench_micro_lora(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("micro_lora");
|
|
|
|
// Test different ranks and dimensions
|
|
for (dim, rank) in [(64, 4), (128, 8), (256, 16), (512, 32)].iter() {
|
|
let input = random_vector(*dim, 42);
|
|
let gradients = random_vector(*dim, 123);
|
|
|
|
group.bench_with_input(
|
|
BenchmarkId::new("forward", format!("d{}_r{}", dim, rank)),
|
|
&(&input, dim, rank),
|
|
|b, (inp, d, r)| {
|
|
// TODO: When MicroLoRA is implemented:
|
|
// let lora = MicroLoRA::new(*d, *r);
|
|
|
|
b.iter(|| {
|
|
// Placeholder: simulate LoRA forward pass
|
|
// output = input + B @ A @ input
|
|
|
|
// A: dim x rank projection
|
|
let mut projected = vec![0.0f32; **r];
|
|
for i in 0..**r {
|
|
for j in 0..**d {
|
|
projected[i] += inp[j] * 0.01;
|
|
}
|
|
}
|
|
|
|
// B: rank x dim projection
|
|
let mut output = vec![0.0f32; **d];
|
|
for i in 0..**d {
|
|
for j in 0..**r {
|
|
output[i] += projected[j] * 0.01;
|
|
}
|
|
}
|
|
|
|
// Add residual
|
|
for (o, i) in output.iter_mut().zip(inp.iter()) {
|
|
*o += i;
|
|
}
|
|
|
|
output
|
|
});
|
|
},
|
|
);
|
|
|
|
group.bench_with_input(
|
|
BenchmarkId::new("backward", format!("d{}_r{}", dim, rank)),
|
|
&(&gradients, dim, rank),
|
|
|b, (grad, d, r)| {
|
|
b.iter(|| {
|
|
// Placeholder: simulate LoRA backward pass
|
|
// Compute gradients for A and B
|
|
|
|
let grad_a = vec![vec![0.01f32; **r]; **d];
|
|
let grad_b = vec![vec![0.01f32; **d]; **r];
|
|
|
|
(grad_a, grad_b)
|
|
});
|
|
},
|
|
);
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_sona_adaptation(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("sona");
|
|
|
|
let input_dim = 64;
|
|
let hidden_dim = 128;
|
|
let output_dim = 32;
|
|
|
|
let input = random_vector(input_dim, 42);
|
|
let target = random_vector(output_dim, 123);
|
|
|
|
group.bench_function("forward", |b| {
|
|
// TODO: When SONA is implemented:
|
|
// let sona = SONA::new(input_dim, hidden_dim, output_dim);
|
|
|
|
b.iter(|| {
|
|
// Placeholder: simulate SONA forward
|
|
let mut hidden = vec![0.0f32; hidden_dim];
|
|
for i in 0..hidden_dim {
|
|
for j in 0..input_dim {
|
|
hidden[i] += input[j] * 0.01;
|
|
}
|
|
hidden[i] = hidden[i].tanh();
|
|
}
|
|
|
|
let mut output = vec![0.0f32; output_dim];
|
|
for i in 0..output_dim {
|
|
for j in 0..hidden_dim {
|
|
output[i] += hidden[j] * 0.01;
|
|
}
|
|
}
|
|
output
|
|
});
|
|
});
|
|
|
|
group.bench_function("adapt_architecture", |b| {
|
|
b.iter(|| {
|
|
// Placeholder: simulate architecture adaptation
|
|
// Analyze activation statistics and prune/grow neurons
|
|
|
|
let neuron_activities = random_vector(hidden_dim, 456);
|
|
let threshold = 0.1;
|
|
|
|
let active_count: usize = neuron_activities.iter()
|
|
.filter(|&a| a.abs() > threshold)
|
|
.count();
|
|
|
|
active_count
|
|
});
|
|
});
|
|
|
|
group.bench_function("prune_neurons", |b| {
|
|
b.iter(|| {
|
|
// Placeholder: simulate neuron pruning
|
|
let neuron_importance = random_vector(hidden_dim, 789);
|
|
let prune_threshold = 0.05;
|
|
|
|
let kept_indices: Vec<usize> = neuron_importance.iter()
|
|
.enumerate()
|
|
.filter(|(_, &imp)| imp.abs() > prune_threshold)
|
|
.map(|(i, _)| i)
|
|
.collect();
|
|
|
|
kept_indices
|
|
});
|
|
});
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_online_learning(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("online_learning");
|
|
|
|
let dim = 64;
|
|
let num_samples = 100;
|
|
|
|
// Generate training samples
|
|
let samples: Vec<(Vec<f32>, Vec<f32>)> = (0..num_samples)
|
|
.map(|i| {
|
|
let input = random_vector(dim, i as u64);
|
|
let target = random_vector(dim, (i + 1000) as u64);
|
|
(input, target)
|
|
})
|
|
.collect();
|
|
|
|
group.throughput(Throughput::Elements(num_samples as u64));
|
|
|
|
group.bench_function("single_sample_update", |b| {
|
|
b.iter(|| {
|
|
// Placeholder: simulate single-sample SGD update
|
|
let (input, target) = &samples[0];
|
|
let learning_rate = 0.01;
|
|
|
|
// Forward
|
|
let mut output = vec![0.0f32; dim];
|
|
for i in 0..dim {
|
|
for j in 0..dim {
|
|
output[i] += input[j] * 0.01;
|
|
}
|
|
}
|
|
|
|
// Compute gradients
|
|
let mut gradients = vec![0.0f32; dim];
|
|
for i in 0..dim {
|
|
gradients[i] = 2.0 * (output[i] - target[i]);
|
|
}
|
|
|
|
// Update (simulated)
|
|
let weight_update: f32 = gradients.iter().map(|g| g * learning_rate).sum();
|
|
|
|
weight_update
|
|
});
|
|
});
|
|
|
|
group.bench_function("batch_update_100", |b| {
|
|
b.iter(|| {
|
|
// Placeholder: simulate batch update
|
|
let mut total_gradient = vec![0.0f32; dim];
|
|
|
|
for (input, target) in &samples {
|
|
// Forward
|
|
let mut output = vec![0.0f32; dim];
|
|
for i in 0..dim {
|
|
for j in 0..dim {
|
|
output[i] += input[j] * 0.01;
|
|
}
|
|
}
|
|
|
|
// Accumulate gradients
|
|
for i in 0..dim {
|
|
total_gradient[i] += 2.0 * (output[i] - target[i]) / (num_samples as f32);
|
|
}
|
|
}
|
|
|
|
total_gradient
|
|
});
|
|
});
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_experience_replay(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("experience_replay");
|
|
|
|
let dim = 64;
|
|
let buffer_size = 10000;
|
|
let batch_size = 32;
|
|
|
|
// Pre-fill buffer
|
|
let buffer: Vec<(Vec<f32>, Vec<f32>)> = (0..buffer_size)
|
|
.map(|i| {
|
|
(random_vector(dim, i as u64), random_vector(dim, (i + 10000) as u64))
|
|
})
|
|
.collect();
|
|
|
|
group.bench_function("uniform_sampling", |b| {
|
|
b.iter(|| {
|
|
// Uniform random sampling
|
|
let mut batch = Vec::with_capacity(batch_size);
|
|
for i in 0..batch_size {
|
|
let idx = (i * 313 + 7) % buffer_size; // Pseudo-random
|
|
batch.push(&buffer[idx]);
|
|
}
|
|
batch
|
|
});
|
|
});
|
|
|
|
group.bench_function("prioritized_sampling", |b| {
|
|
// Priorities (simulated)
|
|
let priorities: Vec<f32> = (0..buffer_size)
|
|
.map(|i| 1.0 + (i as f32 / buffer_size as f32))
|
|
.collect();
|
|
let total_priority: f32 = priorities.iter().sum();
|
|
|
|
b.iter(|| {
|
|
// Prioritized sampling (simplified)
|
|
let mut batch = Vec::with_capacity(batch_size);
|
|
let segment = total_priority / batch_size as f32;
|
|
|
|
for i in 0..batch_size {
|
|
let target = (i as f32 + 0.5) * segment;
|
|
let mut cumsum = 0.0;
|
|
for (idx, &p) in priorities.iter().enumerate() {
|
|
cumsum += p;
|
|
if cumsum >= target {
|
|
batch.push(&buffer[idx]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
batch
|
|
});
|
|
});
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_meta_learning(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("meta_learning");
|
|
|
|
let dim = 32;
|
|
let num_tasks = 5;
|
|
let shots_per_task = 5;
|
|
|
|
// Generate task data
|
|
let tasks: Vec<Vec<(Vec<f32>, Vec<f32>)>> = (0..num_tasks)
|
|
.map(|t| {
|
|
(0..shots_per_task)
|
|
.map(|s| {
|
|
let input = random_vector(dim, (t * 100 + s) as u64);
|
|
let target = random_vector(dim, (t * 100 + s + 50) as u64);
|
|
(input, target)
|
|
})
|
|
.collect()
|
|
})
|
|
.collect();
|
|
|
|
group.bench_function("inner_loop_adaptation", |b| {
|
|
b.iter(|| {
|
|
// MAML-style inner loop (simplified)
|
|
let task = &tasks[0];
|
|
let inner_lr = 0.01;
|
|
let inner_steps = 5;
|
|
|
|
let mut adapted_weights = vec![0.0f32; dim * dim];
|
|
|
|
for _ in 0..inner_steps {
|
|
let mut gradient = vec![0.0f32; dim * dim];
|
|
|
|
for (input, target) in task {
|
|
// Forward
|
|
let mut output = vec![0.0f32; dim];
|
|
for i in 0..dim {
|
|
for j in 0..dim {
|
|
output[i] += input[j] * adapted_weights[i * dim + j];
|
|
}
|
|
}
|
|
|
|
// Backward
|
|
for i in 0..dim {
|
|
for j in 0..dim {
|
|
gradient[i * dim + j] += 2.0 * (output[i] - target[i]) * input[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update
|
|
for (w, g) in adapted_weights.iter_mut().zip(gradient.iter()) {
|
|
*w -= inner_lr * g / (shots_per_task as f32);
|
|
}
|
|
}
|
|
|
|
adapted_weights
|
|
});
|
|
});
|
|
|
|
group.bench_function("outer_loop_update", |b| {
|
|
b.iter(|| {
|
|
// Meta-gradient computation (simplified)
|
|
let outer_lr = 0.001;
|
|
let mut meta_gradient = vec![0.0f32; dim * dim];
|
|
|
|
for task in &tasks {
|
|
// Simulate adapted performance gradient
|
|
for (input, target) in task {
|
|
for i in 0..dim {
|
|
for j in 0..dim {
|
|
meta_gradient[i * dim + j] += input[j] * target[i] * 0.001;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Scale by learning rate
|
|
for g in &mut meta_gradient {
|
|
*g *= outer_lr / (num_tasks as f32);
|
|
}
|
|
|
|
meta_gradient
|
|
});
|
|
});
|
|
|
|
group.finish();
|
|
}
|
|
|
|
criterion_group!(
|
|
benches,
|
|
bench_micro_lora,
|
|
bench_sona_adaptation,
|
|
bench_online_learning,
|
|
bench_experience_replay,
|
|
bench_meta_learning
|
|
);
|
|
|
|
criterion_main!(benches);
|