録音は二つの異なる方法で悪くなり得ますが、その対策は重ならないものです。
一つ目の方法。背景ノイズが音声の上に乗っています — 交通音、扇風機、部屋の唸り。重要な信号はそこにありますが、何か他のものが混ざり込んでいます。それを取り除くのがノイズ除去です。
二つ目の方法。録音がそもそも完全な信号を捉えていませんでした。電話音声は毎秒 8,000 サンプル(8 kHz)でサンプリングされ、完全な品質の録音は通常 48 kHz です。サンプルレートはデジタル信号が表現できる最高周波数を決めるため、8 kHz の通話には 4 kHz を超える内容がまったくありません — 静かなのでも、フィルタされているのでもなく、そもそも一度も記録されなかったのです。その音声を再び完全なものに聞こえるようにするということは、一度も捉えられたことのない、それらしい高周波を作り出すことを意味します。それが帯域拡張です。
audiosronnx はこれらを、異なる進入点を持つ二つの異なる問題として扱います。間違った方を使うと間違ったことをしてしまうからです。帯域拡張器をノイズの多い信号に対して実行すると、そのノイズの高周波版を忠実に再構築してしまいます。ノイズ除去を先に行う必要があります。
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() と load_sr() は互いのエンジンを拒否します — load_denoise に帯域拡張器を求めると、静かに間違った仕事をする代わりにエラーになります。
なぜこれが認識より前に来るのか
音声認識と話者識別は通常、比較的クリーンな音声で学習されます。認識器に 8 kHz の電話音声や、下で扇風機が回っている音声を与えると、単語誤り率が上がります — モデルが悪いからではなく、入力が学習時に見たものとはもはや似ていないからです。識別や話者分離に使われる話者埋め込みも同様です。ノイズと失われた帯域幅は、それらの埋め込みが依存する正確な音響的細部を歪めます。
これによりクリーンアップは、認識の代わりではなく認識の前に位置するパイプラインの段階になります。ノイズの多い 8 kHz の電話通話のための実際のパイプラインはこうです。ノイズを除去し、48 kHz に拡張し、その結果に認識や話者 ID を実行する。入力を先に修正せずにより良い認識器を差し込むことは、間違った場所に労力を使うことです — モデルがどれだけ優れていても、同じ損傷した信号の上では性能が落ちます。
エンジンレジストリ
audiosronnx は十のノイズ除去器と七つの帯域拡張器を提供しており、すべて load_denoise() / load_sr() を通じて名前でロードでき、すべて実行時に torch なしの純粋な ONNX です。
ノイズ除去器:
| エンジン | レート | サイズ | ライセンス |
|---|---|---|---|
| dpdfnet(既定) | 8/16/48 kHz | 8.7–14.9 MB | Apache-2.0 |
| mossformer2 | 48 kHz | 229 MB | Apache-2.0 |
| frcrn | 16 kHz | 57.5 MB | Apache-2.0 |
| mpsenet | 16 kHz | 9.7 MB | MIT |
| gtcrn | 16 kHz | 0.54 MB | MIT |
| cmgan | 16 kHz | 7.8 MB | MIT |
| metadenoiser | 16 kHz | 19–34 MB | CC-BY-NC-4.0 |
| mossformergan | 16 kHz | 17.7 MB | Apache-2.0 |
| voicefixer | 44.1 kHz | 415 MB | MIT |
| deepfilternet | 48 kHz | ~2 MB | MIT |
帯域拡張器:
| エンジン | 入力 | サイズ | ライセンス |
|---|---|---|---|
| lavasr(既定) | 8–48 kHz | ~52 MB | Apache-2.0 |
| novasr | 16 kHz | ~0.2 MB | Apache-2.0 |
| flowhigh | 任意 | ~200 MB | MIT |
| hifiganbwe | 任意 | ~4 MB | MIT |
| apbwe | 任意(12 kHz 帯域) | ~120 MB | MIT |
| sidon | 16 kHz | ~410 MB | MIT |
| callenhancer | 8–16 kHz | ~3 GB / int8 ~1.3 GB | CC-BY-NC-4.0 |
このライブラリで最小のモデルである gtcrn は 0.54 MB です。最大の voicefixer は 415 MB — ほぼ 800 倍大きく、異なる仕事をします。これはノイズ、残響、クリッピング、失われた帯域幅を一つずつではなくまとめて扱う復元モデルです。
ほとんどの重みは MIT か Apache-2.0 です。二つはそうではありません。metadenoiser と callenhancer は非商用の CC-BY-NC-4.0 で提供されます。そのライセンスは重みを対象としており、それで処理された音声を対象とするものではありません。このライブラリはあらゆる利用時点でそれを明示しています — audiosronnx list はエンジンごとにそれを報告します。呼び出し側がその時間領域アーキテクチャのために metadenoiser を選ぶことを妨げるものは何もありませんが、その選択は自覚的に行われなければなりません。
このレジストリが存在するのは、あらゆる録音で勝つ単一のモデルが存在しないからです。dpdfnet が既定なのは、追加の依存関係を必要とせず、一つのモデルで 8、16、48 kHz をカバーするからです。mossformer2 はフルバンド入力における測定上最良の選択です。mossformergan は提供されているノイズ除去器の中で最高の公開 PESQ スコア(3.47)を記録しています。gtcrn は制約がフットプリントであるときの選択で、0.54 MB です。広帯域ガウスノイズを含む一つのテストクリップでは、ノイズ除去器は入力 SNR 19 dB で 3.5〜5.9 dB の SNR を回復し、より厳しい入力 5 dB では 7.5〜13.7 dB まで上がりました。これは合成された、過酷なノイズのケースです。エンジンの順位を一貫して付けますが、babble ノイズやコーデックのアーティファクトについてはほとんど何も語りません。それこそが、このレジストリが勝者一つだけを出荷するのではなく十のモデルを保持している理由です。
cmgan は、意図的に維持されている、劣っているのに残されている最も明確な例です。PESQ と SNR の両方で十四分の一のサイズの gtcrn に負けているにもかかわらず、それでも残されています — cmgan に対して構築された公開結果が再現可能な状態を保ち、比較対象となる別個のアーキテクチャが利用可能なままであるようにするためです。
帯域拡張の側では、sidon と callenhancer は lavasr や novasr とは異なる仕事をします。既存の信号の上にそれらしい高音域を追加する代わりに、神経ボコーダを通じて音声をゼロから再合成します。これは帯域拡張器では手を出せないコーデックの損傷を修復できますが、はるかに高い計算コストがかかります。callenhancer は電話音声に特化して学習されており、それがその重みが非商用ライセンスを持つ理由です。
採用されなかったもの
audiosronnx は、単一の静的な ONNX グラフにエクスポートされ、onnxruntime を通じて CPU で動作し、明確なライセンスを持ち、元の実装に対して端から端まで検証されている場合にのみエンジンを提供します — 生のモデルだけでなくその周囲の正規化を含めてです。ネットワークとは一致するがその周囲の正規化とは一致しないグラフは、良さそうに聞こえて静かに間違っている音声を生み出すからです。
このプロジェクトの docs/not-shipped.md は、評価して却下したすべての候補を具体的な理由とともに文書化しています。これは、このリポジトリの中で最も有用なドキュメントの一つです。なぜなら「純粋な ONNX、CPU 専用」が今日何をできるかの実際の境界を、単に主張するのではなく示しているからです。
反復的なサンプラーにはエクスポートすべき静的グラフがありません。 拡散モデルとフローマッチングモデルは、発話ごとにネットワークを何度も実行し、そのループの長さはエクスポート時に固定されていません。AudioSR(別個の VAE、LDM、ボコーダを持つおよそ 6 GB の潜在拡散パイプライン)と SGMSE の両方がここに該当します — SGMSE 自身の 2025 年のストリーミング後継版でさえ、コンシューマー向け GPU でようやくリアルタイムに達する程度で、CPU は言うまでもありません。
位置可変畳み込みは実格に見えますが、たいていはそうではありません。 resemble-enhance は長らく、このドキュメントの中でボコーダの位置可変畳み込みである LVCNet を理由に却下されていました。unfold と einsum を通じて位置ごとに予測されるカーネルは静的グラフに折り畳めない、という理論からでした。実際にテストしたところ、それは間違いであることが分かりました — 両方の演算には ONNX の対応物があります。実際の失敗は、別個の、よく知られたトレーシングエラー(「未知の形状のカーネルに対する畳み込みの ONNX エクスポート」)であり、これはコードベースの他の場所で BigVGAN のリサンプラーについてすでに解決済みです。resemble-enhance を依然として除外しているのは規模です。CFM の ODE サンプラーとオートエンコーダを含む四つのネットワークが 44.1 kHz で — これは不可能性ではなく範囲の判断です。
一部のモデルにはエクスポートすべき学習済みのものが何もありません。 RNNoise は学習可能なフレームワークのグラフではなく手書きの C として提供されています — それを移植するということは、同等のネットワークをゼロから再学習させることを意味します。Fast-ULCNet はアーキテクチャのコードのみを公開しており、チェックポイントはまったくありません。
制限的なライセンスはラベル付けの決定であり、自動的な失格ではありません — これがまさに callenhancer と metadenoiser が提供されている理由です。失格させるのは、ライセンスがまったくない状態で公開された重みです。mdctGAN は、信頼性のあるエクスポートができない torch.fft ベースのフロントエンドに加えて、まさにその理由で却下されました。
モデル内部で呼び出される torch.stft は実際の構造的な障害です。 NU-Wave2 のサンプラーループは問題ではありません — 他のすべてのエンジンの STFT と同様に、グラフの外の numpy で実行できます。障害となるのは、その forward メソッドが内部で torch.stft と torch.istft を呼び出していることであり、これはこのライブラリが提供するすべてのグラフから意図的に排除しているもので、一般的にも最も信頼性の低いエクスポートをする演算子です。これを修正するには、変換の境界でモデルを分割する必要があり、演算子の入れ替えではなく実際の再構造化が必要です。
モデルのアーキテクチャを再現することは、その出力を再現することと同じではありません。 LiSenNet は 5 万 6 千パラメータ、300 KB 未満で — このライブラリで最小のエンジンになるはずです。その公開されている ONNX 移植版は実行され、それらしく見える減衰した音声を生成しますが、端から端まで測定すると信号を破壊します。入力 11 dB で SNR −10.8 dB です。その移植版自身の参照実装を正確に再現しても同じ負の結果が得られ、これは参照実装自体がその文書が説明するフロントエンドと一致していないことを意味します — まだ検証すべき正しい目標がないのです。
これらすべてを貫くパターンは、興味深い失敗が「モデルが大きすぎる」や「拡散が遅い」といったものではめったにないということです。それらは具体的です。正確な代替物を持つ未対応の演算子(torch.complex に対応する ONNX 演算はありませんが、atan2(im, re) が同じ位相角を計算します)、入力の実行時の形状から作られトレーサーが特定できないテンソル、あるいはグラフ境界の間違った側に置かれた変換などです。
出力が実際に改善したことを確認する
実行できる ONNX ファイルは、録音が改善したことの証明にはなりません。二つの異なる失敗モードが外から見ると同じに見えます。ノイズと一緒に音声も消してしまうノイズ除去器と、間違った倍音内容を持つ高音域を追加する帯域拡張器は、どちらもエラーなく再生され、軽く聴いた限りではむしろクリーンに聞こえることさえあります。
姉妹ライブラリである speechonnxmetrics は、その判断を印象ではなく測定可能なものにするために存在します。音声をMOS(平均オピニオンスコア、知覚品質の 1〜5 評価)で二つの方法で採点します。比較すべきクリーンな元がない録音を採点する DNSMOS や UTMOS のような参照なしの神経予測器と、クリーンな参照を必要とし出力がそれにどれだけ近いかを測る STOI や SI-SDR のような侵襲的な指標です。
import speechonnxmetrics as s
s.score("clean.wav", ["utmos"])
# -> {'utmos': 4.41}
s.score("denoised.wav", ["stoi", "si_sdr"], ref="clean.wav")
# -> {'stoi': 0.66, 'si_sdr': -26.9}
ノイズ除去器や拡張器の前後で実行すると、実際の比較の形が浮かび上がります。生の音声と処理済みの音声に DNSMOS や UTMOS をかけて知覚品質が少しでも動いたかを見て、クリーンな参照が存在する場合(合成ノイズテストでは存在しますが、実際の電話通話ではめったにありません)には SI-SDR や STOI で処理済みの信号が単に違って聞こえるだけでなく実際にそれに収束したかを見ます。これは上記のノイズ除去表にある SNR の数値の背後にあるのと同じ規律です。形容詞ではなく特定のノイズ条件に紐づいた数値です。speechonnxmetrics 自身を含む、これが属するより広い純粋な ONNX ライブラリの一族は、純粋な ONNX 音声ライブラリ群 で扱っています。
音声が認識器、話者 ID システム、あるいは人間の聴取者に届く前にクリーンアップすることは、それ自体が一つのエンジニアリングの仕事であり、独自のトレードオフのレジストリと、試したが実際の信号との接触に耐えられなかったアプローチのリストを持っています。
特定のパイプラインへの適用についてのご質問は お問い合わせください。