CoolFace
Modelpublic

opencouncil/whisper-large-v3-el-council-lora

sourceHugging Faceapache-2.0updated 1mo agoView on Hugging Face
0likes14downloads
Model Card

Whisper Large-v3 Greek Municipal-Council LoRA, v2

A LoRA adapter over openai/whisper-large-v3 for Greek municipal-council speech, from the OpenCouncil ASR project (GSoC 2026).

This is v2, published 2026-08-23. The previous adapter stays available as the v1 tag, and section Which version to use explains the difference.

Adapter file adapter_model.safetensors, sha256 5e4b55d2803541aac8608e608029c8a6573d9a19d1909f23f57d2460f49e3312.

What it is

  • —Base model openai/whisper-large-v3. The adapter does nothing on its own.
  • —LoRA r=32, alpha=64, on q_proj and v_proj only, PEFT 0.19.1.
  • —619 optimizer steps, effective batch 8, lr 1e-4, seed 47, one RTX A4000.
  • —Trained on 2,475 packed examples of Greek council audio. Two councils, Argos and Orestiada, were held out of training and used for validation.

Load it

python
from transformers import WhisperForConditionalGeneration, WhisperProcessor
from peft import PeftModel

base = WhisperForConditionalGeneration.from_pretrained("openai/whisper-large-v3")
model = PeftModel.from_pretrained(base, "opencouncil/whisper-large-v3-el-council-lora")
model = model.merge_and_unload()
processor = WhisperProcessor.from_pretrained("openai/whisper-large-v3",
                                             language="greek", task="transcribe")

For v1, pass revision="v1" to from_pretrained.

The decode configuration these numbers were measured with

Every number below comes from this configuration through faster-whisper on a CTranslate2 float16 conversion of the merged model. A different beam size or a different temperature ladder gives a different number, so quote these figures only alongside this configuration.

python
dict(language="el", beam_size=5, condition_on_previous_text=False,
     temperature=[0.0, 0.2, 0.4, 0.6, 0.8, 1.0],
     no_speech_threshold=0.6, log_prob_threshold=-1.0,
     compression_ratio_threshold=2.4, vad_filter=False)

What changed between v1 and v2

The training data changed. The recipe did not.

v1 treated each corrected utterance as one training example. Those average 3.55 seconds, and Whisper always reads a 30-second window, so most of every example was padding the model never meets at inference.

For v2 I dropped every clip where two people speak at once, then packed continuous spans of a single speaker until each window carried about 22 seconds of speech.

v1   28,967 clips        [ utterance ]...............................  3.55 s speech
v2    2,475 packs        [ one speaker, one continuous span         ]  ~22 s speech
                         |<------- 30-second Whisper window ------->|

Two things moved at the same time, overlap filtering and window occupancy, so this repository cannot tell you which of them did the work.

Results

Measured on 39 frozen validation windows from Argos and Orestiada, two councils absent from all training data, and on 391 held-out windows from 117 meetings scored inside OpenCouncil's own benchmark. Every row below was decoded on one machine with the configuration above.

validation WERheld-out test WERdeletion rate
v2 (this revision)0.13900.17950.0313
v1 (revision="v1")0.16000.18670.0525
whisper-large-v3, not fine-tuned0.19880.0335

v2 beats v1 on validation across all three random seeds I trained. On the held-out test set the WER difference is -0.0040 with a 95% meeting-clustered interval of [-0.0078, +0.0002], which crosses zero.

The difference you can rely on is the deletion rate. v2 drops 0.0313 of the reference against v1's 0.0525, interval [-0.0251, -0.0174]. It leaves out about 40% less of what was said. For a workflow where a person reviews the transcript, a wrong word is easier to catch than a missing sentence.

Domain terms

On 250 occurrences of councillor surnames and place names in the same 39 windows:

DS-WER
Soniox0.3280
ElevenLabs Scribe v20.3720
v2, seed 47 (this revision)0.4360
v2, seed 290.4640
v10.4800
v2, seed 130.4840
whisper-large-v3, not fine-tuned0.5400

The three v2 rows differ only in the random seed and span 0.0480, which is wider than the 0.0187 separating the v2 average from v1. Treat the domain-term ordering between v1 and v2 as unresolved.

What this model does not do

It loses to ElevenLabs Scribe v2 and to Soniox on our own benchmark, on overall WER and on domain terms both. If you need the best available Greek council transcription and can pay for an API, use one of those. This adapter is useful when you want a self-hosted model with no per-minute cost, and it is a clear improvement on the base model it starts from.

Intended use

Greek municipal council meetings: long-form, multi-speaker, procedural vocabulary, variable room acoustics. It was fine-tuned on that and measured on that.

Out-of-scope use

  • —Any language other than Greek.
  • —Domains other than council or committee proceedings. Generalisation outside this domain is untested.
  • —Automated decisions about people. The output contains recognition errors on names at a rate you can read above.
  • —Speaker identification. This model does not do it.

Limitations

  • —Overall WER on held-out council audio is 0.1795, so roughly one word in six differs from the published transcript.
  • —Names are the weak point. Errors on them are mostly substitutions rather than omissions, so a wrong name reads as a plausible name.
  • —Numbers, dates and amounts are not separately validated.
  • —The measurements compare against OpenCouncil's published transcripts, which are themselves human-corrected and carry their own conventions.

Data

This repository contains the adapter weights and configuration. No dataset, no audio, no transcripts.

License

Apache 2.0, matching the base model.

Provenance

Trained and evaluated in the OpenCouncil GSoC 2026 project. Method, experiment records and every number above: github.com/eellak/gsoc2026-opencouncil-stt, report at FINAL_REPORT.md.

Which version to use

Use v2, the default. It leaves out far less of the meeting and matches or beats v1 everywhere else. Load revision="v1" if you need to reproduce a result published before 2026-08-23.