File size: 11,645 Bytes
c6818dd
 
 
 
016e356
 
a2d9b4e
016e356
c6818dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
016e356
 
c6818dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
016e356
c6818dd
016e356
c6818dd
016e356
 
 
 
 
 
 
 
c6818dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
016e356
 
 
 
 
 
 
 
 
c6818dd
016e356
 
 
 
 
 
 
 
 
 
c6818dd
 
 
 
 
 
 
016e356
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c6818dd
 
 
016e356
c6818dd
 
 
 
 
 
 
016e356
c6818dd
 
016e356
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a2d9b4e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
016e356
 
a2d9b4e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
016e356
 
 
 
 
 
f9fad03
 
016e356
 
 
 
 
 
 
 
 
 
 
c6818dd
016e356
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
import os 
import torch
import torch.nn as nn
import torchaudio
import numpy as np  # type: ignore
import gradio as gr  # type: ignore
import pandas as pd
from transformers import pipeline
from huggingface_hub import hf_hub_download
from torchaudio.models import Conformer

class ASRConformerModel(nn.Module):
    def __init__(self, input_dim, vocab_size):
        super().__init__()
        self.encoder = Conformer(
            input_dim=input_dim,
            num_heads=4,
            ffn_dim=512,
            num_layers=4,
            depthwise_conv_kernel_size=31,
            dropout=0.1
        )
        self.classifier = nn.Linear(input_dim, vocab_size)

    def forward(self, x, lengths):
        x, lengths = self.encoder(x, lengths=lengths)
        x = self.classifier(x)
        return x, lengths


VOCAB = set("abcdefghijklmnopqrstuvwxyz '")
char_to_idx = {ch: i + 1 for i, ch in enumerate(sorted(VOCAB))}  # 0 for CTC blank

def greedy_decode(log_probs, blank=0):
    pred_ids = log_probs.argmax(dim=-1)  # [T, B]
    pred_ids = pred_ids.transpose(0, 1)  # [B, T]
    predictions = []
    for seq in pred_ids:
        prev = blank
        pred = []
        for i in seq:
            if i != prev and i != blank:
                pred.append(i.item())
            prev = i
        predictions.append(pred)
    return predictions

def encode(text):
    return torch.tensor([char_to_idx[c] for c in text.lower() if c in char_to_idx], dtype=torch.long)

def decode_to_text(predictions, idx_to_char):
    return [''.join(idx_to_char[i] for i in pred if i in idx_to_char) for pred in predictions]

# Load fine-tuned Whisper model
transcriber_whisper = pipeline("automatic-speech-recognition", model="OwLim/whisper-sundanese-finetune")
transcriber_wav2vec = pipeline("automatic-speech-recognition", model="indonesian-nlp/wav2vec2-indonesian-javanese-sundanese")


device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
SAMPLE_RATE = 16_000

model_path = hf_hub_download(repo_id="Blebbyblub/javanese-conformer-asrV2", filename="pytorch_model.bin")
model = ASRConformerModel(input_dim=80, vocab_size=29).to(device)
model.load_state_dict(torch.load(model_path, map_location=device))

examples_audio = [
    file for file in os.listdir("./") if file.endswith(".wav")
]

idx_to_char = {v: k for k, v in char_to_idx.items()}

def transcribe(audio, model_selection):
    sr, waveform = audio

    # Change into Mono Audio
    if waveform.ndim > 1:
        waveform = waveform.mean(axis=1)

    # Normalisasi
    waveform = waveform.astype(np.float32)
    waveform /= np.max(np.abs(waveform))

    if "Conformer" == model_selection :
        mel_transform = torchaudio.transforms.MelSpectrogram(sample_rate=SAMPLE_RATE, n_mels=80)

        waveform = torch.from_numpy(waveform).float()
        if sr != SAMPLE_RATE:
            waveform = torchaudio.transforms.Resample(sr, SAMPLE_RATE)(waveform)

        waveform = waveform.unsqueeze(0)
        mel = mel_transform(waveform).squeeze(0).transpose(0, 1)  # [time, mel]
        mel = mel.unsqueeze(0).to(device)
        input_length = torch.tensor([mel.size(1)]).to(device)

        model.eval()
        with torch.no_grad():
            output, output_lengths = model(mel, input_length)
            log_probs = output.log_softmax(2).transpose(0, 1)
            pred_ids = greedy_decode(log_probs)
            pred_text = decode_to_text(pred_ids, idx_to_char)[0]

        return pred_text

    if "Wav2Vec" == model_selection :
        selected_model = transcriber_wav2vec
    elif "Whisper" == model_selection:
        selected_model = transcriber_whisper

    return selected_model({
        "sampling_rate" : sr,
        "raw" : waveform
    })["text"]

