Ąžuolas — lietuvių kalbos atpažinimo modelis

Ąžuolas atpažįsta lietuvišką kalbą iš garso įrašų. Tai whisper-large-v3 modelis, SFT apmokytas su visu LIEPA-3 garsynu — skaitoma kalba, laisva kalba ir fonetiniai įrašai.

Iš viso apie 9,8 tūkst. valandų garso: 5 230 val. skaitomos kalbos, 4 359 val. laisvos kalbos ir 217 val. fonetinių įrašų. Pats LIEPA-3 garsynas yra maždaug 11,4 tūkst. valandų — likusi dalis nenaudota, nes reikia apdoroti tą dataset'o dalį, o tikslas buvo išvengti papildomo apdorojimo.

Modelis pavadintas simbolinio Ąžuolo vardu Ąžuolyno bibliotekos garbei. Jis didžiausias ir lėčiausias iš čia lyginamų lietuviškų modelių, tačiau tiksliausias.

Vienas svarbus dalykas prieš pradedant. Ąžuolas prigalvoja tekstą, kai garse nieko nėra — per tylą ar foninį šnypštimą jis „išgirsta" sklandžius lietuviškus sakinius. Tai reali problema, ne smulkmena. Kaip su tuo dirbti — skyriuje Ką reikia žinoti.

Rezultatai

Visi trys modeliai išbandyti su ta pačia programa — ta, kurią parašė paprika-whisper-lt-v3 autorius (kristijonasatpro/paprika). Naudotos jo dekodavimo nuostatos ir jo teksto normalizavimas. Taip visi trys lyginami vienodai, o ne kiekvienas savo taisyklėmis.

FLEURS LT — 985 įrašai, 2,96 val.

modelis dydis WER % WER % be skaitmenų greitis
Ąžuolas (whisper-large-v3) 1,55 mlrd. 9,05 4,68 26× realaus laiko
paprika-whisper-lt-v3 (large-v3-turbo) 0,81 mlrd. 12,06 7,78 83× realaus laiko
kmynas-parakeet-lt-v3 (Parakeet-TDT) 0,6 mlrd. 17,73 13,57 819× realaus laiko

Common Voice 26.0 LT — 5 877 įrašai, 8,50 val.

modelis WER % greitis
Ąžuolas 4,60 27× realaus laiko
paprika-whisper-lt-v3 8,60 76× realaus laiko
kmynas-parakeet-lt-v3 22,86 956× realaus laiko

WER — žodžių klaidų dalis. Mažiau yra geriau.

Abu testai visiems trims modeliams yra iš kitos srities: nei FLEURS, nei Common Voice nėra LIEPA-3 dalis, ir jų įrašymo sąlygos kitokios. Tai verta pabrėžti, nes paprika autorius sąmoningai neskelbia tokio skaičiaus — jo paruoštas FLEURS rinkinys pasirodė esąs 44 iš 44 skaitmeninės tylos įrašų, ir visi iš jo gauti skaičiai buvo atšaukti. Tad ši lentelė yra pirmas šių trijų modelių palyginimas su nepažįstamu garsu ir su vienoda tvarka.

Greičiai išmatuoti viena RTX PRO 6000, fp16. Su kita įranga skaičiai bus kitokie. Ąžuolas maždaug 3× lėtesnis už paprika, nes turi 32 dekoderio sluoksnius, o turbo — tik 4. Kmynas yra visai kitos sandaros ir maždaug 30× spartesnis už Ąžuolą.

Kodėl yra stulpelis „be skaitmenų"

FLEURS atsakymuose skaičiai rašomi skaitmenimis (25), o šie modeliai rašo žodžiais (dvidešimt penki). Formaliai tai klaida, nors atpažinta teisingai. Paprika autorius įvertino, kad tai kainuoja „maždaug 4 WER". Pasitvirtino beveik tiksliai, ir visiems trims vienodai:

visas be skaitmenų skaitmenų kaina
Ąžuolas 9,05 4,68 4,37
paprika-whisper-lt-v3 12,06 7,78 4,28
kmynas-parakeet-lt-v3 17,73 13,57 4,16

Kaina beveik vienoda visiems, tad tai atsakymų teksto, o ne modelių savybė. Stulpelis „be skaitmenų" geriau parodo tikrą atpažinimo kokybę.

