Automatic Speech Recognition
cactus
wannaphong commited on
Commit
821dd49
·
verified ·
1 Parent(s): 5c60154

Create evaluate_fleurs.py

Browse files
Files changed (1) hide show
  1. evaluate_fleurs.py +135 -0
evaluate_fleurs.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ import tarfile
4
+ import argparse
5
+ import cactus
6
+ from huggingface_hub import hf_hub_download
7
+ from pythainlp.util import normalize, num_to_thaiword, thai_digit_to_arabic_digit, digit_to_text
8
+ from pythainlp.tokenize import word_tokenize
9
+ from tqdm import tqdm
10
+
11
+ regex = re.compile(r"[^\w\u0E00-\u0E7Fa-zA-Z]")
12
+ clean_whitespace = re.compile(r"\s+")
13
+
14
+ def convert_numbers_to_thai(text):
15
+ text = thai_digit_to_arabic_digit(text)
16
+ text = re.sub(r"(?<=\d),(?=\d)", "", text)
17
+
18
+ def replace_decimal(m):
19
+ int_part, dec_part = m.group(1), m.group(2)
20
+ try:
21
+ int_word = num_to_thaiword(int(int_part)) if int_part else ""
22
+ except Exception:
23
+ int_word = digit_to_text(int_part)
24
+ dec_word = digit_to_text(dec_part)
25
+ return f" {int_word}จุด{dec_word} "
26
+
27
+ text = re.sub(r"(\d+)\.(\d+)", replace_decimal, text)
28
+
29
+ def replace_int(m):
30
+ s = m.group(0)
31
+ if (len(s) > 1 and s.startswith("0")) or len(s) > 12:
32
+ return f" {digit_to_text(s)} "
33
+ try:
34
+ return f" {num_to_thaiword(int(s))} "
35
+ except Exception:
36
+ return f" {digit_to_text(s)} "
37
+
38
+ text = re.sub(r"\d+", replace_int, text)
39
+ return text
40
+
41
+ def clean_text(s):
42
+ s = s.replace("ํา", "ำ")
43
+ s = convert_numbers_to_thai(s)
44
+ s = normalize(s.strip())
45
+ s = re.sub(r"\s\s+", " ", regex.sub(" ", s).replace(" ", " ").replace("“", "").replace(" ”", "").replace("”", "")).strip()
46
+ return clean_whitespace.sub(" ", " ".join(word_tokenize(s, engine="newmm"))).strip()
47
+
48
+ def compute_cer(ref, hyp):
49
+ ref_chars = list(ref.replace(" ", ""))
50
+ hyp_chars = list(hyp.replace(" ", ""))
51
+ row = list(range(len(hyp_chars) + 1))
52
+ for i, r in enumerate(ref_chars, 1):
53
+ prev, row[0] = row[0], i
54
+ for j, h in enumerate(hyp_chars, 1):
55
+ prev, row[j] = row[j], min(row[j] + 1, row[j - 1] + 1, prev + (r != h))
56
+ return row[-1], len(ref_chars)
57
+
58
+ def compute_wer(ref, hyp):
59
+ ref_words = ref.split()
60
+ hyp_words = hyp.split()
61
+ row = list(range(len(hyp_words) + 1))
62
+ for i, r in enumerate(ref_words, 1):
63
+ prev, row[0] = row[0], i
64
+ for j, h in enumerate(hyp_words, 1):
65
+ prev, row[j] = row[j], min(row[j] + 1, row[j - 1] + 1, prev + (r != h))
66
+ return row[-1], len(ref_words)
67
+
68
+ def main():
69
+ parser = argparse.ArgumentParser(description="Evaluate Whistle Thai model on Google FLEURS (th_th) test set")
70
+ parser.add_argument("--weights", default="/workspace/whistle-thai/output_combined/maprang.cact", help="Path to .cact weights")
71
+ parser.add_argument("--extract-dir", default="./fleurs_th", help="Directory to cache extracted FLEURS audio")
72
+ parser.add_argument("--limit", type=int, default=0, help="Limit number of test clips (0 for full 1,021 clips)")
73
+ parser.add_argument("--skip-non-thai", action="store_true", help="Skip test sentences containing digits or Latin characters")
74
+ args = parser.parse_args()
75
+
76
+ print("Downloading / locating Google FLEURS (th_th) test set...")
77
+ tsv_path = hf_hub_download(repo_id="google/fleurs", filename="data/th_th/test.tsv", repo_type="dataset")
78
+ tar_path = hf_hub_download(repo_id="google/fleurs", filename="data/th_th/audio/test.tar.gz", repo_type="dataset")
79
+
80
+ audio_dir = os.path.join(args.extract_dir, "test")
81
+ if not os.path.isdir(audio_dir) or len(os.listdir(audio_dir)) < 1000:
82
+ print(f"Extracting FLEURS test audio to {args.extract_dir}...")
83
+ os.makedirs(args.extract_dir, exist_ok=True)
84
+ with tarfile.open(tar_path, "r:gz") as tf:
85
+ tf.extractall(args.extract_dir)
86
+
87
+ records = []
88
+ thai_only_pattern = re.compile(r"^[ \u0E00-\u0E7F]+$")
89
+ has_digit = re.compile(r"[0-9\u0E50-\u0E59]")
90
+
91
+ with open(tsv_path, "r", encoding="utf-8") as f:
92
+ for line in f:
93
+ parts = line.rstrip("\n").split("\t")
94
+ if len(parts) < 4:
95
+ continue
96
+ wav_name = parts[1]
97
+ # parts[2] is raw transcription, parts[3] is normalized transcription (numbers spelled out in Thai)
98
+ transcript = parts[3].strip()
99
+ cleaned = clean_text(transcript)
100
+ if args.skip_non_thai:
101
+ if has_digit.search(cleaned) or not thai_only_pattern.match(cleaned):
102
+ continue
103
+ wav_path = os.path.join(audio_dir, wav_name)
104
+ if os.path.isfile(wav_path):
105
+ records.append((wav_path, cleaned))
106
+
107
+ if args.limit > 0:
108
+ records = records[:args.limit]
109
+
110
+ print(f"Evaluating {len(records)} clips from Google FLEURS (th_th) test set...")
111
+ edits_c = units_c = 0
112
+ edits_w = units_w = 0
113
+
114
+ for i, (wav_path, ref) in enumerate(tqdm(records, desc="FLEURS Eval")):
115
+ res = cactus.transcribe(wav_path, weights=args.weights, language="th")
116
+ hyp = res["text"].strip()
117
+
118
+ ec, nc = compute_cer(ref, hyp)
119
+ ew, nw = compute_wer(ref, hyp)
120
+ edits_c += ec
121
+ units_c += nc
122
+ edits_w += ew
123
+ units_w += nw
124
+
125
+ if i < 5:
126
+ tqdm.write(f"[{i+1}] Ref: {ref}")
127
+ tqdm.write(f" Hyp: {hyp}\n")
128
+
129
+ print(f"\n=== Google FLEURS (th_th) Test Results ({len(records)} clips) ===")
130
+ print(f"Model: {args.weights}")
131
+ print(f"Character Error Rate (CER): {edits_c / units_c:.2%}")
132
+ print(f"Word Error Rate (WER): {edits_w / units_w:.2%}")
133
+
134
+ if __name__ == "__main__":
135
+ main()