diff --git a/c/glm.c b/c/glm.c index 3dec2aa..a35ca54 100644 --- a/c/glm.c +++ b/c/glm.c @@ -896,6 +896,11 @@ static float g_temp=-1; /* TEMP: temperatura di sampling sui TOKEN. <0 = auto ( static float g_nuc=0.95f;/* NUCLEUS: top-p sul vocabolario (default dal generation_config GLM-5.2) */ static int g_topk=0; /* TOPK=n -> usa n expert/token invece di config (ricerca: meno disco) */ static float g_topp=0; /* TOPP=p (0..1) -> top-p adattivo: tieni gli expert fino a peso cumulato p */ +static int g_expert_budget=0; /* EXPERT_BUDGET=N -> cap distinct experts loaded per layer across the + * batch-union. Reduces disk I/O on cold/low-RAM hosts by dropping the + * lowest-gate-weight experts from the cross-position union. MoE-Spec + * (arXiv 2602.16052): top-32 of 64 capture 93% routing weight. */ +static int64_t g_budget_dropped=0; /* total experts dropped by EXPERT_BUDGET across all layers */ /* CACHE_ROUTE (paper 2412.00099 max-rank): opt-in only. Keep true top-J always; * fill remaining slots preferring pin∪LRU experts ranked within top-M (or mass ROUTE_P). */ static int g_cache_route=0; @@ -2413,6 +2418,67 @@ static void moe(Model *m, Layer *l, int layer, float *x, int S, float *out, int int e=idxs[(int64_t)s*K+kk]; if(!seen[e]){ seen[e]=1; uniq[nu++]=e; } } + /* EXPERT_BUDGET: cap distinct experts per layer to reduce disk I/O on cold/low-RAM + * hosts. MISS-AWARE: always keep cache hits (pin/LRU — they're free, no disk I/O), + * only drop from misses. From the misses, keep the highest-aggregate-gate-weight + * ones up to the budget; drop the rest from idxs[] so they're never loaded. + * (MoE-Spec arXiv 2602.16052: top-32 of 64 capture 93% routing weight.) + * Complementary to TOPP (per-position) — this trims cross-position. */ + if(g_expert_budget>0 && nu>g_expert_budget){ + /* compute aggregate gate weight per unique expert */ + float *wsum=falloc(nu); for(int j=0;jpin[layer]; + for(int z=0;znpin[layer];z++) if(P[z].eid==eid){ found=1; break; } + if(!found){ ESlot *Sl=m->ecache[layer]; int nn=m->ecn[layer]; + for(int z=0;zbv){ bv=wsum[j]; best=j; } + if(best<0) break; keep[best]=1; nkeep++; + } + /* build a lookup: for each expert id, is it kept? (reuse seen[]) */ + memset(seen,0,(size_t)E); + for(int j=0;jnorm_topk && w>0){ + float sm=0; for(int kk=0;kkrouted_scale; + } + } + } + /* compact uniq[] to kept experts only */ + int nu2=0; + for(int j=0;jereq/produced:0.0, (produced&&nsp)?(double)m->ereq/produced/nsp:0.0, nsp, c->topk, g_topk, g_topp); if(g_cache_route) printf(" | CACHE_ROUTE J=%d M=%d P=%.2f alpha=%.2f", g_route_j, g_route_m, g_route_p, g_route_alpha); + if(g_expert_budget) printf(" | EXPERT_BUDGET=%d (dropped %lld experts, ~%.1f GB I/O saved)", g_expert_budget, (long long)g_budget_dropped, g_budget_dropped*18.9e6/1e9); printf("\n"); printf("speculation: %.2f tokens/forward (%llu forwards per %llu tokens) | MTP acceptance %.0f%% (%llu/%llu)\n", m->n_fw?(double)m->n_emit/m->n_fw:1.0, (unsigned long long)m->n_fw, (unsigned long long)m->n_emit, @@ -4926,6 +4993,7 @@ int main(int argc, char **argv){ if(g_mmap) fprintf(stderr,"[MMAP] expert = viste zero-copy nei file (page cache = cache)\n"); g_topk = getenv("TOPK")?atoi(getenv("TOPK")):0; g_topp = getenv("TOPP")?atof(getenv("TOPP")):0; + g_expert_budget = getenv("EXPERT_BUDGET")?atoi(getenv("EXPERT_BUDGET")):0; g_cache_route = getenv("CACHE_ROUTE")?atoi(getenv("CACHE_ROUTE")):0; g_route_j = getenv("ROUTE_J")?atoi(getenv("ROUTE_J")):2; g_route_m = getenv("ROUTE_M")?atoi(getenv("ROUTE_M")):12;