Tikras įrašas — 57 minutės iš renginio

Testų įrašai trumpi, tvarkingi ir skaitomi. O čia tie patys trys modeliai su tikru įrašu: Vido Mačiulio knygos „Kitas gyvenimas" pristatymu Ąžuolyno bibliotekoje. 57,1 minutės nerepetuotos kalbos su publika, persidengiančiais balsais ir plojimais (youtube.com/watch?v=BrfheG5EJR4).

Šįkart naudota visa paprika ilgų įrašų programa, ne tik nuostatos: tylos filtras, karpymas pauzėse, tada atpažinimas kiekvienoje dalyje atskirai.

modelis žodžių teksto įvairumas greitis dažniausiai pasikartojusi frazė
Ąžuolas 6 646 0,998 8,9× realaus laiko „ir taip toliau aš" ×4
paprika-whisper-lt-v3 6 636 0,998 35,0× realaus laiko „ir taip toliau aš" ×4
kmynas-parakeet-lt-v3 6 554 0,998 1 039× realaus laiko „ir taip toliau aš" ×4

Kiek modelių tekstai sutampa tarpusavyje:

Ąžuolas ↔ paprika 93,1 %
Ąžuolas ↔ kmynas 90,3 %
paprika ↔ kmynas 88,6 %
  • Visi trys sutampa 92 žodžių ribose — 1,4 %. Nė vienas nepraleidžia ir neprigalvoja didelių gabalų. Būtent tai svarbiausia ilguose įrašuose, ir trumpų įrašų WER to nerodo.
  • Teksto įvairumas 0,998 visiems — niekas neįstrigo kartodamas tą patį. Dažniausia frazė visuose trijuose tekstuose ta pati — „ir taip toliau aš", keturis kartus. Tai tikra kalbos frazė, ne modelio klaida. Taip veikia karpymas pauzėse; tie patys modeliai, karpant fiksuotu žingsniu, jau įstringa.

Šios lentelės greičiai išmatuoti fp32, o ne fp16, nes paprika programa garso požymius verčia į fp32. Todėl Ąžuolas čia rodo 8,9×, o FLEURS lentelėje su fp16 — 26×. Šių dviejų lentelių greičių tarpusavyje nelyginkite.

Patikrinta ir kita programa

Tie patys modeliai išmatuoti dar ir nepriklausoma programa (šio projekto eval_compare.py, kitos nuostatos, kitas WER skaičiavimas):

FLEURS / CV 26.0 paprika programa nepriklausoma skirtumas
Ąžuolas 9,05 / 4,60 9,12 / 4,97 0,07 / 0,37
paprika-whisper-lt-v3 12,06 / 8,60 11,84 / 8,42 0,22 / 0,18

Dvi nepriklausomos programos sutampa 0,4 punkto ribose visur ir į abi puses. Todėl eiliškumu galima tikėti. Nė viena programa nepataikauja savo autoriaus modeliui: paprika programa pačią paprika įvertina net kiek griežčiau.

Dar viena patikra: kmynas modelis per šią programą gavo FLEURS 17,73 ir be skaitmenų 13,57, o jo pačio kortelėje paskelbta 17,15 ir 13,11. Skirtumas 0,6 ir 0,5 punkto. Tą skaičių gavo pats programos autorius su tuo pačiu modeliu, tad sutapimas rodo, kad programa perkelta teisingai.

Kaip naudoti

Modelis rašo mažosiomis raidėmis ir be skyrybos ženklų — taip užrašyti LIEPA-3 atsakymai. Jis rašo ir taip, kaip pasakyta, o ne kaip taisyklinga: turim, ne turime.

Jei reikia skyrybos, didžiųjų raidžių ar kalbėtojų žymų — tai atskiri modeliai. Paprika saugykloje esantis transcribe_file.py visa tai padaro aplink Whisper modelį ir veikia su šiuo per --model.

Formatai

Modelis paskelbtas trimis pavidalais. Svoriai visur tie patys — tas pats best_model.pt, iš kurio gauti visi šios kortelės skaičiai — ir visur fp16.

pavidalas kur kaip įkelti
transformers akisviete/azuolas-whisper-lt WhisperForConditionalGeneration.from_pretrained(...)
faster-whisper akisviete/azuolas-whisper-lt-ct2 WhisperModel(...)
openai-whisper original/best_model.pt pagrindinėje saugykloje whisper.load_model(kelias)

