"""Compare exact current points across Mimi standard/MC and CPC MC controls.""" from collections import Counter import csv import hashlib import json from pathlib import Path HERE = Path(__file__).resolve().parent ROOT = HERE.parents[1] OUT = HERE / "results/mimi-comparison" def sha(path): return hashlib.sha256(path.read_bytes()).hexdigest() def read(path): with path.open(encoding="utf-8-sig", newline="") as f: return list(csv.DictReader(f)) def metrics(rows, field): c = Counter((int(r['can_reply_now']), int(float(r[field]) > .5)) for r in rows) tn, fp, fn, tp = c[0,0], c[0,1], c[1,0], c[1,1] return dict(n=len(rows), correct=tn+tp, tn=tn, fp=fp, fn=fn, tp=tp, accuracy=(tn+tp)/len(rows), false_reply_rate=fp/(fp+tn), false_hold_rate=fn/(fn+tp)) def main(): dirs = ['mimi-standard', 'mimi-mc', 'user-only'] labels = ROOT / 'labels/EOT标注/工作数据/eot_labels.csv' summaries = {d: json.loads((HERE/'results'/d/'summary.json').read_text()) for d in dirs} points = {d: {(r['call_id'], int(r['decision_ms'])):r for r in read(HERE/'results'/d/'predictions.csv')} for d in dirs} current = {(r['call_id'], int(r['decision_ms'])):r['can_reply_now'] for r in read(labels) if r['can_reply_now'] in ('0','1')} assert current and all(set(p)==set(current) for p in points.values()) assert all(s['provenance']['label_sha256']==sha(labels) for s in summaries.values()) assert summaries['mimi-standard']['provenance']['mc'] is False assert summaries['mimi-mc']['provenance']['mc'] is True audio_hashes = summaries['mimi-standard']['provenance']['audio_sha256'] assert all(s['provenance']['audio_sha256']==audio_hashes for s in summaries.values()) rows = [] for key, label in sorted(current.items()): standard, mc, cpc = [points[d][key] for d in dirs] assert all(r['can_reply_now']==label for r in (standard,mc,cpc)) assert standard['cpc_mc_stereo_score']==mc['cpc_mc_stereo_score']==cpc['stereo_can_reply_score'] rows.append(dict(call_id=key[0],decision_ms=key[1],can_reply_now=label, mimi_standard=float(standard['can_reply_score']),mimi_mc=float(mc['can_reply_score']), cpc_mc_stereo=float(cpc['stereo_can_reply_score']),cpc_mc_user_only=float(cpc['can_reply_score']))) models = { 'cpc_mc_stereo':'CPC 降噪版(双声道)', 'cpc_mc_user_only':'CPC 降噪版(机器人静音)', 'mimi_standard':'Mimi 标准版(双声道)', 'mimi_mc':'Mimi 降噪版(双声道)', } result = {key:metrics(rows,key) for key in models} base = result['cpc_mc_stereo']['accuracy'] for value in result.values(): value['accuracy_delta_pp_vs_cpc_mc_stereo'] = (value['accuracy']-base)*100 value['relative_accuracy_change_vs_cpc_mc_stereo'] = (value['accuracy']-base)/base paired = {} for key in ('mimi_standard','mimi_mc'): paired[key] = dict( fixed=sum((r['cpc_mc_stereo']>.5)!=bool(int(r['can_reply_now'])) and (r[key]>.5)==bool(int(r['can_reply_now'])) for r in rows), regressed=sum((r['cpc_mc_stereo']>.5)==bool(int(r['can_reply_now'])) and (r[key]>.5)!=bool(int(r['can_reply_now'])) for r in rows)) summary = dict(threshold=.5,rule='1 - p_now[user] > 0.5',n=len(rows),positive=sum(r['can_reply_now']=='1' for r in rows), models=result,paired_vs_cpc_mc_stereo=paired, per_call={c:{m:metrics([r for r in rows if r['call_id']==c],m) for m in models} for c in sorted(audio_hashes)}, sources={d:{'summary_sha256':sha(HERE/'results'/d/'summary.json'),'predictions_sha256':sha(HERE/'results'/d/'predictions.csv')} for d in dirs}, label_sha256=sha(labels),audio_sha256=audio_hashes, limitations=['Single seed 42 with exact-repeat witness, not multiple-seed statistics.', 'Only 44 selected points in six calls; descriptive comparison, not a held-out generalization claim.', 'Mimi standard/MC share the same encoder and framing; CPC uses a different encoder and native 100ms framing.', 'All scores are activity-projection mappings; no endpointing-policy or full-dialogue cutoff/latency claims.']) OUT.mkdir(parents=True,exist_ok=True) with (OUT/'comparison-points.csv').open('w',encoding='utf-8-sig',newline='') as f: writer=csv.DictWriter(f,fieldnames=list(rows[0]));writer.writeheader();writer.writerows(rows) (OUT/'comparison-summary.json').write_text(json.dumps(summary,ensure_ascii=False,indent=2)+'\n') text=['MaAI Mimi 与 CPC 对比(相同当前 44 点,阈值严格 > 0.5)','', '模型 | 正确数 | 准确率 | 误放行 FP/22 | 误阻止 FN/22 | 相对 CPC 双声道准确率变化'] for key,name in models.items(): m=result[key] text.append(f"{name} | {m['correct']}/{m['n']} | {m['accuracy']:.2%} | {m['fp']}/22 | {m['fn']}/22 | {m['accuracy_delta_pp_vs_cpc_mc_stereo']:+.2f} 个百分点(相对 {m['relative_accuracy_change_vs_cpc_mc_stereo']:+.2%})") text+=['','1. 标准版与降噪版的结果差异可直接从上表查看;二者使用相同 Mimi 编码器、双声道输入及 80 ms 帧,变化来自所选 VAP 权重。', '2. 与 CPC 比较时同时存在编码器、checkpoint 和原生帧率差异;不把结果归结为 Mimi 编码器的单独因果效果。', '3. 固定种子重复结果一致,但没有多种子误差条;六通录音的 44 个选定点不足以证明泛化优劣。', '', '建议下一步:扩充并核验按通话隔离的测试集,在独立验证集上选择阈值;若要单独研究编码器,补充标准/降噪与 CPC/Mimi 的完整交叉配置。'] (OUT/'对比分析.txt').write_text('\n'.join(text)+'\n') print('\n'.join(text)) if __name__=='__main__': main()