話者分離がうまくいかず、モデルを 7 つ替えても直らなかった
<!-- タイトル候補:
話者分離の精度が出ないとき、最初に作るべきは正解データ 10 か所だった
「モデルを替えれば直る」は 1 本目で当たって 2 本目で外れた
-->
はじめに
最近英語を話す機会が多いので、自分の英語の改善のためにも、英会話の内容をもとに AI に復習プランを作成してもらいたいと考えました。最初は ChatGPT に録音をそのまま読み込ませようとしたのですが、長すぎて読み込めませんでした。
そこで文字起こしアプリをいくつか調べていたのですが、調べていくうちに、月額料金が思ったより高いことに気づきました。私がやりたいのは、文字起こしをして、それを AI に読み込ませて復習メニューを作ってもらうことだけです。それにしてはちょっと高いなと思ったので、文字起こしアプリを自作することにしました。
この時代すぐに作れますし、自分に必要な最低限のものをローカルで動かすだけなので、作っていこうと思いました。
ここで盲点だったのが話者分離(録音の中で誰が話したかを区別する処理)です。私はただ文字起こしをすればいいと思っていたのですが、話者分離ができたほうが復習にはかなり役に立ちますし、AI 側も汲み取って復習プランを組みやすいことに気づきました。なので、この時点での要件は、ローカルで動くこと、話者分離ができること、文字起こしができることの 3 つになります。
調べていくと、そういったライブラリが OSS ですでに提供されていることまで分かりました。いくつかあったので、それぞれ色々と試しました。今は文字起こしに Whisper、話者分離に sherpa-onnx を使っています。
ところが話者分離をかけると、講師と私が 1 人の話者にまとめられてしまいました。直すまでに 3 晩かかり、その間に原因の予想を 3 回外しています。最後は、誰の声か確実に分かる区間を 10 か所選んで測ったところで原因が分かりました。この記事はその記録です。
話者が 1 人しか出てこない
23 分の録音を話者分離にかけると、話者 A が 1580 語、話者 B が 0 語になりました。録音全体が 1 人の発言として扱われています。
<!-- TODO(本人): 画像 1。話者 A だけになった結果の画面(ツール名・講師名が映らないように切り抜く)
-->
録音は iPhone でしています。講師の声は PC のスピーカー越しに入り、自分の声は直接入ります。
sherpa-onnx は、音声認識や音声合成、話者分離などをまとめて動かせるライブラリです。話者分離は次の順に進みます(構成は公式ドキュメントに載っています)。
録音から、誰かが話している区間を切り出す(pyannote の segmentation モデルを使います)
区間ごとに、声の特徴を数値の並びにする(埋め込みと呼ばれます)
特徴が近い区間をまとめて、まとまりごとに話者を決める(クラスタリング)
外れた予想が 3 つあった
録音に講師の声が入っていない?
最初に疑ったのは録音そのものです。イヤホンで聞いていたなら、講師の声は録音に入っていないかもしれません。
確かめると、録音には 2 人の声が入っていました。
ライブラリのバージョンが違う?
次に疑ったのは環境の違いです。同じ録音を Linux の環境で流すと、304 秒と 554 秒の 2 人に分かれました。それでバージョンか環境の差が原因だと考えました。
ところが翌日の 22 分の録音では、Linux でも 775 秒と 17 秒に偏りました。2 人目とされた 17 秒は相づちと雑音だけです。前の日に分かれたのはたまたまだったようです。
声の特徴を取るモデルが合っていない?
3 つ目に疑ったのは、埋め込みを作るモデルです。sherpa-onnx で使える 7 つのモデルを、うまく分かれた録音と偏った録音の 2 本でそれぞれ 8 分ずつ比べました。
うまく分かれた録音では、TitaNet large(NVIDIA)と ERes2Net base(3D-Speaker)で 132 秒と 136 秒にきれいに分かれ、「これだ」と思いました。でも偏った録音では、同じ 2 つのモデルが 268 秒と 4 秒、266 秒と 5 秒です。7 つのモデルのどれを使っても同じように偏りました。
1 本目の録音だけで比べていたら、TitaNet が正解に見えていたはずです。
自分はほとんど話していなかったかもしれない
775 秒と 17 秒という結果を見たとき、自分はこう話していました。
そうですね。私はあんまり喋れなかったと思います。そもそも今回講師の英語があんまり理解できなかったので、喋る回数が非常に少なかったかもしれません。特に最初の方は。
本当に自分の発言が少なかったなら、この数字は正しいのかもしれません。ツールは正しく動いていて、レッスンで自分があまり話せなかっただけ、という可能性も出てきました。
そこで ChatGPT 用に書き出した文字起こしを読んでみると、自分の自己紹介の音読がすべて講師の発言になっていました。やはりツールが間違えていました。
<!-- TODO(本人): 画像 2。自己紹介の音読が講師側に入っている文字起こし(自分の名前・講師名はぼかす)
-->
誰の声か確実に分かる区間を 10 か所選ぶ
ここまでは、話者ごとの秒数を見て、分かれていそうかどうかをなんとなく判断していました。誰の声かという正解と比べていなかったので、1 本目でうまく分かれたように見えても、本当に合っているかは分かりません。
そこで文字起こしの内容から、誰の声か確実に分かる区間を選ぶことにしました。講師の区間を 5 か所、自分の区間を 5 か所で、長さはそれぞれ 8〜40 秒です。内容を読めば判断できる区間だけを選んだので、1 時間ほどでできました。
声の特徴は 2 人を区別できていた
正解の区間ができたので、話者分離の 3 つの手順のどこで間違えているかを調べました。録音に 2 人の声が入っていることは最初に確認したので、次は手順 2 の埋め込みが 2 人の声を区別できているかを測りました。
正解の区間を 30 個の断片に分けて、断片同士の埋め込みがどれくらい近いかをコサイン類似度で測りました。1 に近いほど似ている、という数値です。
組み合わせ
類似度
同じ人の断片どうし
0.56
違う人の断片どうし
0.26
30 個の断片のうち 29 個は、埋め込みだけで正しい話者に分けられました。埋め込みは 2 人の声を区別できていて、間違えていたのは手順 3 のクラスタリングのほうでした。モデルを替えて変わるのは埋め込みなので、原因がクラスタリングにあるなら、モデルをいくつ試しても直りません。
sherpa-onnx の話者分離は、クラスタリングまで含めて 1 つの API になっています。その中のクラスタリングが、講師の声だけがスピーカー越しという今回の録音の条件に合わなかったのだと思います。
クラスタリングだけを自前のものに替える
区間の切り出しはライブラリの結果をそのまま使い、区間ごとに埋め込みを取り直して、クラスタリングだけを自前のものに替えました。中身は次の通りです。
埋め込みが近い区間同士を、近い順にまとめていく(平均リンク法の凝集型クラスタリング)
話している時間の合計が長い上位 2 つのまとまりを、2 人の話者とする
残った小さなまとまり(相づちや雑音)は、近いほうの話者に入れる
正解の区間で測ると、偏っていた録音の正解率は 78% から 98% になりました。もともと分かれていた録音は 92% のままで、下がってはいません。
<!-- TODO(本人): 画像 3。直したあとの結果の画面(話者 A / B に分かれている。ツール名・講師名が映らないように)
-->
「精度が落ちた」と感じたときも測った
その後、処理を速くするために、区間を切り出す部分を別の方法に差し替えました。
「ちょっと精度落ちたけどめちゃ早くなったいいやん!」って感じたので、実際に精度を比べてみました。
正解の区間で測り直した結果は次の通りです。
録音
差し替え前
差し替え後
偏っていた録音
98.2%
97.8%
分かれていた録音
91.7%
92.1%
精度はほとんど変わっていませんでした。感覚では落ちたと思っていましたが、正解の区間と比べて変わっていないと分かったので、ここは直さないことにしました。
まとめ
今回は、録音、環境、モデルの順に原因を疑いました。録音を最初に確かめたのはよかったのですが、その後は埋め込みとクラスタリングのどちらが間違えているかを確かめないまま、環境やモデルを替えにいっていました。
誰の声か確実に分かる区間を 10 か所選んで測ると、どの手順で間違えているかが分かりました。うまく分かれた録音と偏った録音の両方で試していたので、1 本目の結果だけでモデルを決めずに済んでいます。
間違えた例を実際に見て原因を調べる進め方は、Andrew Ng の講座 Structuring Machine Learning Projects でも「Carrying Out Error Analysis」(エラー分析)として紹介されています。
おわりに
そもそも文字起こしに労力をかける気は全くなかったので、最初は ChatGPT に録音をそのまま読み込ませようと思っていました。ただ、長すぎて読み込めなかったので、自分で作る方向に転換しました。
基本的に、何かを作るというのは負債になりますし、時間もかかる行為です。すでに手段があるなら、積極的に活用していくべきだと思いました。
とはいえ、いろいろな数値が取れましたし、AI があるのですぐに開発ができて、結構楽しい経験になりました。まだここで話していないこともあるので、別の記事で話そうと思います。
参考
openai/whisper - GitHub
k2-fsa/sherpa-onnx - GitHub
Speaker Diarization: Pre-trained models - sherpa documentation
pyannote/pyannote-audio - GitHub
nvidia/speakerverification_en_titanet_large - Hugging Face
modelscope/3D-Speaker - GitHub
コサイン類似度 - Wikipedia
Hierarchical clustering - Wikipedia
Structuring Machine Learning Projects - Coursera
2. 긴 강의 영상을 글자로 바꾸고, 고른 문장 구간만 영상으로 잘라줘요.
말한 사람별로 자를 수 있고 자막 파일도 받아요. 한국어는 안내가 없어요.
modelscope/FunClip
1 like · 7 views
Faster MOSS-Image inference with EntroPack INT8 + DiffSynth-Studio pipeline compilation. ⚡
In the reported test: 974 → 507 ms/step.
Inference script ➡️ github.com/modelscope/DiffSynth-Studio/blob/main/…
Local inference & training ➡️ diffsynth-studio-doc.readthedocs.io t.co
1 like · 152 views
modelscope/ultron
Yeah, it exists. 😂
4) It finds your best clips
FunClip transcribes the video, then lets AI pick the moments worth turning into shorts and adds subtitles.
modelscope/FunClip
8 likes · 92 views
魔搭紫皮书
面向开发者的开源模型应用实战指南,覆盖模型选型、推理、微调、评测、RAG、Agent 与 AIGC,从跑通第一个模型到构建实际应用。
整本开源书图文并貌,易于吸收。推荐给想上手开源模型、又总卡在第一步的朋友。
modelscope/ms-cookbook t.co
4 likes · 1,733 views
Introducing EntroPack: a PyTorch tensor compression library that quantizes your model at flexible birrates to fit your exact GPU memory budget.
💻 Open Sourced at: modelscope/entropack
🎛️ Flexible compression: entropy-coding-based calibration-free quantization that offers arbitrary bpp (bits per parameter), not bound by fixed precisions like 4-bit or 8-bit.
⚡ GPU-native decoding: fast, fused decoding and reconstruction in a single kernel, with minimum overhead, suitable for compute-intensivie workloads such as Diffusion denoising and Transformers-Prefill.
🏆 Make the best use of your GPU VRAM: customized bpp for your exact GPU budget. For example, on a 16G GPU, Qwen-Image-2.1 can be quantized with at 4.8 bpp, resulting in 15.86 GiB usage while cutting reconstruction error from NF4's 9.40% to 4.26%.
📦 Ready to try: pre-quantized weights for Z-Image-Turbo, Qwen-Image-2.1, and MiniMax-H3 at 4 to 8 bpp, for DiffSynth-Studio and ComfyUI. The extreme Z-Image build reaches 2.3 bpp, shrinking its DiT weights to 1.6 GB, around one-seventh of BF16.
📜 Licensed under Apache 2.0.
📄 Technical report: modelscope.ai
🤖 modelscope.ai
19 likes · 939 views
Mentions
話者分離がうまくいかず、モデルを 7 つ替えても直らなかった <!-- タイトル候補: 話者分離の精度が出ないとき、最初に作るべきは正解データ 10 か所だった 「モデルを替えれば直る」は 1 本目で当たって 2 本目で外れた --> はじめに 最近英語を話す機会が多いので、自分の英語の改善のためにも、英会話の内容をもとに AI に復習プランを作成してもらいたいと考えました。最初は ChatGPT に録音をそのまま読み込ませようとしたのですが、長すぎて読み込めませんでした。 そこで文字起こしアプリをいくつか調べていたのですが、調べていくうちに、月額料金が思ったより高いことに気づきました。私がやりたいのは、文字起こしをして、それを AI に読み込ませて復習メニューを作ってもらうことだけです。それにしてはちょっと高いなと思ったので、文字起こしアプリを自作することにしました。 この時代すぐに作れますし、自分に必要な最低限のものをローカルで動かすだけなので、作っていこうと思いました。 ここで盲点だったのが話者分離(録音の中で誰が話したかを区別する処理)です。私はただ文字起こしをすればいいと思っていたのですが、話者分離ができたほうが復習にはかなり役に立ちますし、AI 側も汲み取って復習プランを組みやすいことに気づきました。なので、この時点での要件は、ローカルで動くこと、話者分離ができること、文字起こしができることの 3 つになります。 調べていくと、そういったライブラリが OSS ですでに提供されていることまで分かりました。いくつかあったので、それぞれ色々と試しました。今は文字起こしに Whisper、話者分離に sherpa-onnx を使っています。 ところが話者分離をかけると、講師と私が 1 人の話者にまとめられてしまいました。直すまでに 3 晩かかり、その間に原因の予想を 3 回外しています。最後は、誰の声か確実に分かる区間を 10 か所選んで測ったところで原因が分かりました。この記事はその記録です。 話者が 1 人しか出てこない 23 分の録音を話者分離にかけると、話者 A が 1580 語、話者 B が 0 語になりました。録音全体が 1 人の発言として扱われています。 <!-- TODO(本人): 画像 1。話者 A だけになった結果の画面(ツール名・講師名が映らないように切り抜く) --> 録音は iPhone でしています。講師の声は PC のスピーカー越しに入り、自分の声は直接入ります。 sherpa-onnx は、音声認識や音声合成、話者分離などをまとめて動かせるライブラリです。話者分離は次の順に進みます(構成は公式ドキュメントに載っています)。 録音から、誰かが話している区間を切り出す(pyannote の segmentation モデルを使います) 区間ごとに、声の特徴を数値の並びにする(埋め込みと呼ばれます) 特徴が近い区間をまとめて、まとまりごとに話者を決める(クラスタリング) 外れた予想が 3 つあった 録音に講師の声が入っていない? 最初に疑ったのは録音そのものです。イヤホンで聞いていたなら、講師の声は録音に入っていないかもしれません。 確かめると、録音には 2 人の声が入っていました。 ライブラリのバージョンが違う? 次に疑ったのは環境の違いです。同じ録音を Linux の環境で流すと、304 秒と 554 秒の 2 人に分かれました。それでバージョンか環境の差が原因だと考えました。 ところが翌日の 22 分の録音では、Linux でも 775 秒と 17 秒に偏りました。2 人目とされた 17 秒は相づちと雑音だけです。前の日に分かれたのはたまたまだったようです。 声の特徴を取るモデルが合っていない? 3 つ目に疑ったのは、埋め込みを作るモデルです。sherpa-onnx で使える 7 つのモデルを、うまく分かれた録音と偏った録音の 2 本でそれぞれ 8 分ずつ比べました。 うまく分かれた録音では、TitaNet large(NVIDIA)と ERes2Net base(3D-Speaker)で 132 秒と 136 秒にきれいに分かれ、「これだ」と思いました。でも偏った録音では、同じ 2 つのモデルが 268 秒と 4 秒、266 秒と 5 秒です。7 つのモデルのどれを使っても同じように偏りました。 1 本目の録音だけで比べていたら、TitaNet が正解に見えていたはずです。 自分はほとんど話していなかったかもしれない 775 秒と 17 秒という結果を見たとき、自分はこう話していました。 そうですね。私はあんまり喋れなかったと思います。そもそも今回講師の英語があんまり理解できなかったので、喋る回数が非常に少なかったかもしれません。特に最初の方は。 本当に自分の発言が少なかったなら、この数字は正しいのかもしれません。ツールは正しく動いていて、レッスンで自分があまり話せなかっただけ、という可能性も出てきました。 そこで ChatGPT 用に書き出した文字起こしを読んでみると、自分の自己紹介の音読がすべて講師の発言になっていました。やはりツールが間違えていました。 <!-- TODO(本人): 画像 2。自己紹介の音読が講師側に入っている文字起こし(自分の名前・講師名はぼかす) --> 誰の声か確実に分かる区間を 10 か所選ぶ ここまでは、話者ごとの秒数を見て、分かれていそうかどうかをなんとなく判断していました。誰の声かという正解と比べていなかったので、1 本目でうまく分かれたように見えても、本当に合っているかは分かりません。 そこで文字起こしの内容から、誰の声か確実に分かる区間を選ぶことにしました。講師の区間を 5 か所、自分の区間を 5 か所で、長さはそれぞれ 8〜40 秒です。内容を読めば判断できる区間だけを選んだので、1 時間ほどでできました。 声の特徴は 2 人を区別できていた 正解の区間ができたので、話者分離の 3 つの手順のどこで間違えているかを調べました。録音に 2 人の声が入っていることは最初に確認したので、次は手順 2 の埋め込みが 2 人の声を区別できているかを測りました。 正解の区間を 30 個の断片に分けて、断片同士の埋め込みがどれくらい近いかをコサイン類似度で測りました。1 に近いほど似ている、という数値です。 組み合わせ 類似度 同じ人の断片どうし 0.56 違う人の断片どうし 0.26 30 個の断片のうち 29 個は、埋め込みだけで正しい話者に分けられました。埋め込みは 2 人の声を区別できていて、間違えていたのは手順 3 のクラスタリングのほうでした。モデルを替えて変わるのは埋め込みなので、原因がクラスタリングにあるなら、モデルをいくつ試しても直りません。 sherpa-onnx の話者分離は、クラスタリングまで含めて 1 つの API になっています。その中のクラスタリングが、講師の声だけがスピーカー越しという今回の録音の条件に合わなかったのだと思います。 クラスタリングだけを自前のものに替える 区間の切り出しはライブラリの結果をそのまま使い、区間ごとに埋め込みを取り直して、クラスタリングだけを自前のものに替えました。中身は次の通りです。 埋め込みが近い区間同士を、近い順にまとめていく(平均リンク法の凝集型クラスタリング) 話している時間の合計が長い上位 2 つのまとまりを、2 人の話者とする 残った小さなまとまり(相づちや雑音)は、近いほうの話者に入れる 正解の区間で測ると、偏っていた録音の正解率は 78% から 98% になりました。もともと分かれていた録音は 92% のままで、下がってはいません。 <!-- TODO(本人): 画像 3。直したあとの結果の画面(話者 A / B に分かれている。ツール名・講師名が映らないように) --> 「精度が落ちた」と感じたときも測った その後、処理を速くするために、区間を切り出す部分を別の方法に差し替えました。 「ちょっと精度落ちたけどめちゃ早くなったいいやん!」って感じたので、実際に精度を比べてみました。 正解の区間で測り直した結果は次の通りです。 録音 差し替え前 差し替え後 偏っていた録音 98.2% 97.8% 分かれていた録音 91.7% 92.1% 精度はほとんど変わっていませんでした。感覚では落ちたと思っていましたが、正解の区間と比べて変わっていないと分かったので、ここは直さないことにしました。 まとめ 今回は、録音、環境、モデルの順に原因を疑いました。録音を最初に確かめたのはよかったのですが、その後は埋め込みとクラスタリングのどちらが間違えているかを確かめないまま、環境やモデルを替えにいっていました。 誰の声か確実に分かる区間を 10 か所選んで測ると、どの手順で間違えているかが分かりました。うまく分かれた録音と偏った録音の両方で試していたので、1 本目の結果だけでモデルを決めずに済んでいます。 間違えた例を実際に見て原因を調べる進め方は、Andrew Ng の講座 Structuring Machine Learning Projects でも「Carrying Out Error Analysis」(エラー分析)として紹介されています。 おわりに そもそも文字起こしに労力をかける気は全くなかったので、最初は ChatGPT に録音をそのまま読み込ませようと思っていました。ただ、長すぎて読み込めなかったので、自分で作る方向に転換しました。 基本的に、何かを作るというのは負債になりますし、時間もかかる行為です。すでに手段があるなら、積極的に活用していくべきだと思いました。 とはいえ、いろいろな数値が取れましたし、AI があるのですぐに開発ができて、結構楽しい経験になりました。まだここで話していないこともあるので、別の記事で話そうと思います。 参考 openai/whisper - GitHub k2-fsa/sherpa-onnx - GitHub Speaker Diarization: Pre-trained models - sherpa documentation pyannote/pyannote-audio - GitHub nvidia/speakerverification_en_titanet_large - Hugging Face modelscope/3D-Speaker - GitHub コサイン類似度 - Wikipedia Hierarchical clustering - Wikipedia Structuring Machine Learning Projects - Coursera
2. 긴 강의 영상을 글자로 바꾸고, 고른 문장 구간만 영상으로 잘라줘요. 말한 사람별로 자를 수 있고 자막 파일도 받아요. 한국어는 안내가 없어요. modelscope/FunClip
Faster MOSS-Image inference with EntroPack INT8 + DiffSynth-Studio pipeline compilation. ⚡ In the reported test: 974 → 507 ms/step. Inference script ➡️ github.com/modelscope/DiffSynth-Studio/blob/main/… Local inference & training ➡️ diffsynth-studio-doc.readthedocs.io t.co
modelscope/ultron Yeah, it exists. 😂
4) It finds your best clips FunClip transcribes the video, then lets AI pick the moments worth turning into shorts and adds subtitles. modelscope/FunClip
魔搭紫皮书 面向开发者的开源模型应用实战指南,覆盖模型选型、推理、微调、评测、RAG、Agent 与 AIGC,从跑通第一个模型到构建实际应用。 整本开源书图文并貌,易于吸收。推荐给想上手开源模型、又总卡在第一步的朋友。 modelscope/ms-cookbook t.co
Introducing EntroPack: a PyTorch tensor compression library that quantizes your model at flexible birrates to fit your exact GPU memory budget. 💻 Open Sourced at: modelscope/entropack 🎛️ Flexible compression: entropy-coding-based calibration-free quantization that offers arbitrary bpp (bits per parameter), not bound by fixed precisions like 4-bit or 8-bit. ⚡ GPU-native decoding: fast, fused decoding and reconstruction in a single kernel, with minimum overhead, suitable for compute-intensivie workloads such as Diffusion denoising and Transformers-Prefill. 🏆 Make the best use of your GPU VRAM: customized bpp for your exact GPU budget. For example, on a 16G GPU, Qwen-Image-2.1 can be quantized with at 4.8 bpp, resulting in 15.86 GiB usage while cutting reconstruction error from NF4's 9.40% to 4.26%. 📦 Ready to try: pre-quantized weights for Z-Image-Turbo, Qwen-Image-2.1, and MiniMax-H3 at 4 to 8 bpp, for DiffSynth-Studio and ComfyUI. The extreme Z-Image build reaches 2.3 bpp, shrinking its DiT weights to 1.6 GB, around one-seventh of BF16. 📜 Licensed under Apache 2.0. 📄 Technical report: modelscope.ai 🤖 modelscope.ai