Abiejuose paruoštuose pavidaluose įrašytos 10 alignment_heads porų — oficialus OpenAI rinkinys large-v3 modeliui (iš 640 dekoderio kryžminio dėmesio galvų). Be jų faster-whisper pats pasirenka 320 porų iš paskutinės dekoderio pusės; išmatuota, kad tada nulinės trukmės žodžių padvigubėja (42 → 70).

Svoriai fp16. Jei dirbate procesoriumi, įkeldami nurodykite dtype=torch.float32 — fp16 procesoriuje lėtas. Tikslumas nuo to nekinta: skaičiai tie patys, tik kitaip užrašyti.

Trumpi įrašai

import torch, soundfile as sf
from transformers import WhisperForConditionalGeneration, WhisperProcessor

MODEL = "akisviete/azuolas-whisper-lt"

proc = WhisperProcessor.from_pretrained(MODEL, language="lithuanian", task="transcribe")
mdl = WhisperForConditionalGeneration.from_pretrained(MODEL, dtype=torch.float16).to("cuda").eval()

wav, sr = sf.read("irasas.wav", dtype="float32")        # 16 kHz, vienas kanalas
f = proc(wav, sampling_rate=16000, return_tensors="pt")
ids = mdl.generate(f.input_features.to("cuda", torch.float16),
                   language="lithuanian", task="transcribe",
                   condition_on_prev_tokens=False,
                   temperature=(0.0, 0.2, 0.4, 0.6, 0.8, 1.0),
                   logprob_threshold=-1.0,
                   compression_ratio_threshold=1.35,
                   no_speech_threshold=0.6)
print(proc.decode(ids[0], skip_special_tokens=True))

Su faster-whisper — maždaug 4× greičiau ir mažiau atminties. vad_filter=True kartu išsprendžia tylos problemą, aprašytą žemiau:

from faster_whisper import WhisperModel

m = WhisperModel("akisviete/azuolas-whisper-lt-ct2", device="cuda",
                 compute_type="float16")
segs, _ = m.transcribe("irasas.wav", language="lt", beam_size=5,
                       vad_filter=True, condition_on_previous_text=False)
for s in segs:
    print(f"[{s.start:6.2f} -> {s.end:6.2f}] {s.text}")

Ilgi įrašai — karpykite patys

Supjaustykite garsą į dalis iki 22 sekundžių, kirpdami tylose tarp kalbos, ir atpažinkite kiekvieną dalį atskirai.

Kirpimo vietas imkite iš Silero VAD — raskite kalbos sritis ir kirpkite tarpų tarp jų viduriuose. Tai svarbu ne mažiau už patį ilgį: išmatuota, kad toks kirpimas duoda apie 4 punktais geresnį rezultatą nei paieška pagal garso lygį, kuri gali pataikyti į tylesnę vietą žodžio viduryje.

22 sekundės nėra spėjimas. Su 57 minučių įrašu išbandytos visos ribos ir palygintos su atskaitos tekstu:

dalies ilgis skirtumas nuo atskaitos
16 s 13,86 %
22 s 13,38 %
28 s 14,07 %
40 s 15,10 %
60 s 24,62 %

Trumpesnės dalys verčia kirpti kalbos viduryje (prie 8 s taip nutinka 71 % kirpimų, prie 28 s — 56 %), ir kiekvienas nevykęs kirpimas prigalvoja žodžių abiejuose galuose. Ilgesnės dalys pradeda mesti tekstą: prie 60 s praleidimų penkis kartus daugiau. Tai patikrinta su dviem skirtingai apmokytais modeliais, ir geriausia riba nepasikeitė.

Du įspėjimai, abu patirti savo kailiu:

  • Nenaudokite chunk_length_stransformers. Jis karpo fiksuotu žingsniu ir lipdo tekstą pagal persidengimus, o ko nesulipdo — išmeta. Paprika autorius išmatavo, kad taip tyliai prarandama 30 ir 52 žodžiai sandūrose. Tekstas atrodo tvarkingas, niekas nerodo, kad kažko nėra.
  • Per ilgos dalys sugenda tyliai. Prie 60 s tekste pritrūksta apie 13 % žodžių, o visi „sveikatos" rodikliai atrodo geri. Tik žodžių skaičius, palygintas su atskaita, tai parodo.

