アーキテクチャ概要(全体像)
関連ソースファイル
このページの内容は以下のソースファイルに基づいて生成されています:
- vibevoice/modular/modeling_vibevoice.py
- vibevoice/modular/configuration_vibevoice.py
- vibevoice/modular/modular_vibevoice_diffusion_head.py
- vibevoice/modular/modular_vibevoice_tokenizer.py
- vibevoice/configs/qwen2.5_7b_32k.json
- Figures/VibeVoice_ASR_archi.png
- vibevoice/modular/modeling_vibevoice_streaming.py
- vibevoice/modular/modular_vibevoice_text_tokenizer.py
- vibevoice/modular/modeling_vibevoice_streaming_inference.py
- vibevoice/modular/init.py
- demo/web/app.py
- pyproject.toml
- vllm_plugin/model.py
- vibevoice/init.py
- vllm_plugin/inputs.py
- vllm_plugin/init.py
- demo/vibevoice_realtime_demo.py
- finetuning-asr/lora_finetune.py
- finetuning-asr/inference_lora.py
- demo/vibevoice_asr_gradio_demo.py
VibeVoiceは、Microsoftによって開発された音声生成・認識のためのオープンソースプロジェクトである。本プロジェクトは、大規模言語モデル(LLM)をバックボーンとし、音声トークナイザーと拡散モデルを組み合わせることで、テキストから音声への変換(TTS)や音声認識(ASR)などのタスクを実現する。アーキテクチャはモジュラー設計を採用しており、各コンポーネントが明確な責任境界を持つ。
全体アーキテクチャの構成要素
VibeVoiceのアーキテクチャは、主に4つのコアコンポーネントで構成される:LLMバックボーン(Qwen2.5ベース)、Speech Tokenizer(Acoustic & Semantic)、Diffusion Head、そしてText Tokenizerである。これらのコンポーネントは疎結合されており、設定ファイルを通じて柔軟に構成可能である。
正在加载图表渲染器...
アーキテクチャ図の解説:
- 入力層:テキストはText Tokenizer(Qwen2ベース)によりトークン化され、音声はSpeech Tokenizerにより特徴量ベクトルに変換される
- Speech Connector:音声特徴量の次元をLLMの隠れ層サイズ(3584次元)に合わせるための変換モジュール(modeling_vibevoice.py:59-70)
- LLMバックボーン:Qwen2.5-7Bをベースとし、32Kコンテキスト長をサポート(qwen2.5_7b_32k.json:49-64)
- Diffusion Head:LLMの隠れ状態から音声波形を生成する拡散モデルベースのデコーダ
モジュールのエントリーポイントは vibevoice/modular/init.py:1-14 で定義されており、主要クラス(Model, Config, Inference, Streamer)の依存関係が明示されている。具体的なモデル構成パラメータは qwen2.5_7b_32k.json:39-78 に記載されている。
Speech Tokenizer (Acoustic Semantic)
Speech Tokenizerは、音声信号を離散的なトークン表現に変換するエンコーダーである。VibeVoiceでは、音響的特徴と意味的特徴を別々に抽出する2種類のTokenizerを採用している。
Acoustic Tokenizer
Acoustic Tokenizerは、音声の音響的特性(ピッチ、音色、韻律など)を捉えるためのVAEベースのエンコーダーである。設定は configuration_vibevoice.py:31-91 で定義されている。
主要な設定パラメータ:
| パラメータ | デフォルト値 | 説明 |
|---|---|---|
vae_dim | 64 | VAEの潜在空間次元 |
encoder_ratios | [8,5,5,4,2,2] | エンコーダーのダウンサンプリング比率 |
encoder_depths | "3-3-3-3-3-3-8" | 各エンコーダーレイヤーの深さ |
std_dist_type | 'gaussian' | 潜在分布のタイプ |
causal | True | 因果的畳み込みの使用 |
Semantic Tokenizer
Semantic Tokenizerは、音声の意味的コンテンツ(話される言葉の内容)を抽出する。設定は configuration_vibevoice.py:94-145 で定義されている。Acoustic Tokenizerとの主な違いは、fix_stdが0に設定され、std_dist_typeが'none'である点である。
正規化層の実装
Tokenizer内部では、畳み込みフレンドリーな正規化層が使用される。 modular_vibevoice_tokenizer.py:38-90 では、ConvLayerNormとConvRMSNormの2種類が実装されている:
python1class ConvRMSNorm(RMSNorm): 2 def forward(self, x): 3 x = x.transpose(1, 2) # b ... t -> b t ... 4 if (not APEX_AVAILABLE) or (not self.elementwise_affine): 5 output = self._norm(x.float()).type_as(x) 6 if self.weight is not None: 7 output = output * self.weight 8 else: 9 output = fused_rms_norm_affine(x, self.weight, self.weight.shape, self.eps) 10 output = output.transpose(1, 2) # b t ... -> b ... t 11 return output
この実装では、APEXが利用可能な場合に融合RMS正規化を使用し、そうでない場合はネイティブ実装にフォールバックする。
LLM Backbone (Qwen2.5ベース)
VibeVoiceは、Qwen2.5-7Bを言語モデルのバックボーンとして採用している。この選択により、32Kトークンのコンテキスト長と多言語対応が可能になっている。
Speech Connector
Speech Connectorは、Speech Tokenizerからの出力(64次元)をLLMの隠れ層サイズ(3584次元)に変換するアダプターモジュールである。実装は modeling_vibevoice.py:59-70 にある:
python1class SpeechConnector(nn.Module): 2 def __init__(self, input_dim, output_dim): 3 super().__init__() 4 self.fc1 = nn.Linear(input_dim, output_dim) 5 self.norm = LlamaRMSNorm(output_dim, eps=1e-6) 6 self.fc2 = nn.Linear(output_dim, output_dim) 7 8 def forward(self, features, **kwargs): 9 x = self.fc1(features) 10 x = self.norm(x) 11 x = self.fc2(x) 12 return x
ストリーミング版でも同様の構造が modeling_vibevoice_streaming.py:44-55 で再定義されている。
Text Tokenizer
テキスト処理には、Qwen2Tokenizerをベースとしたカスタムトークナイザーを使用する。 modular_vibevoice_text_tokenizer.py:12-109 では、音声生成用の特殊トークンが追加されている:
python1def _add_vibevoice_special_tokens(self): 2 """Add VibeVoice-specific special tokens.""" 3 special_tokens = { 4 "additional_special_tokens": [ 5 "<|vision_start|>", # Speech start (reusing vision tokens) 6 "<|vision_end|>", # Speech end 7 "<|vision_pad|>", # Speech diffusion pad 8 ] 9 } 10 num_added = self.add_special_tokens(special_tokens)
ASR(音声認識)用のトークナイザーでは、異なる特殊トークンセット(<|object_ref_start|>, <|object_ref_end|>, <|box_start|>)が使用される(modular_vibevoice_text_tokenizer.py:264-283)。
Diffusion Head (音声生成)
Diffusion Headは、LLMの隠れ状態から音声波形を生成する拡散モデルベースのデコーダである。DDPM(Denoising Diffusion Probabilistic Models)を使用し、v-prediction方式を採用している。
正規化層
Diffusion Head内では、RMSNormが使用される。 modular_vibevoice_diffusion_head.py:20-41 の実装:
python1class RMSNorm(nn.Module): 2 def __init__(self, dim: int, eps: float = 1e-6, elementwise_affine=True, memory_efficient=False): 3 super().__init__() 4 self.dim = dim 5 self.eps = eps 6 self.elementwise_affine = elementwise_affine 7 if self.elementwise_affine: 8 self.weight = nn.Parameter(torch.ones(dim)) 9 10 def _norm(self, x): 11 return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps) 12 13 def forward(self, x): 14 output = self._norm(x.float()).type_as(x) 15 if self.weight is not None: 16 output = output * self.weight 17 return output
タイムステップ埋め込み
拡散プロセスのタイムステップを埋め込みベクトルに変換するために、サイン・コサイン埋め込みが使用される。 modular_vibevoice_diffusion_head.py:48-93:
python1class TimestepEmbedder(nn.Module): 2 def __init__(self, hidden_size, frequency_embedding_size=256): 3 super().__init__() 4 self.mlp = nn.Sequential( 5 nn.Linear(frequency_embedding_size, hidden_size, bias=False), 6 ACT2FN['silu'], 7 nn.Linear(hidden_size, hidden_size, bias=False), 8 ) 9 10 @staticmethod 11 def timestep_embedding(t, dim, max_period=10000): 12 half = dim // 2 13 freqs = torch.exp( 14 -math.log(max_period) * torch.arange(start=0, end=half, dtype=torch.float32) / half 15 ).to(t.device) 16 args = t[:, None].float() * freqs[None] 17 embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1) 18 return embedding.to(t.dtype)
Diffusion Head設定
qwen2.5_7b_32k.json:66-78 から、主要な設定パラメータを確認できる:
| パラメータ | 値 | 説明 |
|---|---|---|
ddpm_num_steps | 1000 | 拡散ステップ数(学習時) |
ddpm_num_inference_steps | 20 | 推論時のステップ数 |
ddpm_beta_schedule | "cosine" | ノイズスケジュール |
prediction_type | "v_prediction" | 予測タイプ |
head_layers | 4 | ヘッドのレイヤー数 |
latent_size | 64 | 潜在ベクトルサイズ |
データフローと出力形式
VibeVoiceのデータフローは、入力から出力まで一貫したテンソルフローとして設計されている。
出力データ構造
modeling_vibevoice.py:34-57 では、2種類の出力構造が定義されている:
python1class VibeVoiceCausalLMOutputWithPast(ModelOutput): 2 loss: Optional[torch.FloatTensor] = None 3 diffusion_loss: Optional[torch.FloatTensor] = None 4 speech_token_num: Optional[int] = None 5 logits: torch.FloatTensor = None 6 past_key_values: Optional[Tuple[Tuple[torch.FloatTensor]]] = None 7 hidden_states: Optional[Tuple[torch.FloatTensor, ...]] = None 8 attentions: Optional[Tuple[torch.FloatTensor, ...]] = None 9 10class VibeVoiceGenerationOutput(ModelOutput): 11 sequences: torch.LongTensor = None 12 speech_outputs: Optional[List[torch.FloatTensor]] = None
ストリーミング推論のキャッシュ管理
ストリーミング推論時は、KVキャッシュの効率的な管理が重要である。 modeling_vibevoice_streaming_inference.py:38-138 では、transformers 4.57以降との互換性を確保するためのMockCacheLayerが実装されている:
python1class MockCacheLayer: 2 def __init__(self, key_cache, value_cache, parent_cache=None, layer_idx=0): 3 self.key_cache = key_cache 4 self.value_cache = value_cache 5 self._parent_cache = parent_cache 6 self._layer_idx = layer_idx 7 8 def update(self, key_states, value_states, cache_kwargs=None): 9 if self._parent_cache is None: 10 return self.key_cache, self.value_cache 11 12 parent = self._parent_cache 13 idx = self._layer_idx 14 15 if parent.key_cache[idx] is not None: 16 parent.key_cache[idx] = torch.cat([parent.key_cache[idx], key_states], dim=2) 17 parent.value_cache[idx] = torch.cat([parent.value_cache[idx], value_states], dim=2) 18 else: 19 parent.key_cache[idx] = key_states 20 parent.value_cache[idx] = value_states
エンドツーエンドのデータフロー
正在加载图表渲染器...
データフローの解説:
- テキスト処理:入力テキストはText Tokenizerによりトークン化され、トークンID列に変換される
- 音声処理:参照音声(話者クローン用)はSpeech Tokenizerにより64次元の特徴量ベクトルに変換される
- 次元調整:Speech Connectorが音声特徴量をLLMの隠れ層サイズ(3584次元)に拡張する
- LLM推論:Qwen2.5がテキストと音声コンテキストを統合的に処理し、次トークンの隠れ状態を生成
- 音声生成:Diffusion Headが隠れ状態から20ステップの拡散逆プロセスで音声波形を生成
モジュール依存関係
VibeVoiceのモジュール依存関係は、明確な階層構造を持つ。
正在加载图表渲染器...
依存関係のポイント:
- 設定層:全てのコンポーネントは設定クラスに依存し、設定クラスはJSONファイルからパラメータを読み込む
- コンポーネント層:各コンポーネントは独立してテスト可能
- モデル層:コンポーネントを組み合わせて完全なモデルを構成
- 推論層:モデル層の上に構築され、ストリーミングやバッチ推論を最適化
技術選定と設計判断
VibeVoiceのアーキテクチャにおける主要な技術選定とその理由を以下の表にまとめる。
| 技術 | 用途 | 選定理由 | 代替案 |
|---|---|---|---|
| Qwen2.5-7B | LLMバックボーン | 32Kコンテキスト、多言語対応、効率的な推論 | Llama 3, Mistral |
| VAE | Speech Tokenizer | 潜在空間での滑らかな補間、再構成品質 | VQ-VAE, Wav2Vec |
| DDPM | 音声生成 | 高品質な生成、安定した学習 | Flow Matching, GAN |
| v-prediction | 拡散予測タイプ | 数値安定性、高速収束 | epsilon-prediction |
| Cosine Schedule | ノイズスケジュール | 滑らかなノイズ除去、高周波成分の保持 | Linear Schedule |
| RMSNorm | 正規化 | 計算効率、LayerNormと同等の性能 | LayerNorm |
| BFloat16 | 精度 | メモリ効率と数値安定性のバランス | Float16, Float32 |
| 24kHz | サンプリングレート | 音声品質と計算コストのバランス | 16kHz, 48kHz |
設計上の制約とトレードオフ
- メモリ使用量:7BパラメータのLLMと拡散モデルの組み合わせにより、GPUメモリ要件が高い(最低16GB推奨)
- レイテンシ:拡散モデルの20ステップ推論は、リアルタイム性を損なう可能性がある
- 特殊トークンの再利用:
<|vision_start|>などのトークンを音声用に再利用しており、将来的な拡張で競合する可能性がある
起動フローと初期化
VibeVoiceの初期化プロセスは、設定の読み込みからモデルのロードまで段階的に行われる。
Webアプリケーションの起動フロー
demo/web/app.py:41-67 から、StreamingTTSServiceの初期化フローを確認できる:
python1class StreamingTTSService: 2 def __init__( 3 self, 4 model_path: str, 5 device: str = "cuda", 6 inference_steps: int = 5, 7 ) -> None: 8 self.model_path = model_path 9 self.inference_steps = inference_steps 10 self.sample_rate = SAMPLE_RATE # 24_000 11 12 self.processor: Optional[VibeVoiceStreamingProcessor] = None 13 self.model: Optional[VibeVoiceStreamingForConditionalGenerationInference] = None 14 self.voice_presets: Dict[str, Path] = {} 15 16 if device == "mps" and not torch.backends.mps.is_available(): 17 print("Warning: MPS not available. Falling back to CPU.") 18 device = "cpu" 19 self.device = device
設定の読み込み
設定ファイル(JSON)からモデル構成が読み込まれる。 qwen2.5_7b_32k.json:39-78 には、Acoustic Tokenizer、Decoder、Diffusion Headの3つのセクションが含まれている。設定クラスは configuration_vibevoice.py:14-28 で定義される_convert_dtype_to_string関数を通じて、torch.dtypeを文字列表現に変換し、JSONシリアライゼーション問題を回避している。
