Views
No views yet
lstm_v1 performs frame-level IPA phone classification: given the hidden states
of mHuBERT-147, each frame is assigned one of 45 IPA symbols. phone_mask_v1
adds a second utility head that scores which frames should be kept for decoding.
ctc_v1 is a BiLSTM CTC head that directly predicts a phone sequence with an
extra blank symbol. conformer_v1 is a frozen-backbone Conformer CTC head with
relative position attention and local attention windowing.| Directory | Architecture | Buckeye PER ↓ | Notes |
|---|---|---|---|
lstm_v1/ | BiLSTM (2 layers, hidden 256) | 0.261 | frame-level baseline |
phone_mask_v1/ | BiLSTM phone head + BiLSTM utility head | 0.241 | masked decoding, threshold = 0.50 |
ctc_v1/ | BiLSTM CTC head | 0.215 | frozen backbone |
conformer_v1/ | Conformer CTC head (2 layers, dim 192, 6 heads) | 0.252 | frozen backbone, local window = 25 |
phone_mask_v1 predicts both frame-level phone logits and a frame-utility score. At inference time the utility score is thresholded and only the selected frames are kept for decoding.
ctc_v1 is CTC-head, yields TIMIT TEST PER = 0.0957, Buckeye PER = 0.2150.
conformer_v1 yields TIMIT TEST PER = 0.1060, Buckeye PER = 0.2516ipa_map.json.sil aɪ aʊ b d dʒ eɪ f g h i j k l l̩ m m̩ n n̩ oʊ p r s t tʃ u v w z æ ð ŋ ɑ ɔ ɔɪ ə ɛ ɪ ɹ̩ ɾ ʃ ʊ ʒ ʔ θbcl+b, dcl+d, …) → merged into single release phoneer / axr → ɹ̩ (syllabic r); el → l̩; em → m̩; en → n̩ah / ax / ax-h → ə; dx → ɾ (flap); q → ʔaen, own, …) → merged with oral counterparts| System | Test set | PER ↓ | Approach |
|---|---|---|---|
| This work (ctc_v1) | Buckeye val | 0.215 | frozen-backbone CTC head |
| Wav2IPA | Buckeye val | 0.2479 | CTC fine-tuning |
lstm_v1:1import torch
2from transformers import AutoFeatureExtractor, AutoModel, AutoConfig
3import json
4import librosa
5from huggingface_hub import snapshot_download
6
7
8repo_id = "istomin9192/mHuBERT-147-ipa-head"
9local_dir = snapshot_download(repo_id=repo_id)
10head_dir = f"{local_dir}/lstm_v1"
11ipa_map_path = f"{local_dir}/ipa_map.json"
12
13config = AutoConfig.from_pretrained(head_dir, trust_remote_code=True)
14backbone = AutoModel.from_pretrained(config.base_model)
15feature_extractor = AutoFeatureExtractor.from_pretrained(config.base_model)
16backbone.eval()
17head = AutoModel.from_pretrained(head_dir, trust_remote_code=True)
18head.eval()
19with open(ipa_map_path, "r", encoding="utf-8") as f:
20 id2phone = json.load(f)["id2phone"]
21
22wav, sr = librosa.load(wav_file, sr=16000, mono=True)
23inputs = feature_extractor(wav, sampling_rate=16000, return_tensors="pt")
24with torch.no_grad():
25 emb = backbone(**inputs).last_hidden_state # [1, T, 768]
26 outputs = head(emb)
27 logits = outputs.logits # [1, T, 45]
28 pred_ids = logits.argmax(-1)[0].tolist()
29
30phones = [id2phone[str(i)] for i in pred_ids]
31print(phones)phone_mask_v1:1import torch
2from transformers import AutoFeatureExtractor, AutoModel, AutoConfig
3import json
4import librosa
5from huggingface_hub import snapshot_download
6
7repo_id = "istomin9192/mHuBERT-147-ipa-head"
8local_dir = snapshot_download(repo_id=repo_id)
9head_dir = f"{local_dir}/phone_mask_v1"
10ipa_map_path = f"{local_dir}/ipa_map.json"
11
12config = AutoConfig.from_pretrained(head_dir, trust_remote_code=True)
13backbone = AutoModel.from_pretrained(config.base_model)
14feature_extractor = AutoFeatureExtractor.from_pretrained(config.base_model)
15backbone.eval()
16phone_mask = AutoModel.from_pretrained(head_dir, trust_remote_code=True)
17phone_mask.eval()
18
19with open(ipa_map_path, "r", encoding="utf-8") as f:
20 id2phone = json.load(f)["id2phone"]
21
22wav, sr = librosa.load(wav_file, sr=16000, mono=True)
23inputs = feature_extractor(wav, sampling_rate=16000, return_tensors="pt")
24
25with torch.no_grad():
26 emb = backbone(**inputs).last_hidden_state # [1, T, 768]
27 outputs = phone_mask(emb)
28 phone_logits = outputs.phone_logits # [1, T, 45]
29 utility_logits = outputs.utility_logits # [1, T]
30
31pred_ids = phone_logits.argmax(-1)[0]
32utility = torch.sigmoid(utility_logits[0])
33mask = utility > config.default_threshold
34
35phones = [id2phone[str(i)] for i in pred_ids[mask].tolist()]
36print(phones)ctc_v1:1import json
2import librosa
3import torch
4from huggingface_hub import snapshot_download
5from transformers import AutoConfig, AutoFeatureExtractor, AutoModel
6
7
8repo_id = "istomin9192/mHuBERT-147-ipa-head"
9local_dir = snapshot_download(repo_id=repo_id)
10head_dir = f"{local_dir}/ctc_v1"
11ipa_map_path = f"{local_dir}/ipa_map.json"
12
13config = AutoConfig.from_pretrained(head_dir, trust_remote_code=True)
14backbone = AutoModel.from_pretrained(config.base_model)
15feature_extractor = AutoFeatureExtractor.from_pretrained(config.base_model)
16backbone.eval()
17ctc_head = AutoModel.from_pretrained(head_dir, trust_remote_code=True)
18ctc_head.eval()
19
20with open(ipa_map_path, "r", encoding="utf-8") as f:
21 id2phone = {int(k): v for k, v in json.load(f)["id2phone"].items()}
22
23wav, sr = librosa.load(wav_file, sr=16000, mono=True)
24inputs = feature_extractor(wav, sampling_rate=16000, return_tensors="pt")
25
26with torch.no_grad():
27 emb = backbone(**inputs).last_hidden_state
28 logits = ctc_head(emb).logits[0]
29
30pred_ids = logits.argmax(dim=-1).tolist()
31blank_id = config.architecture["blank_id"]
32
33phones = []
34prev = blank_id
35for pid in pred_ids:
36 if pid != blank_id and pid != prev:
37 phones.append(id2phone[pid])
38 prev = pid
39
40print(phones)conformer_v1:1import json
2import librosa
3import torch
4from huggingface_hub import snapshot_download
5from transformers import AutoConfig, AutoFeatureExtractor, AutoModel
6
7
8repo_id = "istomin9192/mHuBERT-147-ipa-head"
9local_dir = snapshot_download(repo_id=repo_id)
10head_dir = f"{local_dir}/conformer_v1"
11ipa_map_path = f"{local_dir}/ipa_map.json"
12
13config = AutoConfig.from_pretrained(head_dir, trust_remote_code=True)
14backbone = AutoModel.from_pretrained(config.base_model)
15feature_extractor = AutoFeatureExtractor.from_pretrained(config.base_model)
16backbone.eval()
17conformer_head = AutoModel.from_pretrained(head_dir, trust_remote_code=True)
18conformer_head.eval()
19
20with open(ipa_map_path, "r", encoding="utf-8") as f:
21 id2phone = {int(k): v for k, v in json.load(f)["id2phone"].items()}
22
23wav, sr = librosa.load(wav_file, sr=16000, mono=True)
24inputs = feature_extractor(wav, sampling_rate=16000, return_tensors="pt")
25
26with torch.no_grad():
27 emb = backbone(**inputs).last_hidden_state
28 input_len = emb.shape[1]
29 logits = conformer_head(emb, input_lengths=[input_len]).logits[0]
30
31pred_ids = logits.argmax(dim=-1).tolist()
32blank_id = config.architecture["blank_id"]
33
34phones = []
35prev = blank_id
36for pid in pred_ids:
37 if pid != blank_id and pid != prev:
38 phones.append(id2phone[pid])
39 prev = pid
40
41print(phones)