MARKETIA

Vosk 0.3.45 testé pour de vrai : protocole, script et mesures (2026-10-18)

Test exécuté le 18 octobre 2026 (page rédigée le 18 octobre 2026).

Test d'usage réel mais limité : une machine, un jeu de test synthétique, aucune note ni classement. Les résultats ne se généralisent pas à d'autres données. Notre méthode.

Demander l'installation de Vosk sur devisRéponse sous 5 jours ouvrés, sans engagement. Aucun paiement à cette étape.

En résumé

Le 2026-10-18, nous avons installé Vosk 0.3.45 dans un environnement Python neuf, téléchargé le petit modèle français vosk-model-small-fr-0.22, vérifié les empreintes, puis transcrit un seul extrait audio en français de 25,95 s produit par une voix de synthèse. Ce test porte sur une machine, une version, un modèle et 63 mots : il décrit ce que nous avons observé, il ne mesure pas la qualité générale de Vosk et ne se généralise pas à vos enregistrements. Il complète l'avis MagicMate sur Vosk, qui reste une lecture des sources publiques, en particulier pour les licences des modèles.

Ce que nous avons observé :

  • Temps de traitement : 3 514, 3 571, 3 536 et 3 544 ms sur 4 exécutions (moyenne 3 541 ms), chargement du modèle inclus (environ 330 à 345 ms), soit un facteur temps réel d'environ 0,14. Processeur seul.
  • Transcription : 6 erreurs de mots sur 63 mots de référence (9,5 %) avec notre normalisation, sur un seul extrait synthétique, sans valeur statistique.
  • Les nombres sont restitués en toutes lettres (« vingt-trois », « deux mille vingt-six ») ; le nom propre inventé est déformé ; la sortie est en minuscules, sans ponctuation.
  • Les 4 exécutions ont donné exactement le même texte.

Protocole et commandes

Machine : Windows 11, Intel Core i5-10400F (6 cœurs, 12 threads), processeur seul, Python 3.13.13. Commandes en PowerShell. Dans les commandes, $b désigne un dossier de travail neuf (sous-dossiers dl, audio, src, venv, model). Aucun accès réseau pendant la transcription.

  1. Environnement isolé : python -m venv $b\venv.
  2. Paquet Vosk. La version 0.3.45 (publiée le 2022-12-14) est la plus récente indiquée par l'API JSON de PyPI le 2026-10-18. Téléchargement sans installation : $b\venv\Scripts\python.exe -m pip download vosk==0.3.45 --no-deps --only-binary=:all: --platform win_amd64 --python-version 3.13 -d $b\dl. Fichier vosk-0.3.45-py3-none-win_amd64.whl, SHA-256 calculé avec Get-FileHash <fichier> -Algorithm SHA256 : 6994ddc68556c7e5730c3b6f6bad13320e3519b13ce3ed2aa25a86724e7c10ac, identique à celui publié par PyPI pour ce fichier.
  3. Installation : $b\venv\Scripts\python.exe -m pip install --no-index --no-deps $b\dl\vosk-0.3.45-py3-none-win_amd64.whl, puis les dépendances cffi srt websockets tqdm requests (versions résolues le jour même : cffi 2.1.1, srt 3.5.3, websockets 17.2, tqdm 4.70.1, requests 2.34.2).
  4. Modèle : Invoke-WebRequest https://alphacephei.com/vosk/models/vosk-model-small-fr-0.22.zip -OutFile $b\dl\vosk-model-small-fr-0.22.zip. Taille 42 233 323 octets, identique à la taille de la liste officielle des modèles (model-list.json). Cette liste ne publie qu'une empreinte MD5, 8873b1234503f6edd55f54bfff31cf3e, que nous avons retrouvée avec Get-FileHash -Algorithm MD5. Le SHA-256 que nous avons calculé, sans valeur officielle à comparer, est cabf6180e177eb9b3a9a9d43a437bd5e549f3a7d09525e5d69a3fed787be12ad. Extraction : Expand-Archive <zip> -DestinationPath $b\model (68,5 Mo décompressés).
  5. Audio de référence : synthèse vocale Windows (System.Speech, voix « Microsoft Hortense Desktop », fr-FR), écrite avec SetOutputToWaveFile en 16 kHz, 16 bits, mono, fichier test-fr.wav de 830 286 octets, 25,95 s, SHA-256 31e92d62f7fa7eec8c9fc4a7955b485a103b43edb1bb75595d6e2eccf8becb06. Le texte est identique à celui de notre test de whisper.cpp et le fichier a la même taille en octets.
  6. Transcription : $b\venv\Scripts\python.exe -I $b\src\run_vosk.py $b\model\vosk-model-small-fr-0.22 $b\audio\test-fr.wav $b\src\reference.txt 4. Le script est conservé ci-dessous (SHA-256 a656a264cbc4bdd43bfe14d5feebbe0fc8501cd33f64ff614cbbc61884690fb6). Il charge le modèle à chaque exécution, lit le WAV par blocs de 4 000 images, active SetWords(True) (horodatage par mot) et mesure le temps avec time.perf_counter() autour du chargement et de la reconnaissance. Le pic de mémoire est lu en fin de processus (PeakWorkingSetSize) : il couvre donc les 4 exécutions du même processus.
  7. Taux d'erreur de mots : distance de Levenshtein sur les mots, en minuscules, avec les tirets et apostrophes traités comme séparateurs et la ponctuation retirée (fonctions norm et wer du script). Cette normalisation compte 63 mots de référence ; notre test de whisper.cpp en comptait 62 avec un script qui n'a pas été conservé : les deux pourcentages ne sont donc pas comparés ici.

