Zenn
Closed9

オープンソースの会話ターン検出モデル「pipecat-ai/smart-turn」を試す

kun432kun432

VAP(Voice Acitivity Detection)だよね

https://x.com/kwindla/status/1897711929617154148

オープンソース、ネイティブ音声のターン検出 🎉🎉🎉

現在、ほとんどの音声エージェントは、特定の短い長さの音声の休止を待つことでターン検出を行っています。しかし、人間同士が会話をする際には、このような方法で方向検出を行うことはありません!

私は、友人たちと新しい方向検出モデルに取り組んでいます。この問題や機械学習エンジニアリングについてもっと知りたい方は、ぜひ私たちと一緒に小さなモデルをハックしてみましょう!

詳細は下記をご覧ください。

https://x.com/kwindla/status/1897711931311767616

GitHubリポジトリ:https://github.com/pipecat-ai/smart-turn

HuggingFaceモデル:https://huggingface.co/pipecat-ai/smart-turn

プロジェクトの目標は、最先端のターン検出モデルを構築することです。

➡️ 誰でも使用できる、
➡️ 実運用環境への導入が容易、
➡️ 特定のアプリケーションのニーズに合わせて簡単に微調整できる。

https://x.com/kwindla/status/1897711932809068772

私たちが投稿する前に、昨夜すでにこれを見つけた人もいました!

このモデルは、音声AI技術スタックにおける重要なギャップを埋めるものだと思います。多くの人々がデータを寄与し、微調整やコードの改善を行えば、どこまで到達できるのか、とても楽しみです。

https://x.com/askjohngeorge/status/1897460590957740195

https://x.com/askjohngeorge/status/1897460590957740195

kun432kun432

GitHubレポジトリ。前提として現時点では日本語非対応。

https://github.com/pipecat-ai/smart-turn

スマートターン検出

これは、オープンソースでコミュニティ主導のネイティブ音声ターン検出モデルです。

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エンジニアリングに初めて取り組む場合の優れた学習プロジェクトです。下記の「やるべきこと」をご覧ください。

リンク

推論

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 デバイス上でローカルにこのモデルを実行する可能性も開くでしょう。

貢献者

kun432kun432

軽く動かしてみようと思ってクローンするとこうなる。

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上げた

https://github.com/pipecat-ai/smart-turn/issues/3

2025/03/08追記

修正されていた

kun432kun432

とりあえずどういうデータセットで学習しているのかを見てみた。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 モデルは大量の多言語データでトレーニングされています。追加の言語をサポートするには、各言語のデータを収集してクリーニングするか、または合成生成する必要があります。

あたりと、トレーニング用のコードも公開されていることを踏まえると、音声データ+アノテーションさえ用意できれば、日本語対応モデルも作れそうな気がする。

kun432kun432

とりあえず軽く試してみた。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

にはなった。それほど試したわけではないし、当然ながらきちんと日本語で学習させればまた変わってくるのではないかと思う。

このスクラップは2ヶ月前にクローズされました
ログインするとコメントできます