音声対音声モデル

Soniqoは、会話向けのネイティブMLX音声対音声モデルを2系統サポートしています:PersonaPlex 7BVoiceChat 11Bです。どちらも音声を受け取り、モデル音声を直接生成しますが、デュプレックス構成とランタイム契約が異なります。

モデルを選ぶ

モデル会話方式適した用途
PersonaPlex 7BMoshi、Depformer、Mimiによる同時フルデュプレックス聞く・話すの重なりと、選択可能な18音声
VoiceChat 11BFastConformer、Nemotron-H、EAR-TTS、ニューラルコーデックによる連続フレーム同期デュプレックス80 msストリーミングフレーム、テキスト/関数イベント、チェックポイント固有音声

ここで扱うのは会話型の音声対音声モデルです。Hibikiも音声を直接音声へ変換しますが、用途はストリーミング音声翻訳のため、別ページで説明しています。

PersonaPlex 7B

Moshiアーキテクチャ(Kyutai)に基づく全二重音声間対話モデル。PersonaPlex 7Bは、音声入力から直接音声応答を生成します — 中間テキストパイプラインは必要ありません。モデルは18のボイスプリセットを備え、8ビット(推奨)と4ビット量子化で利用可能です。8ビットがデフォルトです — 30%高速で首尾一貫した応答を生成しますが、4ビットは出力品質を劣化させます。

VoiceChat 11B

全二重 speech-to-speech の参照:SALM-Duplex: Efficient and Direct Duplex Modeling for Speech-to-Speech Language Model(Interspeech 2025)。NVIDIA の上流 VoiceChat モデルカードが引用しています。

M5 Pro、48 GB、Release、80 ms ライブ周期、保護ヘッド INT5:3 回の制御済み実行でパイプライン全体の RTF は 0.94、0.92、0.92、ピーク RSS は約 8.70 GB でした。最初の発話テキストは 44.3–46.7 ms、最初に再生可能な音声は 74.0–76.4 ms で得られました。これらはウォーム状態の計算値であり、学習されたターンテイキング遅延ではありません。最適化後の INT8 性能はまだ再測定していません。

VoiceChat は speech-swift のもう一つのネイティブ MLX 音声間ランタイムです。因果 FastConformer 知覚、Nemotron-H の全二重テキスト/関数チャンネル、独立したテキスト条件付き EAR-TTS、22.05 kHz ニューラルコーデックを組み合わせます。セッションは 16 kHz モノラル音声を連続して受け取り、80 ms ごとにテキストイベントと 1,764 サンプルの出力フレームを返します。

VoiceChatModel.load(from:) で読み込み、VoiceChatSession を開始して pushAudio で音声を送ります。完全な bundle には encoder/llm/tts/ が必要で、旧来の理解専用 bundle は拒否されます。

現在の性能

INT5 はテストした M5 Pro で RTF 1 未満の平均スループットを維持します。3 回すべてでフレーム合計 p95 も 76.2–78.6 ms と 80 ms 未満でしたが、デッドラインの余裕はまだ小さいです。モデルの発話開始とハードウェア計算遅延は別々に測定してください。

PersonaPlexのアーキテクチャと使い方

PersonaPlexは3つのコアコンポーネントを持つマルチストリーム自己回帰モデルです:

コンポーネント詳細
Temporal Transformer32レイヤー、dim=4096、32ヘッド、SwiGLU (hidden_scale=4.125)、RoPE、8ビット量子化(デフォルト)
Depformer6レイヤー、dim=1024、16ヘッド、MultiLinear (weights_per_step=true)、dep_q=16
Mimi Codec16コードブック、12.5 Hzフレームレート、24 kHz音声出力

モデルは17ストリームを同時に処理します:1テキストストリーム + 8ユーザー音声ストリーム + 8agent音声ストリーム。このアーキテクチャにより、モデルが同時に聞いて話すことができる全二重会話が可能になります。

ボイスプリセット

PersonaPlexには、自然で多様なスタイルにわたる18の組み込みボイスプリセットが含まれています:

カテゴリプリセット
ナチュラル女性NATF0, NATF1, NATF2, NATF3
ナチュラル男性NATM0, NATM1, NATM2, NATM3
バリード女性VARF0, VARF1, VARF2, VARF3, VARF4
バリード男性VARM0, VARM1, VARM2, VARM3, VARM4

インナーモノローグ

PersonaPlexは各ステップで2つの並列ストリームを生成します:Mimiコーデック用の8つの音声コードブックトークンと、モデルの内部モノローグ用の1つのテキストトークン。テキストストリームは、モデルが話すときに「考えている」ことです — 最終音声から少し発散する可能性がありますが、実際にはライブトランスクリプトとして使用できるほど話された応答と密接に反映します。