Texte de référence exact (sans donnée personnelle, nom propre fictif), enregistré dans reference.txt et lu par la voix de synthèse :

Aujourd'hui, le ciel est nuageux sur la région de Lyon. La température maximale atteindra vingt-trois degrés cet après-midi. Madame Odette Brancourt a présenté le bulletin météo le douze mars deux mille vingt-six. Demain, il pleuvra sur le nord du pays, avec des vents de soixante kilomètres par heure. Le week-end sera plus ensoleillé, et les températures remonteront progressivement.

Script exact run_vosk.py :

# Usage: python -I run_vosk.py <model_dir> <wav> <reference.txt> <runs>
import sys, json, time, wave, re, unicodedata, ctypes
from ctypes import wintypes
from vosk import Model, KaldiRecognizer, SetLogLevel

SetLogLevel(-1)
model_dir, wav_path, ref_path, runs = sys.argv[1], sys.argv[2], sys.argv[3], int(sys.argv[4])

class PMC(ctypes.Structure):
    _fields_ = [("cb", wintypes.DWORD), ("PageFaultCount", wintypes.DWORD),
                ("PeakWorkingSetSize", ctypes.c_size_t), ("WorkingSetSize", ctypes.c_size_t),
                ("QuotaPeakPagedPoolUsage", ctypes.c_size_t), ("QuotaPagedPoolUsage", ctypes.c_size_t),
                ("QuotaPeakNonPagedPoolUsage", ctypes.c_size_t), ("QuotaNonPagedPoolUsage", ctypes.c_size_t),
                ("PagefileUsage", ctypes.c_size_t), ("PeakPagefileUsage", ctypes.c_size_t)]
def peak_mb():
    k = ctypes.WinDLL("kernel32", use_last_error=True); p = ctypes.WinDLL("psapi", use_last_error=True)
    k.GetCurrentProcess.restype = wintypes.HANDLE
    p.GetProcessMemoryInfo.argtypes = [wintypes.HANDLE, ctypes.POINTER(PMC), wintypes.DWORD]
    c = PMC(); c.cb = ctypes.sizeof(PMC)
    p.GetProcessMemoryInfo(k.GetCurrentProcess(), ctypes.byref(c), c.cb)
    return c.PeakWorkingSetSize / 1048576

def norm(s):
    s = s.lower().replace("’", "'")
    s = re.sub(r"[-']", " ", s)
    s = re.sub(r"[^\w\s]", " ", s)
    return s.split()

def wer(ref, hyp):
    d = list(range(len(hyp) + 1))
    for i in range(1, len(ref) + 1):
        prev, d[0] = d[0], i
        for j in range(1, len(hyp) + 1):
            cur = d[j]
            d[j] = min(d[j] + 1, d[j - 1] + 1, prev + (ref[i - 1] != hyp[j - 1]))
            prev = cur
    return d[len(hyp)]

