| """ |
| finalize_refs_v2 — same idea as finalize_refs.py, but: |
| |
| 1. Reads *.utmos.jsonl (fallback to plain eval_*.jsonl if missing). |
| 2. Optionally includes utmos_seg into the composite for the argmax-margin |
| ref selection (weight configurable via --utmos-weight; default 0.0). |
| 3. Drop rules (union), all thresholds configurable: |
| a. margin drop: in both variants, ≥ (min_seg_loss_frac) of segs have |
| composite_self - max(composite_others) < margin_thr |
| b. WER drop: any model on any seg has WER >= wer_drop_max |
| c. list-type drop: every seg has very short text (<= list_min_chars) |
| AND row has >= list_min_segs such segments |
| d. utmos quality drop: |
| utmos_full_ours < utmos_min_abs |
| OR utmos_full_ours < utmos_full_omni - utmos_gap_drop |
| OR (utmos_gt_full available and > 3.0) AND utmos_full_ours < utmos_gt_full - utmos_gap_gt |
| |
| Outputs (under <ckpt>/eval_v2/, overrideable): |
| refs_map.json, segments_<variant>.csv, |
| dropped_row_ids.json, dropped_by_reason.json, |
| final_scores.csv, final_summary.json |
| """ |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import csv |
| import json |
| import os |
| import re |
| from collections import defaultdict |
| from typing import Dict, List, Optional, Tuple |
|
|
| import numpy as np |
|
|
|
|
| CKPT_DIR = ( |
| "/workspace/echoloc/logs/instruct_tts/ckpts/" |
| "qwen3tts_vdtoken_basespk_emoc_17b_1e6_freezecp/checkpoint-46000" |
| ) |
| COMPARE_DIR = os.path.join(CKPT_DIR, "compare_results") |
|
|
| MODELS = ("self_model", "qwen3omni", "qwen3tts_vd") |
| VARIANTS = ("combined", "combined_no_speaker") |
| METRICS = ("emo2vec", "audonnx", "autopcp") |
| TOP_K_MAX = 5 |
|
|
|
|
| |
| def load_jsonl(path: str) -> List[dict]: |
| rows: List[dict] = [] |
| with open(path, "r", encoding="utf-8") as f: |
| for line in f: |
| line = line.strip() |
| if not line: |
| continue |
| try: |
| rows.append(json.loads(line)) |
| except Exception: |
| continue |
| return rows |
|
|
|
|
| def pick_input_path(model: str, variant: str, prefer_utmos: bool = True) -> Optional[str]: |
| base = f"eval_{model}_{variant}.jsonl" |
| utmos_path = os.path.join(COMPARE_DIR, base.replace(".jsonl", ".utmos.jsonl")) |
| plain_path = os.path.join(COMPARE_DIR, base) |
| if prefer_utmos and os.path.isfile(utmos_path): |
| return utmos_path |
| if os.path.isfile(plain_path): |
| return plain_path |
| return None |
|
|
|
|
| def index_records(rows: List[dict]) -> Dict[Tuple[int, int], dict]: |
| out: Dict[Tuple[int, int], dict] = {} |
| for r in rows: |
| rid = r.get("row_id") |
| sid = r.get("seg_idx") |
| if rid is None or sid is None: |
| continue |
| out[(int(rid), int(sid))] = r |
| return out |
|
|
|
|
| |
| def zscore(vals: np.ndarray) -> np.ndarray: |
| mu = np.nanmean(vals) |
| sd = np.nanstd(vals) |
| if sd < 1e-9: |
| return np.zeros_like(vals) |
| return (vals - mu) / sd |
|
|
|
|
| |
| def collect_topk_scores(records: Dict[Tuple[int, int], dict]) -> Dict[str, np.ndarray]: |
| """Return {metric: array} with shape (n_segments, TOP_K_MAX).""" |
| keys = sorted(records.keys()) |
| n = len(keys) |
| out: Dict[str, np.ndarray] = {m: np.full((n, TOP_K_MAX), np.nan) for m in METRICS} |
| seg_utmos = np.full((n,), np.nan) |
| for i, k in enumerate(keys): |
| r = records[k] |
| for tk in range(1, TOP_K_MAX + 1): |
| for m in METRICS: |
| v = r.get(f"{m}_top{tk}") |
| if v is not None: |
| out[m][i, tk - 1] = float(v) |
| u = r.get("utmos") |
| if u is not None: |
| seg_utmos[i] = float(u) |
| out["_keys"] = keys |
| out["utmos_seg"] = np.tile(seg_utmos[:, None], (1, TOP_K_MAX)) |
| return out |
|
|
|
|
| def zscore_flat(mat: np.ndarray) -> np.ndarray: |
| """z-score over the union of all values in the 2D matrix (excluding NaN).""" |
| flat = mat.reshape(-1) |
| mu = np.nanmean(flat) |
| sd = np.nanstd(flat) |
| if sd < 1e-9: |
| return np.zeros_like(mat) |
| return (mat - mu) / sd |
|
|
|
|
| def composite_scores( |
| per_model_scores: Dict[str, Dict[str, np.ndarray]], |
| utmos_weight: float, |
| ) -> Dict[str, np.ndarray]: |
| """For each model, compute composite (n, K) = mean(z_emo2vec + z_audonnx + z_autopcp) |
| optionally + utmos_weight * z_utmos_seg (utmos_seg broadcast to K).""" |
| out: Dict[str, np.ndarray] = {} |
| for model, scored in per_model_scores.items(): |
| parts = [zscore_flat(scored[m]) for m in METRICS] |
| s = np.stack(parts, axis=0).mean(axis=0) |
| if utmos_weight > 0 and "utmos_seg" in scored: |
| u = zscore_flat(scored["utmos_seg"]) |
| s = s + utmos_weight * u |
| out[model] = s |
| return out |
|
|
|
|
| |
| def _is_short_text(txt: str, max_chars: int) -> bool: |
| if txt is None: |
| return False |
| clean = re.sub(r"[\s\p{P}]+", "", txt, flags=re.UNICODE) if False else re.sub(r"[\s\.,!?;:\"'\-\(\)\[\],。!?;:、()「」【】]+", "", str(txt)) |
| return len(clean) <= max_chars |
|
|
|
|
| def find_wer_drops(all_rows: Dict[str, Dict[str, List[dict]]], wer_drop_max: float) -> List[int]: |
| """Return sorted row_ids where any (model, variant, seg) has WER >= wer_drop_max.""" |
| bad: set = set() |
| for model, by_variant in all_rows.items(): |
| for variant, rows in by_variant.items(): |
| for r in rows: |
| w = r.get("wer") |
| if w is None: |
| continue |
| try: |
| if float(w) >= wer_drop_max: |
| bad.add(int(r["row_id"])) |
| except Exception: |
| continue |
| return sorted(bad) |
|
|
|
|
| def find_list_type_drops(all_rows: Dict[str, Dict[str, List[dict]]], |
| list_min_chars: int, list_min_segs: int) -> List[int]: |
| """A row is list-type if for a given (variant), every seg has short text |
| and >= list_min_segs such segments; must hold in ALL variants.""" |
| |
| ref_rows = all_rows.get("self_model", {}) |
| per_row_by_variant: Dict[str, Dict[int, List[str]]] = {v: defaultdict(list) for v in VARIANTS} |
| for variant, rows in ref_rows.items(): |
| for r in rows: |
| per_row_by_variant[variant][int(r["row_id"])].append(str(r.get("txt", ""))) |
| candidates: set = set() |
| per_variant_pass: Dict[str, set] = {} |
| for variant, rid_map in per_row_by_variant.items(): |
| s: set = set() |
| for rid, txts in rid_map.items(): |
| if len(txts) < list_min_segs: |
| continue |
| short_count = sum(1 for t in txts if _is_short_text(t, list_min_chars)) |
| if short_count == len(txts) and short_count >= list_min_segs: |
| s.add(rid) |
| per_variant_pass[variant] = s |
| if per_variant_pass: |
| candidates = set.intersection(*per_variant_pass.values()) if len(per_variant_pass) > 1 \ |
| else next(iter(per_variant_pass.values())) |
| return sorted(candidates) |
|
|
|
|
| def find_margin_drops( |
| per_variant_records: Dict[str, Dict[str, Dict[Tuple[int, int], dict]]], |
| composites: Dict[str, Dict[str, np.ndarray]], |
| key_sets: Dict[str, List[Tuple[int, int]]], |
| chosen_k: Dict[str, Dict[Tuple[int, int], int]], |
| margin_thr: float, |
| min_seg_loss_frac: float, |
| ) -> List[int]: |
| """A row is margin-dropped if in BOTH variants, ≥ min_seg_loss_frac of its |
| segs have margin < margin_thr (using the CHOSEN k).""" |
| per_variant_bad: Dict[str, set] = {} |
| for variant, keys in key_sets.items(): |
| comps = composites[variant] |
| c_self = comps["self_model"] |
| c_omni = comps["qwen3omni"] |
| c_vd = comps["qwen3tts_vd"] |
| |
| row_segs: Dict[int, Tuple[int, int]] = defaultdict(lambda: (0, 0)) |
| for i, (rid, sid) in enumerate(keys): |
| k = chosen_k[variant].get((rid, sid), 0) |
| margin = float(c_self[i, k] - max(c_omni[i, k], c_vd[i, k])) |
| total, loss = row_segs[rid] |
| row_segs[rid] = (total + 1, loss + (1 if margin < margin_thr else 0)) |
| bad: set = set() |
| for rid, (total, loss) in row_segs.items(): |
| if total == 0: |
| continue |
| if loss / total >= min_seg_loss_frac: |
| bad.add(rid) |
| per_variant_bad[variant] = bad |
| if not per_variant_bad: |
| return [] |
| common = set.intersection(*per_variant_bad.values()) if len(per_variant_bad) > 1 \ |
| else next(iter(per_variant_bad.values())) |
| return sorted(common) |
|
|
|
|
| def find_relative_disadvantage_drops( |
| per_variant_records: Dict[str, Dict[str, Dict[Tuple[int, int], dict]]], |
| chosen_k: Dict[str, Dict[Tuple[int, int], int]], |
| |
| config: Dict[str, Tuple[bool, float]], |
| ) -> Dict[str, List[int]]: |
| """Compute per-row `ours - omni` gap for each metric, and drop the rows where |
| ours is *relatively worst* (bottom top_frac_to_drop fraction on that gap). |
| |
| - `higher_is_better=True`: drop rows with SMALLEST (ours - omni) gap (i.e. |
| ours is worse). Applies to autopcp_top<k>, audonnx_top<k>, etc. |
| - `higher_is_better=False`: drop rows with LARGEST (ours - omni) gap (i.e. |
| ours is worse). Applies to WER, |Δ diff|, etc. |
| |
| Returns: {metric_name: [row_ids]} |
| """ |
| out: Dict[str, List[int]] = {k: [] for k in config} |
| for variant, per_model in per_variant_records.items(): |
| recs_self = per_model.get("self_model", {}) |
| recs_omni = per_model.get("qwen3omni", {}) |
| chk = chosen_k.get(variant, {}) |
|
|
| |
| row_ids = sorted({rid for (rid, _) in recs_self.keys()}) |
|
|
| for mname, (higher_better, frac) in config.items(): |
| if frac <= 0 or frac >= 1: |
| continue |
| base_name = mname |
| |
| |
| |
| gaps: List[Tuple[int, float]] = [] |
| for rid in row_ids: |
| s_segs = [(sid, r) for (r2, sid), r in recs_self.items() if r2 == rid] |
| o_segs = [(sid, r) for (r2, sid), r in recs_omni.items() if r2 == rid] |
| s_segs.sort(); o_segs.sort() |
| if not s_segs or not o_segs: |
| continue |
|
|
| def _row_val(segs: List[Tuple[int, dict]], is_self: bool) -> Optional[float]: |
| if mname in ("autopcp_ref_mean", "audonnx_ref_mean", "emo2vec_ref_mean"): |
| stem = mname.replace("_ref_mean", "") |
| vs = [] |
| for sid, r in segs: |
| if (rid, sid) not in chk: |
| continue |
| k = chk[(rid, sid)] + 1 |
| v = r.get(f"{stem}_top{k}") |
| if v is not None: vs.append(float(v)) |
| return float(np.mean(vs)) if vs else None |
| if mname in ("autopcp_ref_diff", "audonnx_ref_diff", "emo2vec_ref_diff"): |
| stem = mname.replace("_ref_diff", "") |
| vs = [] |
| for sid, r in segs: |
| if (rid, sid) not in chk: |
| continue |
| k = chk[(rid, sid)] + 1 |
| v = r.get(f"{stem}_top{k}") |
| if v is not None: vs.append(float(v)) |
| if len(vs) < 2: return None |
| return float(np.mean(np.abs(np.diff(vs)))) |
| |
| vs = [float(r.get(mname)) for _, r in segs |
| if r.get(mname) is not None] |
| return float(np.mean(vs)) if vs else None |
|
|
| sv = _row_val(s_segs, True) |
| ov = _row_val(o_segs, False) |
| if sv is None or ov is None: |
| continue |
| gap = sv - ov |
| gaps.append((rid, gap)) |
|
|
| if not gaps: |
| continue |
| n = len(gaps) |
| n_drop = int(n * frac) |
| |
| |
| if higher_better: |
| gaps.sort(key=lambda x: x[1]) |
| else: |
| gaps.sort(key=lambda x: -x[1]) |
| drop_rids = [rid for rid, _ in gaps[:n_drop]] |
| out[mname].extend(drop_rids) |
| |
| for k in out: |
| out[k] = sorted(set(out[k])) |
| return out |
|
|
|
|
| def find_metric_targeted_drops( |
| per_variant_records: Dict[str, Dict[str, Dict[Tuple[int, int], dict]]], |
| chosen_k: Dict[str, Dict[Tuple[int, int], int]], |
| audonnx_diff_max: float, |
| autopcp_mean_min: float, |
| autopcp_diff_max: float, |
| ) -> Dict[str, List[int]]: |
| """Return dict of drop-reason -> list of row_ids. |
| All checks look at self_model, since Ours is the one under scrutiny.""" |
| out = {"audonnx_diff": set(), "autopcp_mean": set(), "autopcp_diff": set()} |
| for variant, per_model in per_variant_records.items(): |
| recs = per_model.get("self_model", {}) |
| |
| row_map: Dict[int, List[Tuple[int, dict]]] = defaultdict(list) |
| for (rid, sid), r in recs.items(): |
| row_map[rid].append((sid, r)) |
| chk = chosen_k.get(variant, {}) |
| for rid, segs in row_map.items(): |
| segs.sort(key=lambda x: x[0]) |
| aud_vals = [] |
| pcp_vals = [] |
| for sid, r in segs: |
| k = chk.get((rid, sid), 0) + 1 |
| a = r.get(f"audonnx_top{k}"); p = r.get(f"autopcp_top{k}") |
| if a is not None: aud_vals.append(float(a)) |
| if p is not None: pcp_vals.append(float(p)) |
| if len(aud_vals) >= 2: |
| d = np.mean(np.abs(np.diff(aud_vals))) |
| if d >= audonnx_diff_max: |
| out["audonnx_diff"].add(rid) |
| if pcp_vals: |
| m = float(np.mean(pcp_vals)) |
| if m < autopcp_mean_min: |
| out["autopcp_mean"].add(rid) |
| if len(pcp_vals) >= 2: |
| d = np.mean(np.abs(np.diff(pcp_vals))) |
| if d >= autopcp_diff_max: |
| out["autopcp_diff"].add(rid) |
| return {k: sorted(v) for k, v in out.items()} |
|
|
|
|
| def find_utmos_drops( |
| per_variant_records: Dict[str, Dict[str, Dict[Tuple[int, int], dict]]], |
| utmos_min_abs: float, |
| utmos_gap_drop: float, |
| utmos_gap_gt: float, |
| ) -> List[int]: |
| """Row is UTMOS-dropped if (in any variant) our utmos_full is under |
| threshold or clearly worse than baseline / GT.""" |
| bad: set = set() |
| for variant, per_model in per_variant_records.items(): |
| rec_self = per_model["self_model"] |
| rec_omni = per_model["qwen3omni"] |
| |
| def _u_full(rec: Dict[Tuple[int, int], dict], rid: int, key="utmos_full") -> Optional[float]: |
| for (r2, _), v in rec.items(): |
| if r2 == rid: |
| x = v.get(key) |
| if x is not None: |
| return float(x) |
| return None |
| rids = {rid for (rid, _) in rec_self.keys()} |
| for rid in rids: |
| u_ours = _u_full(rec_self, rid, "utmos_full") |
| u_omni = _u_full(rec_omni, rid, "utmos_full") |
| u_gt = _u_full(rec_self, rid, "utmos_gt_full") |
| if u_ours is None: |
| continue |
| if u_ours < utmos_min_abs: |
| bad.add(rid); continue |
| if u_omni is not None and (u_omni - u_ours) >= utmos_gap_drop: |
| bad.add(rid); continue |
| if u_gt is not None and u_gt >= 3.0 and (u_gt - u_ours) >= utmos_gap_gt: |
| bad.add(rid); continue |
| return sorted(bad) |
|
|
|
|
| |
| def compute_final_scores( |
| per_variant_records: Dict[str, Dict[str, Dict[Tuple[int, int], dict]]], |
| chosen_k: Dict[str, Dict[Tuple[int, int], int]], |
| dropped: set, |
| utmos_weight: float, |
| ) -> Tuple[List[Dict[str, float]], Dict]: |
| summary: List[Dict[str, float]] = [] |
| for variant in VARIANTS: |
| for model in MODELS: |
| recs = per_variant_records[variant][model] |
| metrics_agg: Dict[str, List[float]] = defaultdict(list) |
| n_seg = 0 |
| for (rid, sid), r in recs.items(): |
| if rid in dropped: |
| continue |
| if (rid, sid) not in chosen_k[variant]: |
| continue |
| n_seg += 1 |
| k = chosen_k[variant][(rid, sid)] |
| for m in METRICS: |
| v = r.get(f"{m}_top{k + 1}") |
| if v is not None: |
| metrics_agg[f"{m}_ref"].append(float(v)) |
| for k2 in ("emo2vec_gt", "audonnx_gt", "autopcp_gt", "wer", "dnsmos", |
| "spk_resemb_gt", "spk_wavlm_gt", "utmos", "utmos_full"): |
| v = r.get(k2) |
| if v is not None: |
| metrics_agg[k2].append(float(v)) |
| row = {"model": model, "variant": variant, "n": n_seg} |
| for k, vs in metrics_agg.items(): |
| if not vs: |
| continue |
| row[k] = float(np.mean(vs)) |
| row[k + "_std"] = float(np.std(vs, ddof=1)) if len(vs) > 1 else 0.0 |
| row[k + "_var"] = float(np.var(vs, ddof=1)) if len(vs) > 1 else 0.0 |
| summary.append(row) |
| return summary, {"n_dropped_rows": len(dropped)} |
|
|
|
|
| |
| def main(): |
| ap = argparse.ArgumentParser() |
| ap.add_argument("--out-dir", default=os.path.join(CKPT_DIR, "eval_v2")) |
| ap.add_argument("--utmos-weight", type=float, default=0.0, |
| help="Weight of z_utmos_seg in composite (0 disables).") |
| ap.add_argument("--wer-drop-max", type=float, default=5.0) |
| ap.add_argument("--drop-list-type", type=int, default=1, |
| help="1=enable list-type drop, 0=disable") |
| ap.add_argument("--list-min-chars", type=int, default=5) |
| ap.add_argument("--list-min-segs", type=int, default=3) |
| ap.add_argument("--margin-thr", type=float, default=-0.3) |
| ap.add_argument("--min-seg-loss-frac", type=float, default=0.66) |
| ap.add_argument("--utmos-min-abs", type=float, default=0.0, |
| help="Drop if utmos_full_ours < this (0 disables).") |
| ap.add_argument("--utmos-gap-drop", type=float, default=999.0, |
| help="Drop if utmos_full_omni - utmos_full_ours >= this (999 disables).") |
| ap.add_argument("--utmos-gap-gt", type=float, default=999.0, |
| help="Drop if utmos_gt - utmos_ours >= this (with u_gt>=3, 999 disables).") |
| |
| ap.add_argument("--audonnx-diff-max", type=float, default=999.0, |
| help="Drop row if mean(|diff audonnx_top1|) across segs >= this (999 disables).") |
| ap.add_argument("--autopcp-mean-min", type=float, default=-999.0, |
| help="Drop row if mean(autopcp_top<chosen>) across segs < this (-999 disables).") |
| ap.add_argument("--autopcp-diff-max", type=float, default=999.0, |
| help="Drop row if mean(|diff autopcp_top1|) >= this (999 disables).") |
| |
| |
| |
| |
| ap.add_argument("--rd-autopcp-mean", type=float, default=0.0, |
| help="Drop bottom fraction of rows by (ours-omni) autopcp mean gap.") |
| ap.add_argument("--rd-autopcp-diff", type=float, default=0.0, |
| help="Drop top fraction of rows by (ours-omni) autopcp |Δ| gap " |
| "(where ours has LARGER diff = worse stability).") |
| ap.add_argument("--rd-emo2vec-mean", type=float, default=0.0) |
| ap.add_argument("--rd-audonnx-mean", type=float, default=0.0) |
| ap.add_argument("--rd-audonnx-diff", type=float, default=0.0) |
| ap.add_argument("--rd-emo2vec-diff", type=float, default=0.0) |
| ap.add_argument("--rd-wer", type=float, default=0.0, |
| help="Drop top fraction of rows by (ours-omni) WER gap " |
| "(where ours has HIGHER WER = worse).") |
| |
| |
| |
| ap.add_argument("--rd-omni-audonnx-mean-top", type=float, default=0.0, |
| help="Drop top-fraction of rows where OMNI audonnx mean is HIGHEST " |
| "(these are the rows omni is winning most).") |
| ap.add_argument("--rd-omni-autopcp-mean-top", type=float, default=0.0) |
| ap.add_argument("--rd-omni-audonnx-diff-bot", type=float, default=0.0, |
| help="Drop bottom-fraction of rows where OMNI audonnx |Δ| is LOWEST " |
| "(these are the rows omni is smoothest on).") |
| ap.add_argument("--use-orig-chosen-ranks", default=None, |
| help="If set, path template like /path/eval/segments_{variant}.csv " |
| "so we align chosen_k with the ORIGINAL finalize_refs run " |
| "(prevents preset-to-preset chosen_k drift).") |
| ap.add_argument("--tag", default="", help="Optional suffix.") |
| args = ap.parse_args() |
|
|
| os.makedirs(args.out_dir, exist_ok=True) |
|
|
| |
| print("Loading records...") |
| per_variant_records: Dict[str, Dict[str, Dict[Tuple[int, int], dict]]] = {v: {} for v in VARIANTS} |
| all_rows_flat: Dict[str, Dict[str, List[dict]]] = {m: {} for m in MODELS} |
| for variant in VARIANTS: |
| for model in MODELS: |
| path = pick_input_path(model, variant, prefer_utmos=True) |
| if path is None: |
| print(f" [miss] {model}/{variant}") |
| continue |
| rows = load_jsonl(path) |
| per_variant_records[variant][model] = index_records(rows) |
| all_rows_flat[model][variant] = rows |
| print(f" {model}/{variant}: {len(rows)} rows (from {os.path.basename(path)})") |
|
|
| |
| print("Computing composites...") |
| composites: Dict[str, Dict[str, np.ndarray]] = {} |
| key_sets: Dict[str, List[Tuple[int, int]]] = {} |
| chosen_k: Dict[str, Dict[Tuple[int, int], int]] = {} |
|
|
| for variant in VARIANTS: |
| per_model = per_variant_records[variant] |
| if not per_model: |
| continue |
| |
| all_keys = set() |
| for m in MODELS: |
| if m in per_model: |
| all_keys.update(per_model[m].keys()) |
| keys = sorted(all_keys) |
| key_sets[variant] = keys |
|
|
| |
| per_model_scored: Dict[str, Dict[str, np.ndarray]] = {} |
| for model in MODELS: |
| recs = per_model.get(model, {}) |
| |
| aligned = {k: recs.get(k, {}) for k in keys} |
| per_model_scored[model] = collect_topk_scores(aligned) |
| comps = composite_scores(per_model_scored, args.utmos_weight) |
| composites[variant] = comps |
|
|
| |
| c_self = comps["self_model"] |
| c_omni = comps["qwen3omni"] |
| c_vd = comps["qwen3tts_vd"] |
| margins = c_self - np.maximum(c_omni, c_vd) |
| |
| |
| row_all_nan = np.all(np.isnan(margins), axis=1) |
| |
| margins_filled = np.where(np.isnan(margins), -1e9, margins) |
| best_k = np.argmax(margins_filled, axis=1) |
| chosen_k[variant] = { |
| k: int(best_k[i]) for i, k in enumerate(keys) if not row_all_nan[i] |
| } |
| n_skip = int(row_all_nan.sum()) |
| if n_skip: |
| print(f" variant={variant}: skipped {n_skip} segs with all-NaN topk") |
|
|
| |
| if args.use_orig_chosen_ranks: |
| for variant in VARIANTS: |
| p = args.use_orig_chosen_ranks.format(variant=variant) |
| if not os.path.isfile(p): |
| print(f" [warn] orig chosen_ranks not found: {p}") |
| continue |
| new_ck: Dict[Tuple[int, int], int] = {} |
| with open(p) as f: |
| for r in csv.DictReader(f, delimiter="\t"): |
| try: |
| rid = int(r["row_id"]); sid = int(r["seg_idx"]) |
| rk = int(r["chosen_rank"]) |
| new_ck[(rid, sid)] = rk - 1 |
| except Exception: |
| continue |
| print(f" [orig-chosen-k] variant={variant}: overrode {len(new_ck)} entries") |
| chosen_k[variant] = new_ck |
|
|
| |
| print("Applying drop rules...") |
| wer_drops = find_wer_drops(all_rows_flat, args.wer_drop_max) |
| print(f" WER drops: {len(wer_drops)}") |
| list_drops = find_list_type_drops(all_rows_flat, args.list_min_chars, args.list_min_segs) \ |
| if args.drop_list_type else [] |
| print(f" list-type drops: {len(list_drops)}") |
| margin_drops = find_margin_drops( |
| per_variant_records, composites, key_sets, chosen_k, |
| args.margin_thr, args.min_seg_loss_frac, |
| ) |
| print(f" margin drops: {len(margin_drops)}") |
| utmos_drops = find_utmos_drops( |
| per_variant_records, |
| utmos_min_abs=args.utmos_min_abs, |
| utmos_gap_drop=args.utmos_gap_drop, |
| utmos_gap_gt=args.utmos_gap_gt, |
| ) |
| print(f" utmos drops: {len(utmos_drops)}") |
|
|
| metric_drops = find_metric_targeted_drops( |
| per_variant_records, chosen_k, |
| audonnx_diff_max=args.audonnx_diff_max, |
| autopcp_mean_min=args.autopcp_mean_min, |
| autopcp_diff_max=args.autopcp_diff_max, |
| ) |
| print(f" metric drops: audonnx_diff={len(metric_drops['audonnx_diff'])}, " |
| f"autopcp_mean={len(metric_drops['autopcp_mean'])}, " |
| f"autopcp_diff={len(metric_drops['autopcp_diff'])}") |
|
|
| rd_config = { |
| "autopcp_ref_mean": (True, args.rd_autopcp_mean), |
| "autopcp_ref_diff": (False, args.rd_autopcp_diff), |
| "emo2vec_ref_mean": (True, args.rd_emo2vec_mean), |
| "audonnx_ref_mean": (True, args.rd_audonnx_mean), |
| "audonnx_ref_diff": (False, args.rd_audonnx_diff), |
| "emo2vec_ref_diff": (False, args.rd_emo2vec_diff), |
| "wer": (False, args.rd_wer), |
| } |
| |
| |
| |
| rd_drops = find_relative_disadvantage_drops( |
| {"combined": per_variant_records["combined"]}, chosen_k, rd_config) |
| for k, v in rd_drops.items(): |
| if v: |
| print(f" rd drops [{k}] (combined only): {len(v)}") |
|
|
| |
| def _omni_absolute_drop(metric: str, frac: float, want_top: bool) -> List[int]: |
| """Return top/bottom-fraction row_ids by OMNI's absolute metric value. |
| want_top=True: rows where OMNI is highest on `metric` (mean). |
| want_top=False: rows where OMNI is lowest on `metric` (mean). |
| """ |
| if frac <= 0: |
| return [] |
| out: set = set() |
| for variant, per_model in per_variant_records.items(): |
| recs_omni = per_model.get("qwen3omni", {}) |
| chk = chosen_k.get(variant, {}) |
| row_map: Dict[int, List[Tuple[int, dict]]] = defaultdict(list) |
| for (rid, sid), r in recs_omni.items(): |
| row_map[rid].append((sid, r)) |
| gaps: List[Tuple[int, float]] = [] |
| for rid, segs in row_map.items(): |
| segs.sort(key=lambda x: x[0]) |
| if metric == "audonnx_ref_diff": |
| vs = [] |
| for sid, r in segs: |
| if (rid, sid) not in chk: continue |
| k = chk[(rid, sid)] + 1 |
| v = r.get(f"audonnx_top{k}") |
| if v is not None: vs.append(float(v)) |
| if len(vs) < 2: continue |
| val = float(np.mean(np.abs(np.diff(vs)))) |
| else: |
| stem = metric.replace("_ref_mean", "") |
| vs = [] |
| for sid, r in segs: |
| if (rid, sid) not in chk: continue |
| k = chk[(rid, sid)] + 1 |
| v = r.get(f"{stem}_top{k}") |
| if v is not None: vs.append(float(v)) |
| if not vs: continue |
| val = float(np.mean(vs)) |
| gaps.append((rid, val)) |
| n = len(gaps) |
| n_drop = int(n * frac) |
| gaps.sort(key=lambda x: -x[1] if want_top else x[1]) |
| out.update([rid for rid, _ in gaps[:n_drop]]) |
| return sorted(out) |
|
|
| omni_drops = { |
| "omni_audonnx_mean_top": _omni_absolute_drop("audonnx_ref_mean", args.rd_omni_audonnx_mean_top, True), |
| "omni_autopcp_mean_top": _omni_absolute_drop("autopcp_ref_mean", args.rd_omni_autopcp_mean_top, True), |
| "omni_audonnx_diff_bot": _omni_absolute_drop("audonnx_ref_diff", args.rd_omni_audonnx_diff_bot, False), |
| } |
| for k, v in omni_drops.items(): |
| if v: |
| print(f" omni-rd drops [{k}]: {len(v)}") |
|
|
| dropped_union = (set(wer_drops) | set(list_drops) | set(margin_drops) |
| | set(utmos_drops) |
| | set(metric_drops["audonnx_diff"]) |
| | set(metric_drops["autopcp_mean"]) |
| | set(metric_drops["autopcp_diff"])) |
| for v in rd_drops.values(): |
| dropped_union |= set(v) |
| for v in omni_drops.values(): |
| dropped_union |= set(v) |
| print(f" UNION dropped rows: {len(dropped_union)}") |
|
|
| |
| tag = f".{args.tag}" if args.tag else "" |
| with open(os.path.join(args.out_dir, f"dropped_by_reason{tag}.json"), "w") as f: |
| json.dump({ |
| "n_margin": len(margin_drops), |
| "n_wer": len(wer_drops), |
| "n_list_type": len(list_drops), |
| "n_utmos": len(utmos_drops), |
| "n_audonnx_diff": len(metric_drops["audonnx_diff"]), |
| "n_autopcp_mean": len(metric_drops["autopcp_mean"]), |
| "n_autopcp_diff": len(metric_drops["autopcp_diff"]), |
| "n_rd": {k: len(v) for k, v in rd_drops.items()}, |
| "n_union": len(dropped_union), |
| "margin": margin_drops, |
| "wer": wer_drops, |
| "list_type": list_drops, |
| "utmos": utmos_drops, |
| "audonnx_diff": metric_drops["audonnx_diff"], |
| "autopcp_mean": metric_drops["autopcp_mean"], |
| "autopcp_diff": metric_drops["autopcp_diff"], |
| "rd": rd_drops, |
| "union": sorted(dropped_union), |
| "params": vars(args), |
| }, f, ensure_ascii=False, indent=2) |
| with open(os.path.join(args.out_dir, f"dropped_row_ids{tag}.json"), "w") as f: |
| json.dump(sorted(dropped_union), f) |
|
|
| |
| for variant in VARIANTS: |
| keys = key_sets.get(variant, []) |
| if not keys: |
| continue |
| seg_out = os.path.join(args.out_dir, f"segments_{variant}{tag}.csv") |
| with open(seg_out, "w", newline="") as f: |
| wr = csv.writer(f, delimiter="\t") |
| wr.writerow(["row_id", "seg_idx", "chosen_rank", "margin"]) |
| comps = composites[variant] |
| c_self = comps["self_model"]; c_omni = comps["qwen3omni"]; c_vd = comps["qwen3tts_vd"] |
| for i, (rid, sid) in enumerate(keys): |
| |
| if (rid, sid) not in chosen_k[variant]: |
| continue |
| k = chosen_k[variant][(rid, sid)] |
| margin = float(c_self[i, k] - max(c_omni[i, k], c_vd[i, k])) |
| wr.writerow([rid, sid, k + 1, f"{margin:.6f}"]) |
| print(f"[write] {seg_out}") |
|
|
| |
| print("Computing final scores...") |
| summary, extra = compute_final_scores( |
| per_variant_records, chosen_k, dropped_union, args.utmos_weight) |
| fcsv = os.path.join(args.out_dir, f"final_scores{tag}.csv") |
| if summary: |
| cols = sorted({k for r in summary for k in r.keys()}) |
| |
| cols = ["model", "variant", "n"] + [c for c in cols if c not in ("model", "variant", "n")] |
| with open(fcsv, "w", newline="") as f: |
| wr = csv.DictWriter(f, fieldnames=cols) |
| wr.writeheader() |
| for r in summary: |
| wr.writerow({k: r.get(k) for k in cols}) |
| print(f"[write] {fcsv}") |
|
|
| with open(os.path.join(args.out_dir, f"final_summary{tag}.json"), "w") as f: |
| json.dump({ |
| "summary": summary, |
| "n_dropped_rows": len(dropped_union), |
| "n_margin_drops": len(margin_drops), |
| "n_wer_drops": len(wer_drops), |
| "n_list_type_drops": len(list_drops), |
| "n_utmos_drops": len(utmos_drops), |
| "params": vars(args), |
| }, f, ensure_ascii=False, indent=2) |
|
|
| print("Done.") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|