オープンソースの会話ターン検出モデル「pipecat-ai/smart-turn」を試す
VAP(Voice Acitivity Detection)だよね
オープンソース、ネイティブ音声のターン検出 🎉🎉🎉
現在、ほとんどの音声エージェントは、特定の短い長さの音声の休止を待つことでターン検出を行っています。しかし、人間同士が会話をする際には、このような方法で方向検出を行うことはありません!
私は、友人たちと新しい方向検出モデルに取り組んでいます。この問題や機械学習エンジニアリングについてもっと知りたい方は、ぜひ私たちと一緒に小さなモデルをハックしてみましょう!
詳細は下記をご覧ください。
GitHubリポジトリ:https://github.com/pipecat-ai/smart-turn
HuggingFaceモデル:https://huggingface.co/pipecat-ai/smart-turn
プロジェクトの目標は、最先端のターン検出モデルを構築することです。
➡️ 誰でも使用できる、
➡️ 実運用環境への導入が容易、
➡️ 特定のアプリケーションのニーズに合わせて簡単に微調整できる。
私たちが投稿する前に、昨夜すでにこれを見つけた人もいました!
このモデルは、音声AI技術スタックにおける重要なギャップを埋めるものだと思います。多くの人々がデータを寄与し、微調整やコードの改善を行えば、どこまで到達できるのか、とても楽しみです。
VAPについてはこちら。VADとの違いも書いてある。
Pipecatが作ってるという点で期待してる。
GitHubレポジトリ。前提として現時点では日本語非対応。
スマートターン検出
これは、オープンソースでコミュニティ主導のネイティブ音声ターン検出モデルです。
HuggingFace ページ: pipecat-ai/smart-turn
ターン検出は、会話型音声AI技術スタックの中で最も重要な機能の一つです。ターン検出とは、音声エージェントが人間の音声にいつ応答すべきかを判断することを意味します。
現在のほとんどの音声エージェントは、ターン検出の基盤として 音声活動検出 (VAD) を使用しています。VAD は音声を「音声」と「非音声」のセグメントに分割します。VAD は、音声の実際の言語的または音響的内容を考慮することができません。人間は文法、口調、話す速度、その他さまざまな複雑な音声および意味の手がかりに基づいてターン検出を行います。私たちは、VAD ベースのアプローチよりも人間の期待により近いモデルの構築を目指しています。
これは真にオープンなモデルです(BSD 2条項ライセンス)。誰でもこのプロジェクトを利用、フォーク、貢献することができます。このモデルは、Pipecat エコシステムの進行中のコンポーネントとして誕生しました。Pipecat は、オープンソースでベンダーニュートラルな、音声およびマルチモーダルのリアルタイムAIエージェントを構築するためのフレームワークです。
モデルの現状
これは初期の概念実証モデルです。いくつかの一般的な非完了シナリオに対応しています。対応言語は英語のみです。トレーニングデータセットは比較的小規模です。
私たちは、さまざまなアーキテクチャとトレーニングデータへのアプローチを試しており、パフォーマンスが急速に向上できるという自信から、このバージョンのモデルをリリースすることにしました。
このモデルをお試しいただき、モデル開発と実験にご協力いただければ幸いです。
概念実証モデルチェックポイントの実行
環境のセットアップ。
python3.12 -m venv venv source venv/bin/activate pip install -r requirements.txt
システムのマイクからオーディオをストリームし、VAD を使用してセグメントの開始/停止を検出し、各セグメントをフレーズのエンドポイント予測のためにモデルに送信するコマンドラインユーティリティを実行します。
# # 初回起動時は約30秒かかります。 # # "ボキャブラリー" は限られています。以下を試してみてください: # # - "I can't seem to, um ..." # - "I can't seem to, um, find the return label." python record_and_predict.py
プロジェクトの目標
現在のバージョンのこのモデルは、Meta AI の Wav2Vec2-BERT バックボーンに基づいています。モデルアーキテクチャの詳細は以下をご覧ください。
このプロジェクトの大きな目標は、以下の特徴を持つ最先端のターン検出モデルを構築することです:
- 誰でも利用可能であること、
- 本番環境へのデプロイが容易であること、
- 特定のアプリケーションニーズに合わせてファインチューニングが容易であること。
現在の制限事項:
- 英語のみ
- 推論速度が比較的遅い
- GPU で約150ms
- CPU で約1500ms
- トレーニングデータは主にセグメント末尾のポーズフィラー語に焦点を当てています。
中期的な目標:
- 幅広い言語のサポート
- GPU での推論時間を50ms未満、CPU での推論時間を500ms未満にする
- トレーニングデータで捉える音声のニュアンスを大幅に拡充する
- 完全に合成されたトレーニングデータパイプラインの構築
- クレジットカード番号、電話番号、住所入力などの「モード」をサポートするための、テキストによるモデルの条件付け
モデルアーキテクチャ
Wav2Vec2-BERT は、Meta AI の Seamless-M4T プロジェクトの一環として開発された音声エンコーダーモデルです。これは、音響情報と言語情報の両方を活用できる580Mパラメータのベースモデルです。ベースモデルは、143以上の言語をカバーする450万時間以上のラベルなし音声データでトレーニングされています。
Wav2Vec2-BERT を使用するには、通常、ベースモデルに追加のレイヤーを加え、アプリケーション固有のデータセットでトレーニングまたはファインチューニングを行います。
現在、私たちは Hugging Face Transformers ライブラリに
Wav2Vec2BertForSequenceClassification
として便利にパッケージ化された、シンプルな2層の分類ヘッドを使用しています。私たちは、Wav2Vec2-BERT の広く使用されている前身である Wav2Vec2 や、より複雑な分類アプローチを含む、さまざまなアーキテクチャを実験してきました。モデルに取り組む私たちの中には、シンプルな分類ヘッドが、データセットにより複雑な要素を加えるにつれてうまく機能すると考える者もいれば、逆の直感を持つ者もいます。今後の実験次第です!モデルアーキテクチャへの追加実験は、MLエンジニアリングに初めて取り組む場合の優れた学習プロジェクトです。下記の「やるべきこと」をご覧ください。
リンク
- Meta AI Seamless 論文
- W2v-BERT 2.0 音声エンコーダー README
- Wav2Vec2BertForSequenceClassification HuggingFace ドキュメント
推論
predict.py
は、音声サンプルをモデルに通して分類する方法を示しています。inference.py
内の小さな便宜関数が、音声前処理と PyTorch 推論コードをラップしています。# inference.py 内で定義 def predict_endpoint(audio_array): """ オーディオセグメントが完了(ターン終了)しているか未完了であるかを予測します。 引数: audio_array: 16kHz の音声サンプルを含む Numpy 配列 戻り値: 予測結果を含む辞書: - prediction: 完了の場合は 1、未完了の場合は 0 - probability: 完了クラスの確率 """ # 音声の処理 inputs = processor( audio_array, sampling_rate=16000, padding="max_length", truncation=True, max_length=800, # トレーニング時に指定された最大長 return_attention_mask=True, return_tensors="pt", ) # 入力をデバイスへ移動 inputs = {k: v.to(device) for k, v in inputs.items()} # 推論の実行 with torch.no_grad(): outputs = model(**inputs) logits = outputs.logits # ソフトマックスを用いて確率を取得 probabilities = torch.nn.functional.softmax(logits, dim=1) completion_prob = probabilities[0, 1].item() # クラス1(完了)の確率 # 予測の実施(完了の場合は1、未完了の場合は0) prediction = 1 if completion_prob > 0.5 else 0 return { "prediction": prediction, "probability": completion_prob, }
トレーニング
すべてのトレーニングコードは
train.py
に定義されています。ローカルまたは Modal を使用してトレーニングを実行できます。トレーニング実行は、ログ記録を無効にしない限り Weights & Biases に記録されます。
# Modal でトレーニングジョブを実行するには、トレーニングデータを Modal ボリュームにアップロードし、 # Modal 環境をセットアップして、以下を実行します: modal run --detach train.py
データの収集と提供
現在、トレーニングと評価には2つのデータセットが使用されています:
- datasets/human_5_all -- 人間のインタラクションから記録されたセグメント化された音声 - datasets/rime_2 -- [Rime](https://rime.ai/) を使用して生成された合成音声
これら2つのデータセットが読み込まれる際に、4つの分割が作成されます 参照: train.py#L188。
- トレイン、バリデート、テストセットは、合成データと人間データの混合です - ヒューマン評価セットは人間データのみを含みます
7 -- TRAIN -- 8 Total samples: 5,694 9 Positive samples (Complete): 2,733 (48.00%) 10 Negative samples (Incomplete): 2,961 (52.00%) 11 12 -- VALIDATION -- 13 Total samples: 712 14 Positive samples (Complete): 352 (49.44%) 15 Negative samples (Incomplete): 360 (50.56%) 16 17 -- TEST -- 18 Total samples: 712 19 Positive samples (Complete): 339 (47.61%) 20 Negative samples (Incomplete): 373 (52.39%) 21 22 -- HUMAN_EVAL -- 23 Total samples: 773 24 Positive samples (Complete): 372 (48.12%) 25 Negative samples (Incomplete): 401 (51.88%)
初期バージョンのこのモデルの目標は、非自明な量のデータに過剰適合させ、インタラクティブな実験時に定性的な「バイブス」閾値を超えることでした。次のステップは、データの量を拡大し、過剰適合からより一般化へと移行することです。
referred from https://github.com/pipecat-ai/smart-turn[ データに関するさらなるノートは近日公開予定 ]
やるべきこと
さらなる言語の追加
ベースの Wav2Vec2-BERT モデルは大量の多言語データでトレーニングされています。追加の言語をサポートするには、各言語のデータを収集してクリーニングするか、または合成生成する必要があります。
さらなるデータの追加
現在のチェックポイントは約8,000サンプルのデータセットでトレーニングされました。これらのサンプルは主に、英語音声において発話完了なしのポーズの典型的なフィラー語に焦点を当てています。
トレーニングには2つのデータセットが使用されています: 人間の話者から収集された約4,000サンプルと、Rime を使用して生成された約4,000サンプルの合成データです。
最も大きな短期的なデータニーズは、より広範な音声パターンを表す人間のデータサンプルを収集、分類、クリーニングすることです:
- 完了した発話セグメントではなく、「思考中」のポーズを示すイントネーションとペース
- 未完了の発話セグメントで一般的に発生する文法構造(ただし完了したセグメントには見られない)
- より多くの個々の話者の代表性
- より多くの地域およびアクセントの代表性
datasets/rime_2
データセット内の合成データサンプルは、現時点ではモデルの性能を僅かに向上させるに留まっています。しかし、このプロジェクトの一つの目標は、完全に合成されたデータ生成パイプラインの構築に向けた取り組みです。そのパイプラインの潜在的な利点には、より容易に多言語をサポートできること、より正確なモデルの構築に向けたフライホイールの改善、特定のユースケースに迅速にカスタマイズできる能力が含まれます。発話モデルを特定のパターンで出力するように誘導する専門知識がある場合(または実験して学びたい場合)、合成データの提供をご検討ください。
アーキテクチャ実験
現在のモデルアーキテクチャは比較的シンプルです。なぜなら、ベースの Wav2Vec2-BERT モデル自体がすでに非常に強力だからです。
しかし、Wav2Vec2-BERT モデルの上に追加される分類手法として、他のアプローチを実験するのは興味深いでしょう。これは、バイナリ分類から、このターン検出タスクにより特化したアプローチへと移行したい場合に特に有用かもしれません。
例えば、モデルに追加の文脈を提供して推論を条件付けすることができれば素晴らしいでしょう。利用例としては、ユーザーが現在、クレジットカード番号、電話番号、またはメールアドレスを暗唱しているとモデルが「認識」できるようにする場合などが挙げられます。
モデルに追加の文脈を与えることは、未解決のオープンエンドの研究課題です。よりシンプルなやるべき項目としては、以下が含まれます:
- トレーニング中に凍結するレイヤー数の実験
- ハイパーパラメータの調整
- 分類ヘッドのサイズや、多少異なる分類ヘッドの設計および損失関数の試行
より多くのプラットフォームでのトレーニングサポート
私たちは、このモデルの初期バージョンを Google Colab でトレーニングしました。再び Colab をトレーニングプラットフォームとしてサポートすべきです!さまざまなプラットフォームでのトレーニング用クイックスタートがあると素晴らしいでしょう。
また、トレーニングコードを Apple の MLX プラットフォームに移植すべきです。多くのメンバーが MacBook を使用しています!
最適化
このモデルは量子化バージョンで優れた性能を発揮する可能性が高いです。量子化バージョンは、現在の float32 の重みよりも大幅に高速に動作するはずです。
PyTorch の推論コードは特に最適化されているわけではありません。GPU と CPU の両方で大幅に高速に動作するような、手作業で書かれた推論コードが実現できるはずです。
また、推論コードを Apple の MLX プラットフォームに移植することも望ましいです。これは、ローカルでの開発やデバッグに特に有用であるとともに、量子化と組み合わせることで iOS デバイス上でローカルにこのモデルを実行する可能性も開くでしょう。
貢献者
軽く動かしてみようと思ってクローンするとこうなる。
git lfs install
git clone https://github.com/pipecat-ai/smart-turn
Git LFS initialized.
Cloning into 'smart-turn'...
remote: Enumerating objects: 54, done.
remote: Counting objects: 100% (54/54), done.
remote: Compressing objects: 100% (38/38), done.
remote: Total 54 (delta 20), reused 47 (delta 13), pack-reused 0 (from 0)
Receiving objects: 100% (54/54), 259.18 KiB | 1.28 MiB/s, done.
Resolving deltas: 100% (20/20), done.
Downloading datasets/human_5_all/train/data-00000-of-00001.arrow (338 MB)
Error downloading object: datasets/human_5_all/train/data-00000-of-00001.arrow (4bb1a18): Smudge error: Error downloading datasets/human_5_all/train/data-00000-of-00001.arrow (4bb1a18f72ccb4da60ce6b68360c6bf57b1ce37e09cdf17f86447b3357531400): batch response: This repository is over its data quota. Account responsible for LFS bandwidth should purchase more data packs to restore access.
Errors logged to /content/smart-turn/.git/lfs/logs/20250307T170746.396066929.log
Use `git lfs logs last` to view the log.
error: external filter 'git-lfs filter-process' failed
fatal: datasets/human_5_all/train/data-00000-of-00001.arrow: smudge filter lfs failed
warning: Clone succeeded, but checkout failed.
You can inspect what was checked out with 'git status'
and retry with 'git restore --source=HEAD :/'
んー、サイズデカすぎてレポジトリ側で制限かかってるってことかな?
とりあえずissue上げた
2025/03/08追記
修正されていた
とりあえずどういうデータセットで学習しているのかを見てみた。Colaboratory T4で。
!apt install libasound2-dev portaudio19-dev libportaudio2 libportaudiocpp0 ffmpeg
!git lfs install
!git clone https://github.com/pipecat-ai/smart-turn
%cd smart-turn
!pip install -r requirements.txt
from datasets import load_from_disk
human_dataset = load_from_disk("datasets/human_5_all")
rime_dataset = load_from_disk("datasets/rime_2")
とりまデータを1つ見てみる
human_dataset
DatasetDict({
train: Dataset({
features: ['audio', 'endpoint_bool'],
num_rows: 3862
})
})
human_dataset["train"][0]
{'audio': {'path': None,
'array': array([-0.00457764, 0.00320435, 0.00619507, ..., -0.0015564 ,
-0.00146484, -0.00137329]),
'sampling_rate': 16000},
'endpoint_bool': True}
数秒程度の音声データに、どうやら発話の終了=会話ターンの変更を示すフラグが付いたデータになっている様子。
サンプルをピックアップしてみたが、英語なので正直わからない。とりあえずざっと文字起こししてみた。文字起こしには少し前に見かけたUsefulSensors/moonshine-baseを使ってみた。Whisperだとフィラーとか取っ払っちゃう印象があったので。
from transformers import AutoProcessor, MoonshineForConditionalGeneration
processor = AutoProcessor.from_pretrained("UsefulSensors/moonshine-base")
model = MoonshineForConditionalGeneration.from_pretrained("UsefulSensors/moonshine-base")
def moonshine_transcribe(example):
audio_array = example["audio"]["array"]
sampling_rate = example["audio"]["sampling_rate"]
inputs = processor(audio_array, sampling_rate=sampling_rate, return_tensors="pt")
generated_ids = model.generate(**inputs)
transcription = processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
example["transcription"] = transcription
return example
import pandas as pd
human_dataset["train"] = human_dataset["train"].map(moonshine_transcribe)
human_df = human_dataset["train"].to_pandas()
human_df = human_df[["transcription", "endpoint_bool"]]
human_df
こんな感じ。文字起こしの精度的に所々抜けていたり句読点がおそらく間違っていたりするけども、想定していた通りに見える。
ベースの Wav2Vec2-BERT モデルは大量の多言語データでトレーニングされています。追加の言語をサポートするには、各言語のデータを収集してクリーニングするか、または合成生成する必要があります。
あたりと、トレーニング用のコードも公開されていることを踏まえると、音声データ+アノテーションさえ用意できれば、日本語対応モデルも作れそうな気がする。
とりあえず軽く試してみた。Ubuntu-22.04+RTX4090環境。手順はREADME通り。
適当に英語で話しかけるとこんな感じで出力される。
--------
Prediction: Complete
Probability of complete: 0.9973
Listening for speech...
Processing speech segment of length 2.62 seconds...
--------
Prediction: Incomplete
Probability of complete: 0.0022
Listening for speech...
Processing speech segment of length 1.54 seconds...
--------
Prediction: Complete
Probability of complete: 0.9959
Listening for speech...
Processing speech segment of length 2.66 seconds...
--------
Prediction: Incomplete
Probability of complete: 0.0024
Listening for speech...
Processing speech segment of length 0.42 seconds...
--------
Complete
が明確な発話の終了、Incomplete
は、例えば「well...」とか「um...」とか「I'm thinking about...」みたいに言い淀んだりしたタイミングで表示されているように思える。どっちかというとイントネーションのほうが反映されているような印象はあるな。例えば
- 「I'm thinking aboooout→」だと
Incomplete
- 「I'm thinking about↓」だと
Complete
って感じかな。なのでそのあたりの雰囲気を踏まえて日本語で話すと
- 「おはよう。今日の日付はーーー...」だと
Incomplete
- 「おはよう。今日の日付は」だと
Complete
にはなった。それほど試したわけではないし、当然ながらきちんと日本語で学習させればまた変わってくるのではないかと思う。
ベースとなっているこちらもちょっと試してみようかな
CoreMLに対応してた