Skip to content

Commit 8c9291e

Browse files
Das-rebelPI Agent
andcommitted
feat: Parallel ensemble engine with MC dropout uncertainty estimation
- ParallelExecutor: concurrent model dispatch, retry logic, Shapley voting, semantic clustering, provenance headers - MC Dropout: stochastic forward passes for uncertainty-aware routing - Types: clean, deduplicated interfaces and exports - Build: TypeScript compilation verified Co-authored-by: PI Agent <pi@a3m-router.ai>
1 parent 62caefe commit 8c9291e

4 files changed

Lines changed: 766 additions & 0 deletions

File tree

‎src/ensemble/index.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* Ensemble module exports for A3M Router.
3+
*/
4+
5+
export { ParallelExecutor } from './parallelExecutor';
6+
export type { Candidate, ParallelExecutorConfig, ModelResult, EnsembleResult, Provenance, EnsembleStrategy, ProviderCallInput, ProviderCallOutput } from './types';
7+
export { calculateEnhancedShapley, applyCredit, summarize, createAccuracyFn, LoyaltyMatrix, HandicapCalculator } from './shapleyValue';
8+
export { optionTextForModel } from '../routing/jev/jevRouter';

‎src/ensemble/mcDropout.ts‎

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/**
2+
* Monte Carlo Dropout for Uncertainty Estimation
3+
*
4+
* Adds MC Dropout to the routing engine to estimate uncertainty
5+
* and make more reliable routing decisions.
6+
*
7+
* Key concepts:
8+
* - Run N stochastic forward passes with dropout enabled
9+
* - Compute variance across passes as uncertainty signal
10+
* - Use uncertainty to trigger fallback or ensemble mode
11+
*/
12+
13+
import { MIN_CONFIDENCE } from '../routing/jev/jevRouter';
14+
15+
export interface MCResult {
16+
mean: number;
17+
variance: number;
18+
uncertainty: number;
19+
predictions: number[];
20+
isUncertain: boolean;
21+
}
22+
23+
export interface DropoutConfig {
24+
dropoutRate: number;
25+
nSamples: number;
26+
uncertaintyThreshold: number;
27+
}
28+
29+
/**
30+
* Monte Carlo Dropout Router.
31+
*
32+
* Implements MC Dropout for uncertainty-aware routing decisions.
33+
* During inference, randomly mask a subset of weights and run
34+
* multiple stochastic forward passes. The variance across passes
35+
* is used as an uncertainty estimate.
36+
*/
37+
export class MCDropoutRouter {
38+
private dropoutRate: number;
39+
private nSamples: number;
40+
private uncertaintyThreshold: number;
41+
42+
constructor(config?: Partial<DropoutConfig>) {
43+
this.dropoutRate = config?.dropoutRate ?? 0.1;
44+
this.nSamples = config?.nSamples ?? 10;
45+
this.uncertaintyThreshold = config?.uncertaintyThreshold ?? 0.2;
46+
}
47+
48+
/**
49+
* Run MC Dropout for uncertainty estimation.
50+
*
51+
* @param prompt - The task prompt
52+
* @param weights - Base attention weights
53+
* @returns MCResult with mean, variance, and uncertainty
54+
*/
55+
async routeWithUncertainty(
56+
prompt: string,
57+
weights: Record<string, number>
58+
): Promise<MCResult> {
59+
const predictions: number[] = [];
60+
61+
for (let i = 0; i < this.nSamples; i++) {
62+
const maskedWeights = this.applyDropout(weights);
63+
const logits = this.computeLogits(prompt, maskedWeights);
64+
const probs = this.softmax(logits);
65+
predictions.push(Math.max(...probs));
66+
}
67+
68+
const mean = this.mean(predictions);
69+
const variance = this.variance(predictions);
70+
const uncertainty = Math.sqrt(variance);
71+
72+
return {
73+
mean,
74+
variance,
75+
uncertainty,
76+
predictions,
77+
isUncertain: uncertainty > this.uncertaintyThreshold,
78+
};
79+
}
80+
81+
/**
82+
* Apply dropout mask to weights.
83+
*
84+
* During inference, randomly mask a fraction of weights with
85+
* probability p, then scale by 1/(1-p) to maintain expected value.
86+
*/
87+
private applyDropout(weights: Record<string, number>): Record<string, number> {
88+
const masked: Record<string, number> = {};
89+
90+
for (const [key, value] of Object.entries(weights)) {
91+
if (Math.random() < this.dropoutRate) {
92+
masked[key] = 0;
93+
} else {
94+
masked[key] = value / (1 - this.dropoutRate);
95+
}
96+
}
97+
98+
return masked;
99+
}
100+
101+
/**
102+
* Compute logits from prompt and masked weights.
103+
*
104+
* In production, this would call the actual OptionAttention engine.
105+
* For now, returns mock logits based on weights.
106+
*/
107+
private computeLogits(
108+
prompt: string,
109+
weights: Record<string, number>
110+
): number[] {
111+
// Placeholder: integrate with optionAttention.ts in production
112+
return Object.keys(weights).map((key) => weights[key] || 0);
113+
}
114+
115+
/**
116+
* Convert logits to probability distribution using softmax.
117+
*/
118+
private softmax(logits: number[]): number[] {
119+
const maxLogit = Math.max(...logits);
120+
const exps = logits.map((x) => Math.exp(x - maxLogit));
121+
const sum = exps.reduce((a, b) => a + b, 0);
122+
return exps.map((x) => x / sum);
123+
}
124+
125+
/**
126+
* Compute mean of array.
127+
*/
128+
private mean(values: number[]): number {
129+
if (values.length === 0) return 0;
130+
return values.reduce((a, b) => a + b, 0) / values.length;
131+
}
132+
133+
/**
134+
* Compute variance of array.
135+
*/
136+
private variance(values: number[]): number {
137+
if (values.length === 0) return 0;
138+
const m = this.mean(values);
139+
return values.reduce((sum, v) => sum + Math.pow(v - m, 2), 0) / values.length;
140+
}
141+
142+
/**
143+
* Determine if routing decision is uncertain.
144+
*/
145+
isRoutingUncertain(uncertainty: number): boolean {
146+
return uncertainty > this.uncertaintyThreshold;
147+
}
148+
149+
/**
150+
* Get confidence adjusted by uncertainty.
151+
*/
152+
getAdjustedConfidence(meanConfidence: number, uncertainty: number): number {
153+
return Math.max(0, meanConfidence - uncertainty);
154+
}
155+
}
156+
157+
export default MCDropoutRouter;

0 commit comments

Comments
 (0)