def clear():
    return None, ""

# --- Tab 1: Transcribe ---
with gr.Blocks() as tab_transcribe:
    model_selector = gr.Radio(choices=["Whisper", "Conformer", "Wav2Vec"], label="Choose Model", info="This will effect the model that you use for transcribing", )    
    with gr.Row():
        with gr.Column(scale=1):
            audio_input = gr.Audio(sources="microphone", label="Record Your Voice")
            with gr.Row():
                subBtn = gr.Button("Submit", variant="primary")
                clrBtn = gr.ClearButton(variant="stop")

        with gr.Column(scale=1):
            output_text = gr.Textbox(label="Transcription", placeholder="Waiting for Input", lines=3)

    gr.Examples(
        examples=examples_audio,  # List of audio file paths
        inputs=audio_input,
        label="Try with Example Audio"
    )

    subBtn.click(fn=transcribe, inputs=[audio_input, model_selector], outputs=output_text)
    clrBtn.click(fn=clear, outputs=[audio_input, output_text])

# --- Tab 2: Penjelasan Model Fine-Tuned ---
with gr.Blocks() as tab_background:
    gr.HTML("""
    <h3>Latar Belakang Project:</h3>
    <p>
        Pada project kita kali ini, kami ingin membuat suatu model AI Speech Recognition yang mampu untuk menerima, mengenali dan memproses input berupa ucapan lisan multilingual termasuk dengan adanya bahasa lokal (seperti bahasa daerah). Projek kami didasarkan dengan kurangnya pengaplikasian bidang Speech Recognition pada low-resource language atau bahasa-bahasa yang memiliki data atau sumber daya yang relatif lebih sedikit. Kami ingin membuat model yang dapat mendeteksi pengguna baik berbahasa inggris, berbahasa indonesia maupun berbahasa daerah seperti bahasa jawa.
    </p>
    <br>    
    <p>
        Dengan adanya multi-lingual speech recognition, pengolahan lisan dalam bahasa daerah seperti di Indonesia akan lebih terbantu dan semakin banyak pula. Terlebih lagi, pengolahan lisan dalam bahasa daerah masih sedikit dan kurang diperhatikan walaupun di Indonesia sendiri memiliki lebih dari 500 ragam banyaknya. Dari hal ini, kami ingin mengembangkan dua model AI dalam ranah Speech Recognition, yaitu Conformer dan Whisper untuk dapat belajar dan memproses bahasa multilingual.

        Model yang telah kami fine tune merupakan hasil <b>fine-tuning dari Whisper dan Conformer</b> untuk mendukung bahasa lokal di Indonesia, khususnya bahasa Jawa dan Sunda.
        Model dilatih menggunakan kombinasi dataset <b>OpenSLR</b> berikut:
            <br>
                <a href="https://openslr.org/35/" target="_blank" style="text-decoration:none;">             
                        <b>SLR35</b> - Large Javanese ASR training data set
                </a>        
            <br>
                <a href="https://openslr.org/36/" target="_blank" style="text-decoration:none;">             
                        <b>SLR36</b> - Large Sundanese ASR training data set
                </a>        
            <br>
                <a href="https://openslr.org/41/" target="_blank" style="text-decoration:none;">             
                        <b>SLR41</b> - High quality TTS data for Javanese
                </a>        
            <br>
            <a href="https://openslr.org/44" target="_blank" style="text-decoration:none;">                 
                    <b>SLR44</b> - High quality TTS data for Sundanese.
            </a>
        
                <br>
        Model ini diharapkan bisa meningkatkan akurasi untuk bahasa yang sebelumnya kurang terwakili dalam model global.
    </p>
    <h3>Tujuan Project:</h3>
    <ul>
        <li>Dapat memahami ucapan lisan multilingual termasuk dengan bahasa <i>low-resource language</i>.</li>
        <li>Ikut serta dalam pengembangan teknologi dalam pelatihan model pada <i>low-resource language</i>.</li>
        <li>Berpartisipasi dalam pelestarian dan pembudidayaan bahasa-bahasa daerah di Indonesia yang kurang mendapatkan perhatian.</li>
    </ul>
    """)