テキストトークンは生のSentencePieceピースIDとして返されます。PersonaPlexに同梱されているSentencePieceDecoderでデコードしてください:

import PersonaPlex
import AudioCommon

let model = try await PersonaPlexModel.fromPretrained()
let decoder = model.tokenizer  // SentencePieceDecoder?

let result = model.respond(userAudio: userSamples, voice: .NATM0)
let transcript = decoder?.decode(result.textTokens) ?? ""
print(transcript)        // "Sure, I can help with that..."
playAudio(result.audio)  // 24 kHz mono Float32

ストリーミングモードでは、respondStreamが生成されるにつれてtextTokensチャンクを出力します — 音声がまだ生成中の間にライブキャプションビューを駆動するために、それらを増分的にデコードします。--transcript CLIフラグは、まさにこれを舞台裏で行います。

なぜ重要か: SentencePieceDecoderは共有のAudioCommon.SentencePieceModel protobufリーダー上に構築されているため、PersonaPlex、OmnilingualASR、および将来のSentencePieceベースのモデルはすべて、同じトークナイザー実装を通じてデコードします。SentencePieceModelリファレンスを参照してください。

システムプロンプト

カスタムシステムプロンプトをプレーンな文字列として渡します — 外部トークン化は不要:

let response = model.respond(
    userAudio: audio,
    voice: .NATM0,
    systemPrompt: "You enjoy having a good conversation."
)

または組み込みプリセットを使用:

CLIの使用法

音声入力から音声応答を生成します:

# Basic speech-to-speech
.build/release/speech respond --input question.wav

# Choose a voice preset
.build/release/speech respond --input question.wav --voice NATM0

# Stream audio output during generation
.build/release/speech respond --input question.wav --stream

# Custom system prompt text
.build/release/speech respond --input question.wav --system-prompt-text "You enjoy having a good conversation."

# Use a preset system prompt
.build/release/speech respond --input question.wav --system-prompt customer-service

# Get transcript alongside audio
.build/release/speech respond --input question.wav --transcript

# JSON output with metadata
.build/release/speech respond --input question.wav --json

オプション

オプション説明
--input入力音声ファイル(WAV、必須)
--voiceボイスプリセット名(例:NATM0VARF2
--system-promptシステムプロンプトプリセット:assistant、focused、customer-service、teacher
--system-prompt-textカスタムシステムプロンプトテキスト(--system-promptをオーバーライド)
--max-steps最大生成ステップ
--stream生成中に音声チャンクを出力
--compile高速生成のためにMLXコンパイル推論を使用
--transcript音声と一緒にテキストトランスクリプトを出力
--jsonメタデータ付きJSON出力

サンプリングパラメーターもオーバーライドできます:

オプションデフォルト説明
--audio-temp0.8音声トークンサンプリング温度
--audio-top-k250音声トークンtop-kサンプリング
--text-temp0.7テキストトークンサンプリング温度
--text-top-k25テキストトークンtop-kサンプリング

ストリーミング

--streamフラグはリアルタイム音声出力を有効にします。音声チャンクは生成されるにつれて出力されるため、完全な応答が完了する前に再生を開始できます。これは、低レイテンシーが重要なインタラクティブアプリケーションで特に有用です。

パフォーマンス

指標
リアルタイム係数 (RTF)約1.4(8ビット、ほぼリアルタイム)
ステップレイテンシーM2 Max上で約112 ms/ステップ(8ビット)
モデルサイズ(8ビット)約9.1 GB
ピークRAM(8ビット)約11 GB
モデルサイズ(4ビット)約4.9 GB
ピークRAM(4ビット)約7 GB
重要

PersonaPlex 7B(8ビット)は少なくとも24 GBのRAMを必要とします。4ビットバリアントは16 GBデバイスに収まりますが、劣化した出力を生成します。8 GBデバイスでは、どちらのバリアントも収まりません。サポートされているハードウェアで最高のパフォーマンスを得るには--compileを使用してください。

モデルバリアント

モデルサイズHuggingFace
PersonaPlex-7B (8ビット) 推奨9.1 GBaufklarer/PersonaPlex-7B-MLX-8bit
PersonaPlex-7B (4ビット)4.9 GBaufklarer/PersonaPlex-7B-MLX-4bit

Swift API

import PersonaPlex
import AudioCommon

let model = try await PersonaPlexModel.fromPretrained()
let response = model.respond(
    userAudio: userSamples,
    voice: .NATM0,
    systemPrompt: "You are a helpful assistant."
)
try WAVWriter.write(samples: response.audio, sampleRate: 24000, to: URL(filePath: "answer.wav"))