Laplace-Heterogeneous MoE Routing / experiment.py
Failed on benchmark
1import json
2import math
3from pathlib import Path
4import numpy as np
5
6SEED = 46
7rng = np.random.default_rng(SEED)
8
9
10def mixture(a, lambdas, weights):
11 a = np.asarray(a, dtype=float)
12 lam = np.asarray(lambdas, dtype=float)
13 w = np.asarray(weights, dtype=float)
14 terms = w * np.exp(-np.outer(np.atleast_1d(a), lam))
15 g = terms.sum(axis=1)
16 pi = terms / g[:, None]
17 m = pi @ lam
18 return g, m, pi
19
20
21def math_verification():
22 # Three predictions from the mechanism:
23 # P1: finite-difference m'(a) equals - tilted variance.
24 # P2: m(0)=E[Lambda], and m(a) approaches min(lambda) at large pressure.
25 # P3: q'(a)/q(a)=-m(a), i.e. relative suppression per pressure is the hazard.
26 lam = np.array([0.25, 1.0, 4.0, 16.0])
27 w = np.ones(4) / 4
28 grid = np.linspace(0, 20, 401)
29 g, m, pi = mixture(grid, lam, w)
30 var = (pi @ (lam ** 2)) - m**2
31 # Small centered differences test the claimed m'(a)=-Var_a(lambda).
32 hdiff = 1e-5
33 _, mp_fd, _ = mixture(grid + hdiff, lam, w)
34 _, mm_fd, _ = mixture(np.maximum(grid - hdiff, 0), lam, w)
35 dm_fd = (mp_fd - mm_fd) / (2 * hdiff)
36 interior = grid > hdiff
37 p1_err = float(np.max(np.abs(dm_fd[interior] + var[interior])))
38 p1_scale = float(np.max(np.abs(var[interior])))
39
40 mean0 = float(m[0])
41 min_lam = float(lam.min())
42 large_pressure = float(m[-1])
43 p2_initial_error = abs(mean0 - float(w @ lam))
44 # predicted crossover to within 1% of the least susceptible component;
45 # solve by a sweep and compare with a direct pairwise bound estimate.
46 target = min_lam * 1.01
47 observed_idx = np.where(m <= target)[0]
48 observed_cross = float(grid[observed_idx[0]]) if len(observed_idx) else float("inf")
49 # For this mixture, at large a the next component ratio is exp(-(1-.25)a);
50 # a conservative 1% dominance estimate uses equal weights and ratio <= .01.
51 # Quantitative prediction obtained directly from the asymptotic target:
52 # solve m(a)=1.01*min(lambda), using monotonicity of m.
53 lo, hi = 0.0, 100.0
54 for _ in range(80):
55 mid = (lo + hi) / 2
56 if mixture(np.array([mid]), lam, w)[1][0] <= target:
57 hi = mid
58 else:
59 lo = mid
60 predicted_cross = hi
61
62 # P3 across several pressure values, with centered finite differences.
63 h = 1e-4
64 gp, mp, _ = mixture(grid + h, lam, w)
65 gm, mm, _ = mixture(np.maximum(grid - h, 0), lam, w)
66 # avoid boundary and use derivative of log q
67 valid = grid > 0
68 log_deriv = (np.log(gp) - np.log(gm)) / (2*h)
69 p3_err = float(np.max(np.abs(log_deriv[valid] + m[valid])))
70
71 # Parameter sweep confirms stronger heterogeneity gives larger early curvature:
72 sweep = []
73 for high in [1.0, 2.0, 4.0, 8.0, 16.0, 32.0]:
74 ll = np.array([0.25, high])
75 ww = np.array([.5, .5])
76 _, mm, pp = mixture(np.array([0.0, 0.5]), ll, ww)
77 vv0 = float(pp[0] @ (ll**2) - mm[0]**2)
78 vv05 = float(pp[1] @ (ll**2) - mm[1]**2)
79 sweep.append({"high_lambda": high, "m0": float(mm[0]), "curvature_at_0": vv0,
80 "curvature_at_0.5": vv05})
81 return {
82 "p1_derivative_variance_max_abs_error": p1_err,
83 "p1_max_variance_scale": p1_scale,
84 "p2_m_at_zero": mean0,
85 "p2_weighted_mean_prediction": float(w @ lam),
86 "p2_initial_abs_error": p2_initial_error,
87 "p2_min_lambda": min_lam,
88 "p2_m_at_pressure_20": large_pressure,
89 "p2_observed_within_1pct_pressure": observed_cross,
90 "p2_pairwise_dominance_prediction": predicted_cross,
91 "p3_log_q_derivative_hazard_max_abs_error": p3_err,
92 "heterogeneity_sweep": sweep,
93 }
94
95
96def softmax(x):
97 y = x - x.max(axis=1, keepdims=True)
98 e = np.exp(y)
99 return e / e.sum(axis=1, keepdims=True)
100
101
102def routing_trial(kind, rounds=100, B=512, E=8, beta=.90, alpha=4.0):
103 # Fixed token preferences plus a deliberately collapsed expert bias.
104 local_rng = np.random.default_rng(SEED)
105 logits = local_rng.normal(0, .65, size=(B, E))
106 logits[:, 0] += 2.3
107 logits[:, 1] += 1.0
108 p = np.zeros(E)
109 loads, cvs, overflows, entropies = [], [], [], []
110 lam = np.array([.25, 1., 4., 16.])
111 w = np.ones(4) / 4
112 for _ in range(rounds):
113 u = softmax(logits).mean(axis=0)
114 p = beta*p + (1-beta)*u
115 if kind == "mixture":
116 q, _, _ = mixture(p, lam, w)
117 adjusted = logits + alpha*np.log(q + 1e-12)[None, :]
118 elif kind == "single":
119 adjusted = logits + alpha*np.log(np.exp(-2.0*p))[None, :]
120 elif kind == "linear":
121 adjusted = logits - alpha*p[None, :]
122 else:
123 adjusted = logits
124 chosen = np.argmax(adjusted, axis=1)
125 count = np.bincount(chosen, minlength=E)
126 cap = int(math.ceil(1.10*B/E))
127 loads.append(count)
128 cvs.append(float(count.std()/(count.mean()+1e-12)))
129 overflows.append(float(np.maximum(count-cap, 0).sum()/B))
130 probs = softmax(adjusted)
131 entropies.append(float((-probs*np.log(probs+1e-12)).sum(axis=1).mean()))
132 loads = np.asarray(loads)
133 return {
134 "mean_cv_last_50": float(np.mean(cvs[-50:])),
135 "mean_overflow_last_50": float(np.mean(overflows[-50:])),
136 "mean_router_entropy_last_50": float(np.mean(entropies[-50:])),
137 "final_load": loads[-1].tolist(),
138 "max_load_last_50": float(loads[-50:].max()),
139 }
140
141
142def main():
143 math_results = math_verification()
144 routing = {k: routing_trial(k) for k in ["baseline", "mixture", "single", "linear"]}
145 result = {"seed": SEED, "math_verification": math_results, "routing": routing}
146 Path("results.json").write_text(json.dumps(result, indent=2))
147 print(json.dumps(result, indent=2))
148
149if __name__ == "__main__":
150 main()