# --- Tab 3: Arsitektur Model ---
with gr.Blocks() as tab_architecture:
    gr.Markdown("### 🧠 Whisper Architecture")
    with gr.Row():
        with gr.Column():
            gr.HTML("""
            <div>
                <p>
                    Whisper adalah model Automatic Speech Recognition (ASR) open-source yang dikembangkan oleh OpenAI. 
                    Model ini dilatih menggunakan <strong>680,000 jam</strong> data audio multilingual dan multitask, 
                    termasuk data yang memiliki noise dan hasil transkripsi otomatis untuk meningkatkan robustness.
                </p>
                <p>
                    Whisper mampu mentranskrip audio dengan <em>background noise</em>, serta memahami berbagai aksen dan 
                    bahasa secara efektif.
                </p>
            </div>
            """)
        with gr.Column():
            gr.Image("whisper.png", show_label=False, show_download_button=False)

    gr.Markdown("### πŸ”Š Conformer Architecture")
    with gr.Row():
        with gr.Column():
            gr.HTML("""
            <div>
                <p>
                    <strong>Conformer (Convolutional Transformer)</strong> adalah arsitektur deep learning yang dirancang khusus untuk pengolahan sinyal suara, seperti speech recognition.
                </p>
                <br>
                <p>Model ini menggabungkan dua komponen utama:</p>
                <ul>
                    <li><strong>Transformer:</strong> Menangkap hubungan global dalam data, seperti relasi antar kata dalam kalimat.</li>
                    <li><strong>CNN (Convolutional Neural Network):</strong> Menangkap pola lokal seperti fonem atau suku kata dalam suara.</li>
                </ul>
                <p>
                    Dengan kombinasi ini, Conformer dapat memahami baik konteks global maupun detail lokal dari sinyal suara secara lebih efektif.
                </p>
            </div>
            """)
        with gr.Column():
            gr.Image("conformer.png", show_label=False, show_download_button=False)


import gradio as gr
import pandas as pd

data_wer = {
    "Model": ["Whisper", "Conformer"],
    "WER": [11, 50],
}

data_cer = {
    "Model": ["Whisper", "Conformer"],
    'CER': [0, 20]
}

df_WER = pd.DataFrame(data_wer)
df_CER = pd.DataFrame(data_cer)

# --- Tab 4: Tabel Hasil Evaluasi ---
with gr.Blocks() as tab_results:
    gr.Markdown("## πŸ“Š Best Error Rate (WER / CER)")
    with gr.Row():
        gr.BarPlot(
            df_WER,
            x="Model",
            y="WER",
            title="Best WER by Model",
            tooltip=["Model", "WER"],
            y_lim=(0, 100),
            container=False,
            height=400,
            width=300
        )

        gr.BarPlot(
            df_CER,
            x="Model",
            y="CER",
            title="Best CER by Model",
            tooltip=["Model", "CER"],
            y_lim=(0, 100),
            container=False,
            height=400,
            width=300
        )


# --- Tab 5: Fine-tuning Info ---
with gr.Blocks() as tab_authors:
    gr.HTML("""
    <h1 style='text-align:center;'>πŸ‘¨β€πŸ’» Fine-Tuning Information</h1>
    <p style='text-align:center;'>
        Model ini di-fine-tune oleh <b>Brian, Nathan, Owen, Raenault</b> menggunakan framework Hugging Face Transformers dan PyTorch <br><br>
        Semua pelatihan dilakukan di Google Colab.
    </p>
    <p style='text-align:center;'>
        Lihat model di <a href='https://huggingface.co/OwLim/whisper-java-SLR41-SLR35' target='_blank'>Hugging Face Model Hub</a>.
    </p>
    """)

# Gabungkan semua tabs ke dalam aplikasi utama
demo = gr.TabbedInterface(
    [tab_transcribe, tab_background, tab_architecture, tab_results, tab_authors],
    ["Transcribe", "Latar Belakang", "Arsitektur", "Evaluasi", "Fine-Tuned By"],
    theme=gr.themes.Soft(),
    title="Multilingual ASR Model"
)

if __name__ == "__main__":
    demo.launch()