Ką reikia žinoti

Modelis prigalvoja tekstą per tylą, ir apsauga neveikia. Su 60 sekundžių įrašais: visiška tyla — 78 simboliai, tylus šnypštimas — 947 simboliai sklandaus lietuviško teksto, kambario fonas — 247. Pati Whisper apsauga nesuveikia: išmatuota tikimybė „nėra kalbos" per šnypštimą 0,0009, o originaliam large-v3 — 0,8154.

Du būdai, abu veikia:

  • Išfiltruokite tylą prieš atpažinimą — paprastas garso lygio patikrinimas, kaip daro paprika programa. Užima mikrosekundes ir problemą pašalina.
  • Naudokite vad_filter=True su faster-whisper. Išmatuota: 0 simbolių visais trimis atvejais.

Kodėl taip atsitiko: dėl mokymo duomenų, ne dėl sandaros. Garsynas buvo paruoštas suklijuojant sakinių įrašus į 30 sekundžių langus be tarpų, tad modelis niekada nematė lango be kalbos ir neišmoko nutilti.

Kiti apribojimai:

  • Rašo mažosiomis raidėmis, be skyrybos.
  • 16 kHz, vienas kanalas. Vyrauja skaitoma ir laisva kalba. Tarmių dalies nėra — paprika v3 ją turi.
  • Maždaug 3× lėtesnis už paprika. Išmatuota: 404 s prieš 128 s su 985 FLEURS įrašais.
  • Ankstesnėse šios linijos versijose buvo sugedęs ilgų įrašų laiko žymėjimas. Priežastis — langų klijavimas, kuris išjungdavo laiko žymų mokymą. Pataisyta nustatant no_timestamp_rate: 0.5; klaidų skaičius nukrito nuo 23 iki 0. Šioje versijoje laiko žymos patikimos, bet tekstui vis tiek geriau karpyti patiems.
  • Mokymo metu matytas 2,99 % WER yra iš tos pačios srities kaip ir mokymo duomenys. Tai ne tikras vertinimas — remkitės FLEURS ir CV skaičiais.

Kaip apmokyta

Metodas ne savas. Jis paimtas iš i4Ds/FHNW darbo Fine-tuning Whisper on Low-Resource Languages for Real-World Applications (arXiv:2412.15726) — ten aprašytas ir duomenų klijavimas, ir mokymo tvarka. Skirtumai nuo straipsnio surašyti šaltiniuose.

pagrindas openai/whisper-large-v3, apmokyti visi svoriai
duomenys visas LIEPA-3 — 5 230 val. skaitoma + 4 359 val. laisva + 217 val. fonetinė
paruošimas i4Ds Whisper-prep, klijavimas į 30 s langus, overlap_chance 0,4
optimizatorius AdamW + Muon, muon_ndim_threshold 2
mokymo greitis 2e-5, kosinusinis, 64 įšilimo žingsniai
Muon momentas 0,95, svorių slopinimas 0,01
AdamW (pagalbinis) betos [0,9 · 0,98], eps 1e-6, svorių slopinimas 0,01
paketas 32 × 8 = 256
epochos 2
reguliarizacija žymų lyginimas 0,1, atsitiktinis gylis 0,1, max_grad_norm 1,0
garso iškraipymai SpecAugment ir deep SpecAugment
skaičių tikslumas fp16, gradientų perskaičiavimas koduotuve ir dekoduotuve
laiko žymos no_timestamp_rate 0,5, prompt_use_rate 0,5
failas 3,09 GB fp16

Muon taikomas tik dvimačiams svoriams transformerio blokuose. Įterptiniai vektoriai, konvoliucinis įėjimas, normalizavimo sluoksniai ir visi poslinkiai tvarkomi pagalbiniu AdamW.

Šaltiniai

Lyginti modeliai

Vertinimo programa (naudota visoms lentelėms)

