@@ -40,6 +40,17 @@ def mean(xs):
4040 return sum (xs ) / max (len (xs ), 1 )
4141
4242
43+ def agg (dicts , keys ):
44+ """mean ± sd of each key across per-seed result dicts (stats protocol)."""
45+ out = {}
46+ for k in keys :
47+ vals = [d [k ] for d in dicts ]
48+ m = mean (vals )
49+ sd = (sum ((v - m ) ** 2 for v in vals ) / max (len (vals ) - 1 , 1 )) ** 0.5
50+ out [k ] = {"mean" : m , "sd" : sd }
51+ return out
52+
53+
4354def fact_bank (gen : RealCorpusGenerator , n : int ):
4455 """n facts with DISTINCT entities (so 'ingest all, query each' has no duplicates)."""
4556 seen , facts = set (), []
@@ -146,6 +157,7 @@ def main():
146157 ap .add_argument ("--skill" , required = True )
147158 ap .add_argument ("--squad" , action = "store_true" )
148159 ap .add_argument ("--baseline-facts" , type = int , default = 64 )
160+ ap .add_argument ("--n-seeds" , type = int , default = 3 , help = "repeat baselines/generative over N held-out draws -> mean±sd" )
149161 ap .add_argument ("--scale" , default = "8,16,32,64,128" )
150162 ap .add_argument ("--paraphrase" , action = "store_true" , help = "query with questions (content-addressable)" )
151163 ap .add_argument ("--seed" , type = int , default = 1234 )
@@ -161,22 +173,34 @@ def main():
161173 skill = MemorySkill .load (args .skill , device = args .device )
162174
163175 records = load_squad_records () if args .squad else None
164- gen = RealCorpusGenerator (records = records , split = "eval" , seed = args .seed )
165176 checkpoints = [int (x ) for x in args .scale .split ("," )]
166- bank = fact_bank (gen , max (args .baseline_facts , max (checkpoints )))
167- print (f"held-out bank: { len (bank )} distinct-entity real facts, paraphrase={ args .paraphrase } " )
168177
178+ # baselines + generative over N seeds (different held-out draws) -> mean ± sd
179+ base_runs , gen_runs = [], []
180+ for s in range (args .n_seeds ):
181+ gs = RealCorpusGenerator (records = records , split = "eval" , seed = args .seed + s )
182+ bank_s = fact_bank (gs , args .baseline_facts )
183+ base_runs .append (run_baselines (model , tok , skill , bank_s , args .device , args .paraphrase ))
184+ gen_runs .append (run_generative (model , tok , skill , bank_s , args .device , args .paraphrase ))
185+ bkeys = ["floor_lift_nats" , "memory_lift_nats" , "in_context_lift_nats" , "retrieval_at1" , "retrieval_recall_top5" ]
186+
187+ # scale + persistence once on the seed-0 bank (already worst-case over many facts)
188+ scale_bank = fact_bank (RealCorpusGenerator (records = records , split = "eval" , seed = args .seed ), max (checkpoints ))
169189 report = {
170- "n_held_out " : len (bank ),
190+ "n_held_out_entities " : len ({ f . entity for f in scale_bank } ),
171191 "paraphrase" : args .paraphrase ,
172- "baselines" : run_baselines (model , tok , skill , bank [: args .baseline_facts ], args .device , args .paraphrase ),
173- "generative" : run_generative (model , tok , skill , bank [: args .baseline_facts ], args .device , args .paraphrase ),
174- "scale" : run_scale (model , tok , skill , bank , checkpoints , args .device , args .paraphrase , NEUTRAL ),
192+ "n_seeds" : args .n_seeds ,
193+ "baselines" : agg (base_runs , bkeys ),
194+ "generative" : agg (gen_runs , ["generative_exact_match" ]),
195+ "scale" : run_scale (model , tok , skill , scale_bank , checkpoints , args .device , args .paraphrase , NEUTRAL ),
175196 }
176197 b = report ["baselines" ]
177- print (f"\n baselines (n={ b ['n' ]} ): floor { b ['floor_lift_nats' ]:.2f} | memory { b ['memory_lift_nats' ]:.2f} | "
178- f"in-context { b ['in_context_lift_nats' ]:.2f} | retrieval@1 { b ['retrieval_at1' ]:.2f} " )
179- print (f"generative EM: { report ['generative' ]['generative_exact_match' ]:.2f} " )
198+ print (f"\n baselines (n_seeds={ args .n_seeds } , mean±sd): "
199+ f"floor { b ['floor_lift_nats' ]['mean' ]:.2f} ±{ b ['floor_lift_nats' ]['sd' ]:.2f} | "
200+ f"memory { b ['memory_lift_nats' ]['mean' ]:.2f} ±{ b ['memory_lift_nats' ]['sd' ]:.2f} | "
201+ f"in-context { b ['in_context_lift_nats' ]['mean' ]:.2f} | retrieval@1 { b ['retrieval_at1' ]['mean' ]:.2f} " )
202+ print (f"generative EM: { report ['generative' ]['generative_exact_match' ]['mean' ]:.2f} "
203+ f"±{ report ['generative' ]['generative_exact_match' ]['sd' ]:.2f} " )
180204 Path (args .out ).parent .mkdir (parents = True , exist_ok = True )
181205 Path (args .out ).write_text (json .dumps (report , indent = 2 ))
182206 print (f"wrote { args .out } " )
0 commit comments