"""Пересчитать WER открытого бенчмарка Транскрибы без модели, GPU и сторонних пакетов. Скачайте https://transkriba.ru/api/bench/results в файл results.json рядом с этим скриптом и выполните: python3 verify_bench.py Скрипт проверяет арифметику каждого прогона (ошибки и число слов эталона сходятся с агрегатом) и то, что внутри набора у всех моделей одни и те же клипы и эталоны. Происхождение весов и воспроизводимость распознавания он не проверяет: для этого в JSON записаны репозиторий и коммит весов модели. """ import json from pathlib import Path def distance(reference, hypothesis): previous = list(range(len(hypothesis) + 1)) for i, word in enumerate(reference, 1): current = [i] for j, other in enumerate(hypothesis, 1): current.append(min(current[-1] + 1, previous[j] + 1, previous[j - 1] + (word != other))) previous = current return previous[-1] if __name__ == "__main__": data = json.loads(Path(__file__).with_name("results.json").read_text(encoding="utf-8")) references = {} for run in data["runs"]: name = f"{run['dataset']} · {run['engine']} {run['revision']}" rows = run.get("utterances") if not rows: print(f"{name}: строки не опубликованы, только агрегат WER {100 * run['aggregate']['wer']:.2f}%") continue refs = {str(row["id"]): row["ref"] for row in rows} assert references.setdefault(run["dataset"], refs) == refs, f"{name}: другие клипы или эталоны" errors = sum(distance(row["ref"].split(), row["hyp"].split()) for row in rows) words = sum(len(row["ref"].split()) for row in rows) assert errors == run["aggregate"]["errors"] and words == run["aggregate"]["ref_words"], name print(f"{name}: {errors}/{words} слов, WER {100 * errors / words:.2f}% — сходится")