<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Taruen Blog</title>
        <link>https://taruen.com/blog</link>
        <description>Taruen Blog</description>
        <lastBuildDate>Mon, 08 Jun 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Fine-tuning Whisper for Laz: An End-to-End Journey]]></title>
            <link>https://taruen.com/blog/fine-tuning-whisper-laz</link>
            <guid>https://taruen.com/blog/fine-tuning-whisper-laz</guid>
            <pubDate>Mon, 08 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[How we fine-tuned Whisper-small on Common Voice Laz data, the issues we hit running it on Colab and RunPod, and what's next for Laz speech recognition.]]></description>
            <content:encoded><![CDATA[<p>Taruen is a language technology studio that puts equal emphasis on supporting all languages, regardless of speaker numbers. Turkey is home to many languages besides Turkish, and one of them is Laz — a Kartvelian language spoken primarily along the southeastern Black Sea coast, listed by UNESCO as definitely endangered.</p>
<p>While based in Istanbul, we had the privilege of meeting people from the <a href="https://www.lazenstitu.com/" target="_blank" rel="noopener noreferrer" class="">Laz Institute</a>, an organization founded in 2013 dedicated to preserving, developing, and revitalizing the Laz language. They do extensive work: producing textbooks, organizing language courses (Laz is now an elective in some Turkish schools and universities), publishing books through the <a href="https://lazika.com.tr/" target="_blank" rel="noopener noreferrer" class="">Lazika Yayın Kollektifi</a>, and crucially for our purposes, contributing voices to <a href="https://commonvoice.mozilla.org/" target="_blank" rel="noopener noreferrer" class="">Mozilla Common Voice</a>.</p>
<p>The Institute also operates the <a href="https://www.youtube.com/@LazuriTVLazcaTV/videos" target="_blank" rel="noopener noreferrer" class="">LazuriTV YouTube channel</a>, which hosts roughly 105 hours of spoken Laz content — about 4× the data available on Common Voice (28 hours). However, most of these videos lack transcriptions or subtitles.</p>
<p>Our previous involvement with speech recognition was a <a href="https://arxiv.org/abs/2107.10637" target="_blank" rel="noopener noreferrer" class="">2021 paper on low-resource ASR for Turkic languages</a>. Out of three motivations — sharpening our own skills, learning the latest developments in the speech-to-text field, and wanting to help the Laz Institute eventually transcribe their YouTube archive to feed back into Common Voice — we decided to fine-tune a Whisper-small ASR model on the Common Voice Laz data.</p>
<p>This post documents how we did it. The resulting model is available on the Hugging Face Hub at <a href="https://huggingface.co/Taruen/whisper-small-laz" target="_blank" rel="noopener noreferrer" class="">Taruen/whisper-small-laz</a>. (We've also built a browser-based <a href="https://edge.taruen.com/abc" target="_blank" rel="noopener noreferrer" class="">Laz transliterator</a> that converts Georgian Mkhedruli script into customizable Latin orthographies, with options for exactly the ejective and affricate consonants the model has to get right below.)</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-another-guide">Why another guide?<a href="https://taruen.com/blog/fine-tuning-whisper-laz#why-another-guide" class="hash-link" aria-label="Direct link to Why another guide?" title="Direct link to Why another guide?" translate="no">​</a></h2>
<p>Great fine-tuning guides already exist:</p>
<ol>
<li class=""><a href="https://huggingface.co/blog/fine-tune-whisper" target="_blank" rel="noopener noreferrer" class="">HuggingFace's fine-tune Whisper post</a></li>
<li class=""><a href="https://community.mozilladatacollective.com/fine-tune-a-speech-to-text-model-for-any-language-including-yours/" target="_blank" rel="noopener noreferrer" class="">Mozilla Data Collective's fine-tuning guide</a></li>
</ol>
<p>So why write another? Besides showcasing our own work, we wanted to:</p>
<ol>
<li class="">Show how to fine-tune Whisper on a language <strong>it didn't support at release</strong> — Laz isn't in OpenAI's original language list</li>
<li class="">Cover the workflow <strong>end-to-end with Mozilla Data Collective as the data provider</strong>, with all fine-tuning code in a single file you can tweak</li>
<li class="">Show how to run the pipeline on a <strong>proper GPU cloud</strong> when Colab/Kaggle hit their limits — which they will</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-data-common-voice-laz-via-mozilla-data-collective">The data: Common Voice Laz via Mozilla Data Collective<a href="https://taruen.com/blog/fine-tuning-whisper-laz#the-data-common-voice-laz-via-mozilla-data-collective" class="hash-link" aria-label="Direct link to The data: Common Voice Laz via Mozilla Data Collective" title="Direct link to The data: Common Voice Laz via Mozilla Data Collective" translate="no">​</a></h2>
<p>Common Voice Laz has 34,909 recorded clips totaling around 28 hours. We accessed it via the <a href="https://mozilladatacollective.com/" target="_blank" rel="noopener noreferrer" class="">Mozilla Data Collective</a> Python SDK, which returns a pandas DataFrame with audio file paths and transcriptions plus a <code>split</code> column with Mozilla's official <code>train</code> / <code>dev</code> / <code>test</code> / <code>validated</code> assignments.</p>
<p>A crucial detail we initially missed: <strong>Mozilla speaker-separates these splits</strong>. We verified this explicitly:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Verify zero speaker overlap across official splits</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">train_speakers </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">df</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">df</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'split'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">==</span><span class="token string" style="color:#e3116c">'train'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'speaker_id'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">dropna</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">test_speakers  </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">df</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">df</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'split'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">==</span><span class="token string" style="color:#e3116c">'test'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'speaker_id'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">dropna</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">dev_speakers   </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">df</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">df</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'split'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">==</span><span class="token string" style="color:#e3116c">'dev'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'speaker_id'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">dropna</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"train vs test overlap: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation builtin">len</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">(</span><span class="token string-interpolation interpolation">train_speakers </span><span class="token string-interpolation interpolation operator" style="color:#393A34">&amp;</span><span class="token string-interpolation interpolation"> test_speakers</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">)</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"train vs dev overlap:  </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation builtin">len</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">(</span><span class="token string-interpolation interpolation">train_speakers </span><span class="token string-interpolation interpolation operator" style="color:#393A34">&amp;</span><span class="token string-interpolation interpolation"> dev_speakers</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">)</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"dev vs test overlap:   </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation builtin">len</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">(</span><span class="token string-interpolation interpolation">dev_speakers </span><span class="token string-interpolation interpolation operator" style="color:#393A34">&amp;</span><span class="token string-interpolation interpolation"> test_speakers</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">)</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># All zero — Mozilla's speaker separation holds</span><br></div></code></pre></div></div>
<p>For Laz, the official splits are: train (5,051 rows, 7 speakers), dev (3,551 rows, 12 speakers), test (3,495 rows, 93 speakers), and validated (21,151 rows, 112 speakers — quality-checked but not assigned to a specific split). We used <code>train + validated</code> for training, <code>dev</code> for evaluation during training, and held <code>test</code> out entirely for final evaluation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="adding-laz-to-whispers-vocabulary">Adding Laz to Whisper's vocabulary<a href="https://taruen.com/blog/fine-tuning-whisper-laz#adding-laz-to-whispers-vocabulary" class="hash-link" aria-label="Direct link to Adding Laz to Whisper's vocabulary" title="Direct link to Adding Laz to Whisper's vocabulary" translate="no">​</a></h2>
<p>Whisper doesn't know about Laz. The model uses special tokens like <code>&lt;|en|&gt;</code>, <code>&lt;|tr|&gt;</code>, <code>&lt;|ka|&gt;</code> to mark the target language. To add Laz, we added a custom <code>&lt;|lzz|&gt;</code> token and resized the model's embedding layer:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">new_lang_token </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;|lzz|&gt;"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">processor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tokenizer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">add_tokens</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">new_lang_token</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> special_tokens</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">model</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">resize_token_embeddings</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">len</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">processor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tokenizer</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>We then forced the decoder to start every transcription with our custom language token:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">lang_id          </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> processor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tokenizer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">convert_tokens_to_ids</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">new_lang_token</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">task_id          </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> processor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tokenizer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">convert_tokens_to_ids</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"&lt;|transcribe|&gt;"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">no_timestamps_id </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> processor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tokenizer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">convert_tokens_to_ids</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"&lt;|notimestamps|&gt;"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">manual_forced_ids </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lang_id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> task_id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> no_timestamps_id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">model</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">forced_decoder_ids            </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> manual_forced_ids</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">model</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">generation_config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">forced_decoder_ids </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> manual_forced_ids</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-colab-debacle">The Colab debacle<a href="https://taruen.com/blog/fine-tuning-whisper-laz#the-colab-debacle" class="hash-link" aria-label="Direct link to The Colab debacle" title="Direct link to The Colab debacle" translate="no">​</a></h2>
<p>Our first attempt was on Google Colab Pro. The data preprocessing pipeline — which loads audio files, computes mel spectrograms, and tokenizes labels — hung indefinitely at 0% on A100 and A100 High-RAM runtimes. Same code worked on T4 instances. We initially blamed everything from PyArrow to HuggingFace <code>datasets</code> chunking before identifying the actual cause:</p>
<p><strong>OpenMP thread pool deadlock in PyTorch's STFT operation.</strong> PyTorch's audio feature extraction uses OpenMP for parallelism, and on high-CPU instances the thread pool grew large enough to deadlock during fork operations. T4 instances escaped it because they have fewer cores and thus a smaller thread pool. The fix is one environment variable:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">export OMP_NUM_THREADS=1</span><br></div></code></pre></div></div>
<p>This is a known issue (<a href="https://github.com/pytorch/pytorch/issues/17199" target="_blank" rel="noopener noreferrer" class="">PyTorch #17199</a>) but not well documented in the context of Whisper feature extraction. It's also a good lesson: if your training script "just hangs" with no error on a beefier machine, suspect threading before suspecting your code.</p>
<p>After the deadlock fix, Colab still had issues — runtime disconnections overnight, lost checkpoints because we forgot to save to Google Drive. We pivoted to a proper GPU cloud.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="running-on-runpod">Running on RunPod<a href="https://taruen.com/blog/fine-tuning-whisper-laz#running-on-runpod" class="hash-link" aria-label="Direct link to Running on RunPod" title="Direct link to Running on RunPod" translate="no">​</a></h2>
<p>We moved to <a href="https://runpod.io/?ref=7d8g7enb" target="_blank" rel="noopener noreferrer" class="">RunPod</a>. An A100 80GB SXM instance at $1.49/hour ran the full pipeline in about 5 hours, for a total of ~$8 per training run. Compared to the gymnastics required to keep Colab alive overnight, an SSH-accessible VM with <code>tmux</code> and proper checkpoint persistence is a different world.</p>
<p>Setup:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># After SSHing into the RunPod instance:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pip install transformers accelerate evaluate jiwer tensorboard \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            datasets[audio] datacollective librosa pandas pyarrow</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Set the API key</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export MDC_API_KEY=your_key_here</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export OMP_NUM_THREADS=1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Run inside tmux so a dropped SSH connection doesn't kill the job</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tmux new -s laz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python3 train_whisper_laz.py</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Ctrl+B then D to detach</span><br></div></code></pre></div></div>
<p>The full training script is included at the end of this post.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="first-run-catastrophic-overfitting">First run: catastrophic overfitting<a href="https://taruen.com/blog/fine-tuning-whisper-laz#first-run-catastrophic-overfitting" class="hash-link" aria-label="Direct link to First run: catastrophic overfitting" title="Direct link to First run: catastrophic overfitting" translate="no">​</a></h2>
<p>Our naive first run used a random 90/10 train/test split and no text normalization, weight decay, or audio augmentation. By step 1500, the training loss was approaching zero while validation WER had plateaued at 42%. Classic memorization.</p>
<p>Worse, the random 90/10 split meant the same speaker could appear in both train and test, contaminating the evaluation. The 42% number wasn't even an honest representation of generalization.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="second-run-methodology-improvements">Second run: methodology improvements<a href="https://taruen.com/blog/fine-tuning-whisper-laz#second-run-methodology-improvements" class="hash-link" aria-label="Direct link to Second run: methodology improvements" title="Direct link to Second run: methodology improvements" translate="no">​</a></h2>
<p>For the second run we applied several improvements:</p>
<p><strong>1. Official Mozilla splits</strong>: Train on <code>train + validated</code>, evaluate on <code>dev</code>, hold out <code>test</code> entirely. Speaker-separated by construction.</p>
<p><strong>2. Text normalization</strong>: Whisper outputs are cased and punctuated. If your dataset has inconsistent punctuation, the model wastes capacity (and gets penalized in WER) for guessing punctuation correctly. We strip punctuation and lowercase before training and evaluation:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">normalize_text</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">text</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">str</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token builtin">str</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    text </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> text</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">lower</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    text </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> re</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sub</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">r"[^\w\s']"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> text</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic"># keep word chars, whitespace, and apostrophes (for Laz ejectives like k')</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    text </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> re</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sub</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">r"\s+"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">" "</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> text</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">strip</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> text</span><br></div></code></pre></div></div>
<p><strong>3. Regularization</strong>: Added <code>weight_decay=0.01</code> and turned on Whisper's dropout (off by default):</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">model</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">attention_dropout  </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">model</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">activation_dropout </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.1</span><br></div></code></pre></div></div>
<p><strong>4. Speed perturbation augmentation</strong>: Roughly half the time, randomly stretch audio to 0.9× or 1.1× speed. Free data multiplication, forces the model to learn speaker-rate-invariant features:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">SPEED_RATES </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0.9</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1.0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1.0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1.1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic"># 50% no augment</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rate </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> SPEED_RATES</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">random</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">randint</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">len</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SPEED_RATES</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">audio_array</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> librosa</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">load</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">audio_path</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sr</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mono</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> rate </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1.0</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    audio_array </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> librosa</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">effects</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">time_stretch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">audio_array</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> rate</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">rate</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">audio_array </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> librosa</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">resample</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">audio_array</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> orig_sr</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">sr</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> target_sr</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">16000</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p><strong>5. Earlier stopping</strong>: Capped at 2000 steps instead of 4000, since the first run made it clear nothing useful happens after ~step 1750.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="results">Results<a href="https://taruen.com/blog/fine-tuning-whisper-laz#results" class="hash-link" aria-label="Direct link to Results" title="Direct link to Results" translate="no">​</a></h2>
<p>The improved methodology produced these numbers on the held-out Mozilla test set (3495 examples, never seen during training):</p>
<table><thead><tr><th>Run</th><th>Dev WER</th><th>Test WER</th></tr></thead><tbody><tr><td>Naive (random split, no normalization, no regularization)</td><td>42%</td><td>not measured (split was contaminated)</td></tr><tr><td>Improved (official splits + normalization + regularization + augmentation)</td><td><strong>26.08%</strong></td><td><strong>28.48%</strong></td></tr></tbody></table>
<p>The dev/test gap of about 2.4 points is normal and indicates the model isn't overfit to the dev set either. We were honestly surprised the model worked this well for a language Whisper had never seen — a testament to Whisper's strong multilingual phonetic priors.</p>
<p>Looking at actual predictions on the test set, most errors are diacritic confusions or single-character swaps:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ğormotik gamaǩçǩvidan        | ngormotik gamamçkvidan      ← 2 char errors</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">dido ini on                  | dido ini on                 ← perfect</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aya lemşik va duçvinasinon   | aya lemşik va duçvinasinon  ← perfect</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">nana baba do bere isa renan  | nana baba do bere isa renan ← perfect</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pucis tzǩuni uğun            | puciş tzǩuni uğun           ← single char swap</span><br></div></code></pre></div></div>
<p>The character error rate would likely be much lower than the word error rate — maybe ~10-12% — since most errors are partial-word.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="trying-it-on-real-world-audio">Trying it on real-world audio<a href="https://taruen.com/blog/fine-tuning-whisper-laz#trying-it-on-real-world-audio" class="hash-link" aria-label="Direct link to Trying it on real-world audio" title="Direct link to Trying it on real-world audio" translate="no">​</a></h2>
<p>We ran the model on a 6-minute Laz story from the <a href="https://www.youtube.com/watch?v=lnbBndJEC8E" target="_blank" rel="noopener noreferrer" class="">LazuriTV YouTube channel</a> — out-of-domain conversational speech, not isolated Common Voice sentences. The output was fluent Laz throughout, with consistent diacritic usage and natural word boundaries:</p>
<blockquote>
<p>heva ǩa xalaşi mtsxuli metasi çiruğai va moxtaşa opute mtsxuli do oşkuri mogorum badi şuri çirdumtu...</p>
</blockquote>
<p>A native speaker would still find errors, but the model produces something that's recognizably and consistently Laz — not English-tinged gibberish or Turkish-leaking output.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's next<a href="https://taruen.com/blog/fine-tuning-whisper-laz#whats-next" class="hash-link" aria-label="Direct link to What's next" title="Direct link to What's next" translate="no">​</a></h2>
<p>A few things we explicitly did <em>not</em> solve here:</p>
<p><strong>Punctuation and case restoration.</strong> Since we normalized everything to lowercase without punctuation during training, this system is more accurately called an <strong>ASR</strong> (Automatic Speech Recognition) than a full <strong>STT</strong> (Speech-to-Text). True STT requires restoring sentence boundaries, capitalization, and punctuation — usually as a separate post-processing step using a small language model. We'll cover this in a future post.</p>
<p><strong>Efficient deployment.</strong> Having a fine-tuned model is one thing; serving it efficiently for inference is another. Whisper-small runs comfortably on CPU but a production system would want batching, streaming, and possibly quantization. We'll cover that separately too.</p>
<p><strong>Closing the data loop.</strong> The most impactful next step isn't a better model — it's more data. With a working (if imperfect) Laz ASR model in hand, the natural next step is to transcribe the LazuriTV YouTube archive and have Laz speakers correct the output. Correcting a 28% WER transcription is dramatically faster than transcribing from blank audio, so this human-in-the-loop workflow could realistically double or triple the training set. The Laz Institute is the right partner for this — they have both the linguistic expertise and the community connections to make it happen.</p>
<p>If you're a Laz speaker who would like to help, or an organization working with under-resourced languages and looking for similar work, <a href="mailto:contact@taruen.com" target="_blank" rel="noopener noreferrer" class="">get in touch</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-complete-training-script">The complete training script<a href="https://taruen.com/blog/fine-tuning-whisper-laz#the-complete-training-script" class="hash-link" aria-label="Direct link to The complete training script" title="Direct link to The complete training script" translate="no">​</a></h2>
<!-- -->
<p>The full <code>train_whisper_laz.py</code> is available on our GitHub. The key sections:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># train_whisper_laz.py</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> os</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">environ</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"OMP_NUM_THREADS"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"1"</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic"># critical: prevents PyTorch STFT deadlock</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># ... [data loading, model setup, audio extraction, collator, metrics] ...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">training_args </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Seq2SeqTrainingArguments</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    output_dir</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"./whisper-small-laz"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    per_device_train_batch_size</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">64</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    learning_rate</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1e-5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    warmup_steps</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">500</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    max_steps</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2000</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    fp16</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    eval_strategy</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"steps"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    eval_steps</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">250</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    save_steps</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">250</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    load_best_model_at_end</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    metric_for_best_model</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"wer"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    greater_is_better</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">False</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    weight_decay</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.01</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">trainer </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Seq2SeqTrainer</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    args</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">training_args</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    model</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">model</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    train_dataset</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">dataset</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"train"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    eval_dataset</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">dataset</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"dev"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    data_collator</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">data_collator</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    compute_metrics</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">compute_metrics</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    processing_class</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">processor</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">feature_extractor</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">trainer</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">train</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>]]></content:encoded>
            <category>laz</category>
            <category>whisper</category>
            <category>Mozilla Common Voice</category>
            <category>Speech-to-text</category>
            <category>fine-tuning</category>
        </item>
        <item>
            <title><![CDATA[Common Voice Қазақша]]></title>
            <link>https://taruen.com/blog/common-voice-kazakh-kk</link>
            <guid>https://taruen.com/blog/common-voice-kazakh-kk</guid>
            <pubDate>Wed, 17 Apr 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[English version is here.]]></description>
            <content:encoded><![CDATA[<p><em>English version is <a class="" href="https://taruen.com/blog/common-voice-kazakh">here</a>.</em></p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>Жаңарту (2026)</div><div class="admonitionContent_BuS1"><p>Бұл жазба жарияланғаннан бері жақсы жаңалық: <strong>қазақ тілі Common Voice-та іске
қосылды</strong> және үлес қосуға ашық. Төмендегі 2019 жылғы жазба шақыратын еңбектің
арқасында — интерфейсті аудару және сөйлемдер жинау — қазақ тілінің
тасымалдаушыларының көмегімен тіл <a href="https://github.com/common-voice/common-voice/issues/2974" target="_blank" rel="noopener noreferrer" class="">іске
қосылды</a>. 26.0 нұсқасы
бойынша, үлес қосушылар бірнеше сағат тексерілген аудио жинады — шағын, бірақ
нақты бастама. <strong>Дауысыңызды қазір
<a href="https://commonvoice.mozilla.org/kk" target="_blank" rel="noopener noreferrer" class="">commonvoice.mozilla.org/kk</a> сайтында қоса
аласыз.</strong></p><p>Төмендегі 2019 жылғы жазба сол тарихтың бір бөлігіне айналды.</p></div></div>
<p>Google Assistant немесе Yandex Alisa қазақ тілінде де сөйлесе, керемет болмас па
еді?</p>
<p>Мұндай сөйлесетін ассистенттердің қажетті компоненті болып <code>сөйлеуді тану</code>
(ағылшыншасы “speech recognition”) немесе <code>сөйлеуді мәтінге</code> (ағылшыншасы
“speech-to-text”) деп аталатын жүйе табылады.</p>
<!-- -->
<p>Машина оқыту методтарымен бір тіл үшін жақсы сапалы сөйлеу тану жүйесін болдыру
үшін, ол тілде даустық деректердің аса үлкен көлемі (мыңдаған сағат, төменде
қараңыз) болуы қажет. Бұдан басқа, ол деректер әртүрлі адамдар тарапынан
жазылған болуы және транскрипцияланған болуы керек. Осы уақытқа дейін, тиісті
лицензиялі аудиодеректердің болмауы себепті, көпшілік тілдер үшін <code>ерікті / ашық бастапқы кодты</code> сөйлеуді тану жүйесі қол жетімсіз болып қала береді.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>Жаңарту (2026)</div><div class="admonitionContent_BuS1"><p><a href="https://github.com/openai/whisper" target="_blank" rel="noopener noreferrer" class="">Whisper</a> сияқты алдын ала үйретілген
модельдер мен
<a href="https://en.wikipedia.org/wiki/Fine-tuning_(deep_learning)" target="_blank" rel="noopener noreferrer" class="">файн-тюнингтің</a>
арқасында, бастапқы Whisper қолдамайтын тіл үшін дәл сөйлеу тану жүйесін
болдыруға қажет деректер көлемі бүгінде әлдеқайда азырақ — мыңдаған емес,
ондаған сағат шамасында. Мұның мысалдарын осы блогтың кейінгі жазбаларынан
қараңыз.</p></div></div>
<p>Бақытымызға орай, бұл жағдайды жақсы жаққа өзгертуге болады. 2018 жылы Mozilla,
Firefox веб-браузері және көптеген басқа бағдарламалардың артындағы компания,
<a href="https://commonvoice.mozilla.org/" target="_blank" rel="noopener noreferrer" class="">Common Voice</a> (“Халық дауысы”) жобасын іске
қосты.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="common-voice-деген-не">Common Voice деген не?<a href="https://taruen.com/blog/common-voice-kazakh-kk#common-voice-%D0%B4%D0%B5%D0%B3%D0%B5%D0%BD-%D0%BD%D0%B5" class="hash-link" aria-label="Direct link to Common Voice деген не?" title="Direct link to Common Voice деген не?" translate="no">​</a></h2>
<p>Міне, ол жобаның <a href="https://commonvoice.mozilla.org/about" target="_blank" rel="noopener noreferrer" class="">About</a> бетінен бір
үзінді:</p>
<blockquote>
<p>Common Voice — бүкіл әлемдегі ерікті үлес қосушылардың дауыстарынан құралған,
жалпыға қолжетімді дауыс деректер жиынтығы. Дауыстық бағдарламалар жасағысы
келетіндер бұл деректер жиынтығын машина оқыту модельдерін үйрету үшін
қолдана алады.</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="сіз-қалай-көмектесе-аласыз">Сіз қалай көмектесе аласыз?<a href="https://taruen.com/blog/common-voice-kazakh-kk#%D1%81%D1%96%D0%B7-%D2%9B%D0%B0%D0%BB%D0%B0%D0%B9-%D0%BA%D3%A9%D0%BC%D0%B5%D0%BA%D1%82%D0%B5%D1%81%D0%B5-%D0%B0%D0%BB%D0%B0%D1%81%D1%8B%D0%B7" class="hash-link" aria-label="Direct link to Сіз қалай көмектесе аласыз?" title="Direct link to Сіз қалай көмектесе аласыз?" translate="no">​</a></h2>
<p>Біз <a href="https://taruen.com/" target="_blank" rel="noopener noreferrer" class="">Taruen</a> ретінде қазақ тіліндегі Common Voice-ты іске
қосқымыз келеді, және бұл мақсатқа қарай алғашқы қадамдарды жасадық. Бірақ
Common Voice-та қазақ тілі де іске қосылсын үшін, қазақ тілін жақсы білушілердің
көмегі керек. Егер қазақ тілі ана тіліңіз болса, мына қалай көмектесе аласыз:</p>
<ol>
<li class="">
<p><a href="https://commonvoice.mozilla.org/kk" target="_blank" rel="noopener noreferrer" class="">Common Voice</a> сайты
<a href="https://pontoon.mozilla.org/kk/common-voice" target="_blank" rel="noopener noreferrer" class="">Pontoon</a> атты Mozilla-дың
локализация құралында дұрыс аударылған ма жоқ па екенін
<a href="https://pontoon.mozilla.org/kk/common-voice" target="_blank" rel="noopener noreferrer" class="">тексеріңіз</a>. Аудармалардың шамамен
үштен бірін біз — яғни қазақ тілі ана тілі болмаған адамдар — үстедік, сондықтан
олар қателі болуға мүмкін.</p>
</li>
<li class="">
<p>Біз Common Voice-тың сөйлем жинау құралына жіберген сөйлемдерді
<a href="https://commonvoice.mozilla.org/kk/review" target="_blank" rel="noopener noreferrer" class="">тексеріңіз</a>. Бір тіл Common Voice-та
іске қосылсын үшін, ол тілде ең азы 5000 тексерілген сөйлем болу қажет.</p>
</li>
</ol>
<p>Бұл сөйлемдерді біз М. Әуезов атындағы Әдебиет және өнер институты жариялаған
“Бабалар сөзі” деп аталатын, қазақ халық шығармашылығы туындыларын өз ішіне
алған мықты 100 томдықтың 65 және 68 томдарынан алдық (65-68 томдарда мақалдар
жиналған). Қазақстан Республикасының Авторлық құқық туралы заңының 8-нші бабына
сәйкес, фольклор шығармалары авторлық құқықтан азат және осылайша қоғамдық
байлық (public domain) болып тұр. Демек, оларды Common Voice-та қолдануға
болады. Сонымен, 65-68-нші томдар ішіндегі мақал-мәтелдер Common Voice жобасының
басқа критерийлеріне де сәйкес келеді — оларда сандар, шетелдік әріптер және
рұқсат етілмеген басқа белгілер жоқ, олар әдетте қысқа, педагогикалық / қызықты
және осылайша оқу үшін көңілді.</p>
<p>Common Voice <a href="https://commonvoice.mozilla.org/kk/guidelines" target="_blank" rel="noopener noreferrer" class="">талап ететін</a>
орфография мен грамматиканың дұрыстығын тексеруден басқа, біз сізден ол
сөйлемдер кімді де болса ренжітпейтінін тексеруіңізді өтінеміз. Басқаша
айтқанда, ол сөйлемдерде ерлерге, әйелдерге, ата-аналарға, балаларға, діни
адамдарға, діни емес адамдарға, Оңтүстік Қазақстандықтарға, Солтүстік
Қазақстандықтарға, Батыс Қазақстандықтарға, Шығыс Қазақстандықтарға, Қытайдың
қазақтарына… түсінесіз шығар — тіл тигізетін заттардың болмауы қайырлы. Ол
сөйлемдерден көз жүгірткенде ондайларын көрмедік, бірақ бұл сұраққа да қазақша
жақсы білетін адамдар ғана жауап бере алады.</p>
<p>Бірге, қалаған әр адам да қазақ тілін түсінуші сөйлеу тану жүйесін болдыра
аларлық көлемде аудиодеректер жинай аламыз деген үміттеміз. Жобаның жиі
қойылатын сұрақтар бетінде мозиллашылар жақсы сапалы сөйлеу тану жүйесін
<strong>нөлден</strong> үйрету үшін шамамен 10000 сағат тексерілген аудиожазбалар қажет деп
жазады. Демек бұл — мақсат. 10000 сағат қолжетпестік көп сияқты, бірақ 10 мың
сағатты қазақша білушілердің ең консерватив санына бөлсек те, кісі басына
шамамен 4 секунд аудио тура келеді. Ал 4 секунд — ол әлдеқайда азырақ қорқынышты
сан.</p>
<p>(Жоғарыдағы Жаңартуда айтылғандай, Whisper сияқты алдын ала үйретілген модельді
файн-тюнинг жасауға әлдеқайда аз дерек керек — бірақ дерек көп болғаны еш зиян
етпейді, әрі үлкен, ашық лицензиялы қазақ дауыс деректер жиынтығы модельдер
қалай үйретілсе де құнды болып қала береді.)</p>]]></content:encoded>
            <category>Kazakh</category>
            <category>Mozilla Common Voice</category>
            <category>Speech-to-text</category>
        </item>
        <item>
            <title><![CDATA[Common Voice Kazakh]]></title>
            <link>https://taruen.com/blog/common-voice-kazakh</link>
            <guid>https://taruen.com/blog/common-voice-kazakh</guid>
            <pubDate>Tue, 16 Apr 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[_Бұл мақаланың қазақша нұсқасы мұнда (Kazakh]]></description>
            <content:encoded><![CDATA[<p><em>Бұл мақаланың қазақша нұсқасы <a class="" href="https://taruen.com/blog/common-voice-kazakh-kk">мұнда</a> (Kazakh
version <a class="" href="https://taruen.com/blog/common-voice-kazakh-kk">here</a>).</em></p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>Update (2026)</div><div class="admonitionContent_BuS1"><p>Good news since this was written: <strong>Kazakh has launched on Common Voice</strong> and
is open for contributions. Following the effort the 2019 post below calls for —
translating the interface and collecting sentences, with the help of native
Kazakh speakers — the language
<a href="https://github.com/common-voice/common-voice/issues/2974" target="_blank" rel="noopener noreferrer" class="">went live</a>. As of
the 26.0 release, contributors have accumulated a few hours of validated audio —
a modest but real start. <strong>You can add your voice now at
<a href="https://commonvoice.mozilla.org/kk" target="_blank" rel="noopener noreferrer" class="">commonvoice.mozilla.org/kk</a>.</strong></p><p>The 2019 post below has aged into a piece of that history.</p></div></div>
<p>Wouldn’t it be great, if Google Assistant or Yandex Alisa spoke Kazakh?</p>
<p>One necessary component of such speech-enabled digital assistants is a so-called
<code>automatic speech recognition (ASR)</code> or <code>speech-to-text (STT)</code> system.</p>
<!-- -->
<p>Large amounts of audio data (thousands of hours, see below), from many different
people, along with transcriptions, are needed to train a good speech-to-text
system using <code>machine learning</code> methods. So far, due to lack of appropriately
licensed, freely available audio data in them, building a high-accuracy
free/libre/open-source software (FLOSS) speech recognition system is out of
reach for most languages.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>Update (2026)</div><div class="admonitionContent_BuS1"><p>Thanks to pre-trained models like <a href="https://github.com/openai/whisper" target="_blank" rel="noopener noreferrer" class="">Whisper</a>
and <a href="https://en.wikipedia.org/wiki/Fine-tuning_(deep_learning)" target="_blank" rel="noopener noreferrer" class="">fine-tuning</a>,
the amount of training data needed to build an accurate ASR
system for a language the original Whisper does not support is much less
nowadays — in the order of tens of hours, not thousands. See subsequent posts
on this blog for examples of that.</p></div></div>
<p>Fortunately, there is a way to change this for the better. In 2018, Mozilla, the
company behind the Firefox web-browser and many other programs, launched the
<a href="https://commonvoice.mozilla.org/" target="_blank" rel="noopener noreferrer" class="">Common Voice</a> project.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-mozilla-common-voice">What is Mozilla Common Voice?<a href="https://taruen.com/blog/common-voice-kazakh#what-is-mozilla-common-voice" class="hash-link" aria-label="Direct link to What is Mozilla Common Voice?" title="Direct link to What is Mozilla Common Voice?" translate="no">​</a></h2>
<p>Here is a quote from the project's
<a href="https://commonvoice.mozilla.org/about" target="_blank" rel="noopener noreferrer" class="">About</a> page:</p>
<blockquote>
<p>Common Voice is a publicly available voice dataset, powered by the voices of
volunteer contributors around the world. People who want to build voice
applications can use the dataset to train machine learning models.</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-you-can-help">How you can help<a href="https://taruen.com/blog/common-voice-kazakh#how-you-can-help" class="hash-link" aria-label="Direct link to How you can help" title="Direct link to How you can help" translate="no">​</a></h2>
<p>We at <a href="https://taruen.com/" target="_blank" rel="noopener noreferrer" class="">Taruen</a> want to launch Common Voice in Kazakh, and
took the first steps towards that goal. But for that to happen, we need
help from native speakers of Kazakh. If you are one, here is how you can help:</p>
<ol>
<li class="">
<p><a href="https://pontoon.mozilla.org/kk/common-voice/" target="_blank" rel="noopener noreferrer" class="">Review</a> whether the <a href="https://commonvoice.mozilla.org/kk" target="_blank" rel="noopener noreferrer" class="">Common
Voice website</a> has been correctly translated
into Kazakh on <a href="https://pontoon.mozilla.org/kk/common-voice/" target="_blank" rel="noopener noreferrer" class="">Pontoon</a>,
Mozilla’s localization tool. About one-third of the translations were authored
by us — non-native Kazakh speakers — and thus might be incorrect.</p>
</li>
<li class="">
<p><a href="https://commonvoice.mozilla.org/kk/review" target="_blank" rel="noopener noreferrer" class="">Review</a> Kazakh sentences we’ve
submitted to the Common Voice Sentence Collector tool. At least 5000 reviewed
sentences are needed to “launch” a language on Common Voice.</p>
</li>
</ol>
<p>These sentences were taken from Volumes 65 and 68 of the mighty 100-volume
set with works of Kazakh folklore, called “Бабалар сөзі” and published by M.
Auezov Institute of Literature and Art. By Article 8 of Kazakhstani Copyright
Law, works of folklore are exempt from copyright and are thus in the public
domain and suitable for submitting to Common Voice. Moreover, proverbs from
volumes 65 and 68 match other criteria of the Common Voice project as well —
they don’t contain digits, foreign letters and other symbols not allowed in the
dataset, they are mostly short, arguably pedagogical/entertaining and thus fun
to read.</p>
<p>Besides usual checks for correct spelling and grammaticality
<a href="https://commonvoice.mozilla.org/kk/guidelines" target="_blank" rel="noopener noreferrer" class="">required</a> by Common Voice, when
reviewing sentences, we also ask you to make sure that none of the sentences are
remotely offensive to men, women, parents, children, religious people,
non-religious people, Southern Kazakhstanis, Northern Kazakhstanis, Western
Kazakhstanis, Eastern Kazakhstanis, Kazakhs of China, Kazakhs of … You get the
idea. A glimpse over the sentences did not suggest that they would contain
anything like that, but again, that’s something for native speakers to judge.</p>
<p>We hope that together we can assemble enough data so that anyone who wishes to
do so can train a speech-to-text system for Kazakh. On the FAQ page of the
project, Mozillians mention 10000 hours as an approximate number of validated
hours needed to train a production speech-to-text system <strong>from scratch</strong>, so
that’s something to strive for. It does sound like a lot, but when divided among
even a conservative number of Kazakh speakers, it requires each person to record
sentences for about 4 seconds. That is a much less scary number.</p>
<p>(As the Update above notes, fine-tuning a pre-trained model like Whisper needs
far less data — but more data never hurts, and a large, openly-licensed Kazakh
voice dataset is valuable regardless of how models are trained.)</p>]]></content:encoded>
            <category>Kazakh</category>
            <category>Mozilla Common Voice</category>
            <category>Speech-to-text</category>
        </item>
    </channel>
</rss>