Download evaluate_fleurs.py from pythainlp/MaprangSTT: direct link, hf CLI and curl.
- Browser
- Download file 5.42 kB
-
https://huggingface.co/pythainlp/MaprangSTT/resolve/main/evaluate_fleurs.py
- Command line
-
hf download hf://pythainlp/MaprangSTT/evaluate_fleurs.py
-
curl -L -o evaluate_fleurs.py https://huggingface.co/pythainlp/MaprangSTT/resolve/main/evaluate_fleurs.py
5.42 kB
| import os | |
| import re | |
| import tarfile | |
| import argparse | |
| import cactus | |
| from huggingface_hub import hf_hub_download | |
| from pythainlp.util import normalize, num_to_thaiword, thai_digit_to_arabic_digit, digit_to_text | |
| from pythainlp.tokenize import word_tokenize | |
| from tqdm import tqdm | |
| regex = re.compile(r"[^\w\u0E00-\u0E7Fa-zA-Z]") | |
| clean_whitespace = re.compile(r"\s+") | |
| def convert_numbers_to_thai(text): | |
| text = thai_digit_to_arabic_digit(text) | |
| text = re.sub(r"(?<=\d),(?=\d)", "", text) | |
| def replace_decimal(m): | |
| int_part, dec_part = m.group(1), m.group(2) | |
| try: | |
| int_word = num_to_thaiword(int(int_part)) if int_part else "" | |
| except Exception: | |
| int_word = digit_to_text(int_part) | |
| dec_word = digit_to_text(dec_part) | |
| return f" {int_word}จุด{dec_word} " | |
| text = re.sub(r"(\d+)\.(\d+)", replace_decimal, text) | |
| def replace_int(m): | |
| s = m.group(0) | |
| if (len(s) > 1 and s.startswith("0")) or len(s) > 12: | |
| return f" {digit_to_text(s)} " | |
| try: | |
| return f" {num_to_thaiword(int(s))} " | |
| except Exception: | |
| return f" {digit_to_text(s)} " | |
| text = re.sub(r"\d+", replace_int, text) | |
| return text | |
| def clean_text(s): | |
| s = s.replace("ํา", "ำ") | |
| s = convert_numbers_to_thai(s) | |
| s = normalize(s.strip()) | |
| s = re.sub(r"\s\s+", " ", regex.sub(" ", s).replace(" ", " ").replace("“", "").replace(" ”", "").replace("”", "")).strip() | |
| return clean_whitespace.sub(" ", " ".join(word_tokenize(s, engine="newmm"))).strip() | |
| def compute_cer(ref, hyp): | |
| ref_chars = list(ref.replace(" ", "")) | |
| hyp_chars = list(hyp.replace(" ", "")) | |
| row = list(range(len(hyp_chars) + 1)) | |
| for i, r in enumerate(ref_chars, 1): | |
| prev, row[0] = row[0], i | |
| for j, h in enumerate(hyp_chars, 1): | |
| prev, row[j] = row[j], min(row[j] + 1, row[j - 1] + 1, prev + (r != h)) | |
| return row[-1], len(ref_chars) | |
| def compute_wer(ref, hyp): | |
| ref_words = ref.split() | |
| hyp_words = hyp.split() | |
| row = list(range(len(hyp_words) + 1)) | |
| for i, r in enumerate(ref_words, 1): | |
| prev, row[0] = row[0], i | |
| for j, h in enumerate(hyp_words, 1): | |
| prev, row[j] = row[j], min(row[j] + 1, row[j - 1] + 1, prev + (r != h)) | |
| return row[-1], len(ref_words) | |
| def main(): | |
| parser = argparse.ArgumentParser(description="Evaluate Whistle Thai model on Google FLEURS (th_th) test set") | |
| parser.add_argument("--weights", default="/workspace/whistle-thai/output_combined/maprang.cact", help="Path to .cact weights") | |
| parser.add_argument("--extract-dir", default="./fleurs_th", help="Directory to cache extracted FLEURS audio") | |
| parser.add_argument("--limit", type=int, default=0, help="Limit number of test clips (0 for full 1,021 clips)") | |
| parser.add_argument("--skip-non-thai", action="store_true", help="Skip test sentences containing digits or Latin characters") | |
| args = parser.parse_args() | |
| print("Downloading / locating Google FLEURS (th_th) test set...") | |
| tsv_path = hf_hub_download(repo_id="google/fleurs", filename="data/th_th/test.tsv", repo_type="dataset") | |
| tar_path = hf_hub_download(repo_id="google/fleurs", filename="data/th_th/audio/test.tar.gz", repo_type="dataset") | |
| audio_dir = os.path.join(args.extract_dir, "test") | |
| if not os.path.isdir(audio_dir) or len(os.listdir(audio_dir)) < 1000: | |
| print(f"Extracting FLEURS test audio to {args.extract_dir}...") | |
| os.makedirs(args.extract_dir, exist_ok=True) | |
| with tarfile.open(tar_path, "r:gz") as tf: | |
| tf.extractall(args.extract_dir) | |
| records = [] | |
| thai_only_pattern = re.compile(r"^[ \u0E00-\u0E7F]+$") | |
| has_digit = re.compile(r"[0-9\u0E50-\u0E59]") | |
| with open(tsv_path, "r", encoding="utf-8") as f: | |
| for line in f: | |
| parts = line.rstrip("\n").split("\t") | |
| if len(parts) < 4: | |
| continue | |
| wav_name = parts[1] | |
| # parts[2] is raw transcription, parts[3] is normalized transcription (numbers spelled out in Thai) | |
| transcript = parts[3].strip() | |
| cleaned = clean_text(transcript) | |
| if args.skip_non_thai: | |
| if has_digit.search(cleaned) or not thai_only_pattern.match(cleaned): | |
| continue | |
| wav_path = os.path.join(audio_dir, wav_name) | |
| if os.path.isfile(wav_path): | |
| records.append((wav_path, cleaned)) | |
| if args.limit > 0: | |
| records = records[:args.limit] | |
| print(f"Evaluating {len(records)} clips from Google FLEURS (th_th) test set...") | |
| edits_c = units_c = 0 | |
| edits_w = units_w = 0 | |
| for i, (wav_path, ref) in enumerate(tqdm(records, desc="FLEURS Eval")): | |
| res = cactus.transcribe(wav_path, weights=args.weights, language="th") | |
| hyp = res["text"].strip() | |
| ec, nc = compute_cer(ref, hyp) | |
| ew, nw = compute_wer(ref, hyp) | |
| edits_c += ec | |
| units_c += nc | |
| edits_w += ew | |
| units_w += nw | |
| if i < 5: | |
| tqdm.write(f"[{i+1}] Ref: {ref}") | |
| tqdm.write(f" Hyp: {hyp}\n") | |
| print(f"\n=== Google FLEURS (th_th) Test Results ({len(records)} clips) ===") | |
| print(f"Model: {args.weights}") | |
| print(f"Character Error Rate (CER): {edits_c / units_c:.2%}") | |
| print(f"Word Error Rate (WER): {edits_w / units_w:.2%}") | |
| if __name__ == "__main__": | |
| main() | |