ref = open(ref_path, encoding="utf-8").read()
refw = norm(ref)
res = []
for r in range(runs):
    t0 = time.perf_counter()
    m = Model(model_dir); t_load = time.perf_counter()
    wf = wave.open(wav_path, "rb")
    rec = KaldiRecognizer(m, wf.getframerate()); rec.SetWords(True)
    parts = []
    while True:
        data = wf.readframes(4000)
        if not data: break
        if rec.AcceptWaveform(data): parts.append(json.loads(rec.Result()))
    parts.append(json.loads(rec.FinalResult()))
    t1 = time.perf_counter()
    text = " ".join(p.get("text", "") for p in parts).strip()
    dur = wf.getnframes() / wf.getframerate()
    res.append(dict(run=r + 1, total_ms=round((t1 - t0) * 1000), load_ms=round((t_load - t0) * 1000), dur_s=round(dur, 2), text=text))
    if r == 0:
        json.dump(parts, open(sys.argv[3] + ".vosk-words.json", "w", encoding="utf-8"), ensure_ascii=False, indent=1)
hypw = norm(res[0]["text"])
print(json.dumps(res, ensure_ascii=False, indent=1))
print("ref_words", len(refw), "hyp_words", len(hypw), "errors_raw", wer(refw, hypw), "peak_mb", round(peak_mb(), 1))
print("HYP:", res[0]["text"])

Résultats mesurés

MesureValeur
Durée de l'audio25,95 s
Temps total, 4 exécutions3 514 / 3 571 / 3 536 / 3 544 ms (moyenne 3 541 ms)
Dont chargement du modèle344 / 335 / 331 / 332 ms
Facteur temps réelenviron 0,14 (environ 7 fois plus rapide que le temps réel)
Pic de mémoire du processus318,8 Mo (couvre les 4 chargements successifs)
Taille du modèle42,2 Mo compressé, 68,5 Mo décompressé
Erreurs de mots6 sur 63 mots de référence (9,5 %)

Transcription obtenue, identique sur les 4 exécutions (accents restitués) : « aujourd'hui le ciel nuageux sur la région de lyon la température maximale atteindra vingt-trois degrés cet après-midi mme odette brand cours a présenté le bulletin météo le douze mars deux mille vingt-six demain il pleuvra sur le nord du pays avec des vents de soixante kilomètres par heure le week-end sera plus ensoleillés et les températures remonterons progressivement ».

Les 6 erreurs, relevées en comparant à la main avec le texte de référence : « est » omis dans « le ciel est nuageux » (1) ; « Madame » rendu « mme » (1) ; « Brancourt » rendu « brand cours », une substitution et une insertion (2) ; « ensoleillé » rendu « ensoleillés » (1) ; « remonteront » rendu « remonterons » (1). Nous ne qualifions pas ces erreurs au-delà de ce relevé.

Horodatage par mot : le premier segment renvoyé contient 9 mots, avec pour chacun un début, une fin et une confiance (par exemple « aujourd'hui », de 0,12 s à 0,84 s). Nous n'avons pas vérifié la précision de ces horodatages.

Le fichier README du modèle indique une mesure de l'éditeur, « %WER 23.95 », sur un jeu de test Common Voice. C'est une affirmation de l'éditeur sur un autre jeu de données : elle n'est ni reproduite ni comparable à notre mesure.

Limites du test

  • Une seule machine (Windows 11, processeur i5-10400F), une seule version (Vosk 0.3.45, modèle vosk-model-small-fr-0.22).
  • Un seul extrait de 25,95 s et 63 mots, généré par une voix de synthèse claire, sans bruit ni chevauchement de voix : les erreurs ne représentent pas celles d'enregistrements réels.
  • Le pourcentage d'erreur dépend de la normalisation choisie (apostrophes et tirets séparateurs, minuscules) : avec un autre choix, il changerait.
  • Le pic de mémoire couvre les 4 chargements dans un même processus ; il n'a pas été mesuré pour une exécution isolée.
  • Les temps incluent le chargement du modèle ; ils ne sont pas représentatifs d'un autre matériel.
  • Nous ne comparons pas ces chiffres à ceux de whisper.cpp : modèles, scripts de calcul et normalisations diffèrent.

Ce que nous n'avons pas testé

  • Des enregistrements réels (téléphone, bruit, plusieurs locuteurs, accents), des fichiers longs, la reconnaissance en flux continu depuis un micro.
  • Les autres modèles français (dont ceux sous licence non commerciale ou AGPL signalés dans l'avis), les grands modèles, les autres langues, la reconnaissance des locuteurs.
  • Le mode vocabulaire restreint (grammaire), les liaisons Java, Node.JS, C#, C++, Rust, Go, l'exécution sur Raspberry Pi ou téléphone, le serveur WebSocket.
  • D'autres systèmes d'exploitation et versions, y compris toute version postérieure à la 0.3.45.
  • La licence propre au modèle utilisé, au-delà de la mention de la page publique (voir l'avis).

Sources

Aller plus loin

Recevoir la newsletter Marketia