git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
314 lines
8.2 KiB
Markdown
314 lines
8.2 KiB
Markdown
# ruvector-learning-wasm
|
|
|
|
Ultra-fast MicroLoRA adaptation for WASM - rank-2 LoRA with <100us latency for per-operator learning.
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
npm install ruvector-learning-wasm
|
|
```
|
|
|
|
## Overview
|
|
|
|
This package provides Low-Rank Adaptation (LoRA) matrices optimized for WebAssembly execution. It enables real-time per-operator-type learning in query optimization systems with minimal latency overhead.
|
|
|
|
### Key Features
|
|
|
|
- **Rank-2 LoRA**: Minimal parameter count (2d parameters per adapter)
|
|
- **Per-Operator Scoping**: Separate adapters for 17 different operator types
|
|
- **<100us Adaptation**: Instant weight updates for real-time learning
|
|
- **WASM-Optimized**: Compiled to WebAssembly for near-native performance
|
|
- **Zero-Allocation Hot Paths**: Pre-allocated buffers for performance-critical operations
|
|
|
|
## JavaScript API
|
|
|
|
### WasmMicroLoRA
|
|
|
|
The main LoRA engine for single-adapter use cases.
|
|
|
|
```typescript
|
|
import init, { WasmMicroLoRA } from 'ruvector-learning-wasm';
|
|
|
|
// Initialize WASM module
|
|
await init();
|
|
|
|
// Create a new MicroLoRA engine
|
|
const lora = new WasmMicroLoRA(
|
|
256, // dim: Embedding dimension (max 256)
|
|
0.1, // alpha: Scaling factor
|
|
0.01 // learning_rate: Learning rate for adaptation
|
|
);
|
|
|
|
// Forward pass with typed array
|
|
const input = new Float32Array(256).fill(1.0);
|
|
const output = lora.forward_array(input);
|
|
|
|
// Adapt with gradient
|
|
const gradient = new Float32Array(256).fill(0.1);
|
|
lora.adapt_array(gradient);
|
|
|
|
// Get statistics
|
|
console.log('Forward count:', lora.forward_count());
|
|
console.log('Adapt count:', lora.adapt_count());
|
|
console.log('Delta norm:', lora.delta_norm());
|
|
console.log('Parameter count:', lora.param_count());
|
|
|
|
// Reset engine
|
|
lora.reset();
|
|
```
|
|
|
|
#### Zero-Allocation API
|
|
|
|
For performance-critical loops, use the buffer-based API:
|
|
|
|
```typescript
|
|
const lora = new WasmMicroLoRA(256, 0.1, 0.01);
|
|
|
|
// Get buffer pointers
|
|
const inputPtr = lora.get_input_ptr();
|
|
const outputPtr = lora.get_output_ptr();
|
|
const dim = lora.dim();
|
|
|
|
// Create views into WASM memory
|
|
const memory = new Float32Array(lora.memory.buffer);
|
|
const inputView = new Float32Array(memory.buffer, inputPtr, dim);
|
|
const outputView = new Float32Array(memory.buffer, outputPtr, dim);
|
|
|
|
// Write input directly
|
|
inputView.set(myInputData);
|
|
|
|
// Forward pass (zero allocation)
|
|
lora.forward();
|
|
|
|
// Read output directly
|
|
const result = outputView.slice();
|
|
|
|
// Adapt using input buffer as gradient
|
|
lora.adapt();
|
|
|
|
// Adapt with reward (for RL)
|
|
lora.adapt_with_reward(0.5); // improvement ratio
|
|
```
|
|
|
|
### WasmScopedLoRA
|
|
|
|
Per-operator-type LoRA manager with 17 specialized adapters plus category fallback.
|
|
|
|
```typescript
|
|
import init, { WasmScopedLoRA } from 'ruvector-learning-wasm';
|
|
|
|
await init();
|
|
|
|
const scopedLora = new WasmScopedLoRA(
|
|
256, // dim
|
|
0.1, // alpha
|
|
0.01 // learning_rate
|
|
);
|
|
|
|
// Operator types (0-16)
|
|
const HNSW_SCAN = 2;
|
|
const HASH_JOIN = 5;
|
|
const FILTER = 9;
|
|
|
|
// Forward for specific operator
|
|
const input = new Float32Array(256).fill(1.0);
|
|
const output = scopedLora.forward_array(HNSW_SCAN, input);
|
|
|
|
// Adapt for specific operator
|
|
const gradient = new Float32Array(256).fill(0.1);
|
|
scopedLora.adapt_array(FILTER, gradient);
|
|
|
|
// Per-operator statistics
|
|
console.log('HNSW forward count:', scopedLora.forward_count(HNSW_SCAN));
|
|
console.log('Filter adapt count:', scopedLora.adapt_count(FILTER));
|
|
console.log('Filter delta norm:', scopedLora.delta_norm(FILTER));
|
|
|
|
// Total statistics
|
|
console.log('Total forwards:', scopedLora.total_forward_count());
|
|
console.log('Total adapts:', scopedLora.total_adapt_count());
|
|
|
|
// Get operator name
|
|
console.log(WasmScopedLoRA.scope_name(HNSW_SCAN)); // "HnswScan"
|
|
|
|
// Enable/disable category fallback (default: enabled)
|
|
scopedLora.set_category_fallback(true);
|
|
|
|
// Reset specific operator or all
|
|
scopedLora.reset_scope(FILTER);
|
|
scopedLora.reset_all();
|
|
```
|
|
|
|
#### Operator Types
|
|
|
|
| Value | Name | Category |
|
|
|-------|------|----------|
|
|
| 0 | SeqScan | Scan |
|
|
| 1 | IndexScan | Scan |
|
|
| 2 | HnswScan | Scan |
|
|
| 3 | IvfFlatScan | Scan |
|
|
| 4 | NestedLoopJoin | Join |
|
|
| 5 | HashJoin | Join |
|
|
| 6 | MergeJoin | Join |
|
|
| 7 | Aggregate | Aggregation |
|
|
| 8 | GroupBy | Aggregation |
|
|
| 9 | Filter | Transform |
|
|
| 10 | Project | Transform |
|
|
| 11 | Sort | Order |
|
|
| 12 | Limit | Order |
|
|
| 13 | VectorDistance | Vector |
|
|
| 14 | Rerank | Vector |
|
|
| 15 | Materialize | Utility |
|
|
| 16 | Result | Utility |
|
|
|
|
### WasmTrajectoryBuffer
|
|
|
|
Trajectory recording for reinforcement learning and pattern analysis.
|
|
|
|
```typescript
|
|
import init, { WasmTrajectoryBuffer } from 'ruvector-learning-wasm';
|
|
|
|
await init();
|
|
|
|
const buffer = new WasmTrajectoryBuffer(
|
|
1000, // capacity: max trajectories to store
|
|
256 // embedding_dim
|
|
);
|
|
|
|
// Record a trajectory
|
|
const embedding = new Float32Array(256).fill(1.0);
|
|
buffer.record(
|
|
embedding,
|
|
2, // op_type: HnswScan
|
|
0, // attention_type
|
|
100.0, // execution_ms
|
|
150.0 // baseline_ms (improvement = 150/100 - 1 = 0.5)
|
|
);
|
|
|
|
// Get statistics
|
|
console.log('Total count:', buffer.total_count());
|
|
console.log('Buffer length:', buffer.len());
|
|
console.log('Mean improvement:', buffer.mean_improvement());
|
|
console.log('Best improvement:', buffer.best_improvement());
|
|
console.log('Success rate:', buffer.success_rate());
|
|
console.log('Best attention type:', buffer.best_attention());
|
|
console.log('Variance:', buffer.variance());
|
|
|
|
// Filter by quality
|
|
console.log('High quality count:', buffer.high_quality_count(0.5));
|
|
|
|
// Filter by operator
|
|
console.log('HnswScan trajectories:', buffer.count_by_operator(2));
|
|
|
|
// Reset buffer
|
|
buffer.reset();
|
|
```
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Input Embedding (d-dim)
|
|
|
|
|
v
|
|
+---------+
|
|
| A: d x 2 | Down projection
|
|
+---------+
|
|
|
|
|
v
|
|
+---------+
|
|
| B: 2 x d | Up projection (initialized to zero)
|
|
+---------+
|
|
|
|
|
v
|
|
Delta W = alpha * (A @ B)
|
|
|
|
|
v
|
|
Output = Input + Delta W
|
|
```
|
|
|
|
### Category Fallback
|
|
|
|
When an operator has fewer than 10 adaptations, the output is blended with the category adapter based on relative experience:
|
|
|
|
```
|
|
weight = min(operator_adapt_count / 10, 1.0)
|
|
output = operator_output * weight + category_output * (1 - weight)
|
|
```
|
|
|
|
This enables transfer learning between similar operators (e.g., all scan types share Scan category knowledge).
|
|
|
|
## Performance
|
|
|
|
- **Forward pass**: ~50us for 256-dim embeddings
|
|
- **Adaptation**: ~30us for gradient update
|
|
- **Memory**: ~2KB per LoRA pair (A + B matrices)
|
|
- **WASM size**: ~39KB (release build)
|
|
|
|
## TypeScript Types
|
|
|
|
Full TypeScript definitions are included in the package:
|
|
|
|
```typescript
|
|
export class WasmMicroLoRA {
|
|
constructor(dim?: number, alpha?: number, learning_rate?: number);
|
|
get_input_ptr(): number;
|
|
get_output_ptr(): number;
|
|
dim(): number;
|
|
forward(): void;
|
|
forward_array(input: Float32Array): Float32Array;
|
|
adapt(): void;
|
|
adapt_array(gradient: Float32Array): void;
|
|
adapt_with_reward(improvement: number): void;
|
|
reset(): void;
|
|
forward_count(): bigint;
|
|
adapt_count(): bigint;
|
|
delta_norm(): number;
|
|
param_count(): number;
|
|
}
|
|
|
|
export class WasmScopedLoRA {
|
|
constructor(dim?: number, alpha?: number, learning_rate?: number);
|
|
get_input_ptr(): number;
|
|
get_output_ptr(): number;
|
|
forward(op_type: number): void;
|
|
forward_array(op_type: number, input: Float32Array): Float32Array;
|
|
adapt(op_type: number): void;
|
|
adapt_array(op_type: number, gradient: Float32Array): void;
|
|
adapt_with_reward(op_type: number, improvement: number): void;
|
|
reset_scope(op_type: number): void;
|
|
reset_all(): void;
|
|
forward_count(op_type: number): bigint;
|
|
adapt_count(op_type: number): bigint;
|
|
delta_norm(op_type: number): number;
|
|
total_forward_count(): bigint;
|
|
total_adapt_count(): bigint;
|
|
set_category_fallback(enabled: boolean): void;
|
|
static scope_name(op_type: number): string;
|
|
}
|
|
|
|
export class WasmTrajectoryBuffer {
|
|
constructor(capacity?: number, embedding_dim?: number);
|
|
record(
|
|
embedding: Float32Array,
|
|
op_type: number,
|
|
attention_type: number,
|
|
execution_ms: number,
|
|
baseline_ms: number
|
|
): void;
|
|
total_count(): bigint;
|
|
len(): number;
|
|
is_empty(): boolean;
|
|
mean_improvement(): number;
|
|
best_improvement(): number;
|
|
success_rate(): number;
|
|
best_attention(): number;
|
|
variance(): number;
|
|
reset(): void;
|
|
high_quality_count(threshold: number): number;
|
|
count_by_operator(op_type: number): number;
|
|
}
|
|
```
|
|
|
|
## License
|
|
|
|
MIT OR Apache-2.0
|