ONNX ist ein Dateiformat für ein trainiertes neuronales Netz: die Gewichte und der Berechnungsgraph, eingefroren, ohne Abhängigkeit von dem Framework, das es trainiert hat. Ein nach ONNX exportiertes Modell kann über ONNX Runtime laufen, eine kleine Inferenz-Engine, die nichts anderes tut, als diesen Graphen auszuführen. Sie weiß nicht, wie das Modell trainiert wurde, unterstützt kein Training und braucht kein installiertes PyTorch oder TensorFlow.
Mehrere unserer Bibliotheken halten sich an eine Regel: Zur Laufzeit sind die
einzigen Abhängigkeiten onnxruntime und numpy. Nicht “meistens” — der Import
des Pakets selbst zieht niemals ein Trainings-Framework nach. audiosronnx
(Bandbreitenerweiterung und Entrauschung), voiceclonnx (Voice Cloning),
speakeronnx (Sprecher-Embeddings), speechonnxmetrics (Evaluierung), stressonnx
(Wortbetonung), vadonnx (Sprachaktivitätserkennung) und phoonnx (Phonemisierung
und Text-zu-Sprache) folgen dieser Regel alle, jede in ihrem eigenen PyPI-Paket.
Zwei weitere, phoonnx.js und precise-onnx-js, setzen dieselbe Idee im Browser
um, mit onnxruntime-web statt.
Warum der Aufwand
Der naheliegende Weg, ein Sprachmodell auszuliefern, besteht darin, das Trainings-Framework auch für die Inferenz zu behalten. Das ist während der Entwicklung bequem. In der Produktion ist es eine Belastung.
- Installationsgröße. Eine PyTorch-+-CUDA-Installation läuft in
Gigabyte-Bereiche, bevor Sie auch nur ein einziges Modell geladen haben.
onnxruntimeundnumpyzusammen sind wenige Dutzend Megabyte. - Kein CUDA zu verwalten. Einen GPU-Treiber, eine CUDA-Toolkit-Version und einen Framework-Build passend zu halten, ist eine wiederkehrende Quelle für Ausfälle. Reines CPU-ONNX-Runtime umgeht das vollständig und läuft trotzdem auf einer GPU, sofern eine verfügbar ist, mit demselben Graphen.
- Läuft auf bescheidener Hardware. Ein Raspberry Pi oder ein zehn Jahre alter
Laptop kann
onnxruntimebequem ausführen. Einen vollständigen PyTorch-Stack kann er meist nicht mit brauchbarer Geschwindigkeit ausführen, oder auf einer 32-Bit- oder speicherbeschränkten Platine überhaupt nicht installieren. - Ein Artefakt, jede Plattform. Dieselbe
.onnx-Datei läuft unverändert auf Linux, macOS, Windows — und, überonnxruntime-web, in einem Browser-Tab. Es gibt keinen separaten Exportschritt pro Ziel. - Keine Konflikte zwischen Trainings- und Serving-Versionen. Ein Trainings-Stack pinnt bestimmte Framework- und CUDA-Versionen fest. Ein Serving-Stack will die kleinstmögliche, stabilste Menge an Abhängigkeiten. Sie zu trennen bedeutet, eine aktualisieren zu können, ohne die andere zu brechen.
Was es kostet
Die Einschränkung ist real, und sie ist nicht umsonst.
Sie können nicht In-Process feinabstimmen. Ein ONNX-Graph hat keinen
Optimizer, keinen Backward-Pass. Jede dieser Bibliotheken behandelt Modelle als
feste Artefakte: Sie laden sie und führen sie aus. Training oder Fine-Tuning
geschieht separat, mit dem ursprünglichen Framework, und das Ergebnis wird
anschließend nach ONNX exportiert. stressonnx und speechonnxmetrics behalten
beide ein optionales export-Extra, das torch ausschließlich für diesen
Offline-Konvertierungsschritt zieht — niemals für die Inferenz.
Nicht jede Architektur exportiert sauber. Dynamischer Kontrollfluss,
benutzerdefinierte CUDA-Kernel oder Operationen ohne ONNX-Äquivalent können einen
geradlinigen Export blockieren. Das README von audiosronnx dokumentiert das
direkt: Es führt eine Liste nicht ausgelieferter Modelle,
die evaluiert und abgelehnt wurden, samt Gründen, statt so zu tun, als würde
jedes Forschungsmodell sich problemlos portieren lassen.
Vorverarbeitung muss von Hand neu implementiert werden. Ein Framework wie
PyTorch oder Kaldi liefert schnelle, getestete Implementierungen von STFT
(Umwandlung einer Wellenform in ein Spektrogramm), Mel-Filterbank-Merkmalen und
Resampling. Sobald das Modell selbst nicht mehr von diesem Framework abhängt,
kann seine Vorverarbeitung das auch nicht mehr — speakeronnx implementiert aus
genau diesem Grund eine 80-Band-Log-Mel-Filterbank in reinem NumPy neu, und
audiosronnx tut dasselbe für STFT und Resampling. Es ist mehr Code, den man
richtig hinbekommen muss, und er braucht eigene Paritätstests gegen das Original.
Eine Aufgabe, mehrere Engines, eine API
Trainierte Sprachmodelle variieren enorm nach Sprache, Aufnahmebedingung und Zieldomäne. Ein auf sauberer Lesesprache trainiertes Sprecherverifikationsmodell kann bei Telefonaudio versagen. Ein für englische Klangfarbenübertragung abgestimmtes Voice-Cloning-Modell kann bei Tonsprachen an Verständlichkeit verlieren. Es gibt kein einziges Modell, das überall gewinnt, sodass eine Festlegung im Voraus eine Vermutung ist.
Jede Bibliothek in dieser Familie wählt eine einzelne Aufgabe und umschließt mehrere unabhängig veröffentlichte Modelle hinter einer Schnittstelle, sodass der Wechsel der Engine eine einzeilige Änderung ist statt einer Neufassung.
audiosronnx trennt seine zwei Aufgaben — Entrauschung und
Bandbreitenerweiterung (die Umwandlung einer Schmalbandaufnahme, etwa
8-kHz-Telefonaudio, in ein volleres klingendes Signal mit höherer Abtastrate) —
hinter zwei Loadern, jeder von mehreren Engines gestützt:
from audiosronnx import load_denoise, load_sr
clean, rate = load_denoise("dpdfnet").denoise("noisy_call.wav") # remove noise
wide, _ = load_sr("lavasr").upscale(clean, rate) # extend to 48 kHz
load_denoise registriert derzeit zehn Entrauscher (dpdfnet, mossformer2,
frcrn, mpsenet, gtcrn, cmgan, metadenoiser, mossformergan,
voicefixer, deepfilternet), von einem 0,54-MB-Modell bis zu einem
415-MB-Modell, unter unterschiedlichen Lizenzen. load_sr registriert sieben
Bandbreitenerweiterer (lavasr, novasr, flowhigh, hifiganbwe, apbwe,
sidon, callenhancer). Dominierte Modelle — solche, die eine andere Engine
auf jeder gemessenen Achse schlägt — bleiben trotzdem in der Registry, sodass
ein veröffentlichtes Benchmark-Ergebnis auf Abruf reproduzierbar bleibt.
voiceclonnx verfolgt denselben Ansatz für Voice Cloning — die Umwandlung der
Stimme in einer bestehenden Aufnahme, damit sie wie ein anderer
Referenzsprecher klingt, ohne den Umweg über Text:
from voiceclonnx import VoiceCloner
cloner = VoiceCloner(engine="facodec")
out = cloner.clone_voice("source.wav", "reference.wav", "out.wav")
Zehn Engines sind registriert (facodec, openvoice, chatterbox, triaan,
cosyvoice, bicodec, knnvc, focalcodec, lscodec, rvc), die sechs
unterschiedliche Modellfamilien umfassen — kNN-Feature-Swap, faktorisierter
Codec, Flow-Matching, Klangfarbenübertragung, AR-Codec-LM und
sprecherentkoppelter Codec. Im Hintergrund liefert jede davon veröffentlichte
Verständlichkeits- und Sprecherähnlichkeitswerte, sodass die Wahl einer Engine
ein Vergleich ist, kein Münzwurf.
vadonnx wendet das Muster auf Sprachaktivitätserkennung an — die
Entscheidung, welche Teile eines Audiostreams überhaupt Sprache enthalten:
from vadonnx import load_vad
vad = load_vad("silero")
segments = vad.get_speech_segments(audio, sample_rate=16000)
# -> [SpeechSegment(start=0.32, end=2.27), SpeechSegment(start=3.27, end=4.45), ...]
Sechs Modellfamilien sind registriert (silero, marblenet, pyannote,
fsmn, speechbrain, ten), und eine deklarative IOSignature lässt eine
einzige generische Engine die meisten davon ansteuern oder auf jede
benutzerdefinierte .onnx-VAD-Datei zeigen.
speakeronnx extrahiert ein Sprecher-Embedding — einen Vektor fester
Länge, der zusammenfasst, wer spricht, unabhängig davon, was gesagt wurde —
und vergleicht zwei Embeddings per Kosinus-Ähnlichkeit, um zu prüfen, ob zwei
Clips vom selben Sprecher stammen:
from speakeronnx import SpeakerEmbedder, cosine
embedder = SpeakerEmbedder(model="wespeaker-resnet34")
alice1 = embedder.embed("alice_clip1.wav")
alice2 = embedder.embed("alice_clip2.wav")
print(cosine(alice1, alice2)) # e.g. 0.82 - same speaker
Es registriert neun Modelle über vier Architekturfamilien (WeSpeaker, CAM++, ERes2Net, ReDimNet), mit veröffentlichten Embedding-Dimensionen und Lizenzen.
stressonnx wählt die Wortbetonung für Text-zu-Sprache-Frontends — welche
Silbe eines Wortes die Betonung trägt, eine Information, die viele Sprachen
nicht ausbuchstabieren (Russisch за́мок, Schloss, gegenüber замо́к, Schloss
(Verschluss), teilen jeden Buchstaben). Es registriert eine neuronale Pipeline
für Russisch, eine zweite für Ukrainisch und Belarussisch und ein
Regel-und-Wörterbuch-Backend, das 26 Sprachen ganz ohne neuronale Inferenz
abdeckt:
from stressonnx import stress
stress("старинный замок стоит на горе", "ru")
# 'стари́нный за́мок сто́ит на горе́'
phoonnx phonemisiert Text (verwandelt geschriebene Wörter in die
Klangeinheiten, die ein TTS-Modell verarbeitet) und führt Text-zu-Sprache über
17 registrierte Synthese-Engines und Stimmen aus mehreren Ökosystemen aus
(natives phoonnx, Piper, Mimic3, Coqui, MMS, Transformers):
import wave
from phoonnx.voice import TTSVoice
voice = TTSVoice.load("model.onnx", "model.json")
with wave.open("hello.wav", "wb") as wav_file:
voice.synthesize_wav("Hello world!", wav_file)
phoonnx.js trägt dieselben Tokenizer-Pfade in den Browser mit
onnxruntime-web, und precise-onnx-js portiert Weckwort-Erkennung
(MFCC-Merkmalsextraktion plus ein ONNX-Klassifikator, kompatibel mit
Mycroft-Precise-Modellen) nach JavaScript, beide ohne Server:
import { loadVoice, synthesizeWav } from "phoonnx";
import { getVoice } from "phoonnx/voices";
const voice = await loadVoice(getVoice("phoonnx_eu-ES_dii_unicode")!);
const blob = await synthesizeWav(voice, "Kaixo mundua!");
Gewichte für audiosronnx (18 veröffentlichte Modelle) und voiceclonnx (10
veröffentlichte Modelle) liegen als separate Downloads auf der
TigreGótico-Hugging-Face-Organisation,
werden bei der ersten Nutzung geholt und lokal zwischengespeichert, sodass die
Wahl einer anderen Engine eine Konfigurationsänderung ist, keine
Neubereitstellung.
Den Kreis schließen: Engines bewerten statt raten
Viele Engines hinter einer API zu registrieren, zahlt sich nur aus, wenn Sie
erkennen können, welche für Ihre Eingabe tatsächlich besser ist. Dafür ist
speechonnxmetrics da: eine Metrik-Bibliothek, die auf derselben
numpy-+-onnxruntime-Beschränkung aufbaut, sodass die Bewertung eines
Modells keine zusätzlichen Installationskosten verursacht.
Sie gruppiert Metriken in drei Arten. Referenzlose MOS-Schätzer — UTMOS, DNSMOS, NISQA, SIGMOS — sagen einen Mean Opinion Score vorher, die 1-bis-5-Natürlichkeitsbewertung, die ein menschliches Hörer-Panel einem Clip geben würde, ohne eine saubere Referenz zum Vergleich zu brauchen. Intrusive Metriken — STOI (Short-Time Objective Intelligibility), SI-SDR (skaleninvariantes Signal-zu-Verzerrungs-Verhältnis), MCD (Mel-Cepstral-Distortion) — brauchen eine passende saubere Referenz und messen, wie nah die Ausgabe daran liegt. ASR-basierte Textmetriken — WER (Word Error Rate) und CER (Character Error Rate) — führen einen Spracherkenner über die Ausgabe und vergleichen die Transkription mit dem erwarteten Text, wobei sie Fälle erfassen, in denen ein Modell Audio produziert, das gut klingt, aber die falschen Wörter sagt.
import speechonnxmetrics as s
print(s.score("degraded.wav", ["utmos"]))
# -> {'utmos': 4.41...}
print(s.score("clone_output.wav", ["stoi", "mcd", "si_sdr"], ref="source.wav"))
# -> {'stoi': 0.662..., 'mcd': 10.459..., 'si_sdr': -26.937...}
Das verwandelt die Wahl der Engine von einem Hörtest in eine Tabelle.
voiceclonnx veröffentlicht genau diesen Vergleich für seine zehn
Cloning-Engines — WER gegen die Quelltranskription plus einen separaten
Sprecherähnlichkeitswert für jede, sodass „facodec liefert 0 % WER” oder
„lscodec tauscht WER gegen stärkere Klangfarbenübertragung” gemessene
Aussagen sind, keine Eindrücke. Multipliziert man das über Sprachen und
Aufnahmebedingungen, hört manueller Vergleich auf, realistisch zu sein; eine
objektive Metrik ist das, was eine Zehn-Engine-Registry benutzbar macht statt
überwältigend.
Wo das nützlich ist
Wenn Sie Offline-Sprachverarbeitung brauchen — eine Aufnahme säubern, eine
Stimme klonen, erkennen, wer spricht, oder eine synthetisieren — auf Hardware,
die nie eine GPU sehen wird, ist das die Form, nach der Sie suchen sollten:
eine kleine Laufzeitabhängigkeit, eine Wahl unter veröffentlichten Modellen
statt eines einzigen festen Standards, und eine Möglichkeit zu messen, welches
für Ihren Fall tatsächlich funktioniert. Jede der oben genannten Bibliotheken
ist ein pip install entfernt, auf Code-Ebene MIT- oder Apache-lizenziert
(einzelne Modellgewichte tragen ihre eigenen Upstream-Lizenzen, pro Engine
dokumentiert), und läuft gleich auf einem Laptop, einem Server oder einem
Raspberry Pi.
Nehmen Sie Kontakt auf über /contact oder sehen Sie, was wir sonst noch bauen, unter /services.