Pagrindinis mokymo šaltinis

  • Vincenzo Timmel, Claudio Paonessa, Reza Kakooee, Manfred Vogel, Daniel Perruchoud. Fine-tuning Whisper on Low-Resource Languages for Real-World Applications. arXiv:2412.15726, 2024 m. gruodžio 20 d., CC BY 4.0 — https://arxiv.org/html/2412.15726v1

    FHNW (Šiaurės vakarų Šveicarijos taikomųjų mokslų universitetas) ir Noxenum. Būtent šis darbas aprašo metodą, kuriuo Ąžuolas paruoštas ir apmokytas, o Whisper-prep bei Whisper-finetune yra jo kodas. Iš jo perimta: sakinių lygio įrašų klijavimas į 30 s langus su VAD pataisytomis laiko žymomis, kalbėtojo išlaikymas, persidengimai, no_timestamp_rate ir prompt_use_rate po 0,5, paketas 256, gradientų perskaičiavimas koduotuve ir dekoduotuve, atsitiktinis gylis ir SpecAugment.

    Kur nukrypta: jie pradėjo nuo large-v2 (šveicarų vokiečių kalbai jis pasirodė geresnis), Ąžuolas — nuo large-v3; jų mokymo greitis 2e-4 ir tiesinis mažėjimas, Ąžuolo 2e-5 ir kosinusinis; jie naudojo 8 bitų AdamW, Ąžuolas — AdamW + Muon.

    Vertas dėmesio ir straipsnio 4.4 skyrius: autoriai patys pastebi, kad po tokio permokymo tikrų ilgų įrašų skaidymas ir atpažinimas pablogėja. Tas pats matyti ir čia — todėl kortelėje ir rašoma karpyti patiems.

Mokymo kodas

Naudotos šios pataisos, visos pasiūlytos ir pirminiams projektams. no_timestamp_rate pataisa yra ta, dėl kurios šioje versijoje laiko žymos naudotinos:

pataisa projektas ką pataiso
whisper-prep#6 whisper-prep palieka visą 30 s langą ir įrašo persidengiančio segmento pradžios laiką
whisper-prep#7 whisper-prep VTT MM:SS.mmm skaitymas, prarasta paskutinė eilutė, pasenęs buferis (perkelta iš jumon#33)
whisper-finetune#11 whisper-finetune įspėja, kad no_timestamp_training tyliai išjungia no_timestamp_rate
whisper-finetune#12 whisper-finetune priima vieną likusią pradžios žymą _get_partial_segment_start
whisper-finetune#13 whisper-finetune praleidžia nieko nekeičiantį kalbos map (~65 min. garso perrašymo per kiekvieną mokymą)

Duomenys

Metodai

  • Muon — https://kellerjordan.github.io/posts/muon/ ir Muon is Scalable for LLM Training, arXiv:2502.16982
  • Silero VAD — https://github.com/snakers4/silero-vad
  • Distil-Whisper, arXiv:2311.00430 — iš kur 22 sekundės. Jų 23 lentelė rodo, kad geriausias gabalo ilgis seka mokymo lango ilgį: Whisper optimalus ties 30 s, Distil-Whisper ties 15 s, nes pastarojo mokymo imties vidurkis 7,1 s. Ten pat ir haliucinacijų matavimas per pasikartojančias 5-gramas. Patys autoriai naudoja persidengiantį chunk_length_s karpymą; išbandyta su šiuo modeliu — Silero VAD karpymas už jį geresnis.
  • Semantic Segmentation with Bidirectional Language Models Improves Long-form ASR, arXiv:2305.18419 — išbandyta ir atmesta. Siūloma kirpti ties sakinių ribomis, o ne ties pauzėmis. Patikrinta su šiuo modeliu ir 57 minučių įrašu: pralaimi Silero VAD kirpimui. Pasirodo, kad svarbu pataikyti į tikrą tylą, o ne į sakinio ribą — Silero kerpa per sakinio vidurį dažniau, ir vis tiek yra geresnis.

Licencija

Svoriai — CC BY 4.0, perimant LIEPA-3 garsyno nuorodų grandinę (VU / raštija.lt). Pagrindinis modelis openai/whisper-large-v3 — Apache-2.0.

Kontaktai

Dėl klausimų ir pasiūlymų rašykite akisviete@gmail.com.

Downloads last month
36
Safetensors
Model size
2B params
Tensor type
F16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for akisviete/azuolas-whisper-lt

Finetuned
(1053)
this model
Finetunes
1 model

Papers for akisviete/azuolas-whisper-lt