AIバブル:弾けたら大変、弾けなくても大変

たまたま以下の記事を読んだのですが、「AIは見かけ上の企業利益を大きくみせる」という減価償却の仕組みが面白かったので、いろいろと調べてみました。

www.financialpointer.com

  • この記事では、AIブームのなかでテック企業が競うようにGPU資産への巨額投資を実行しているにも関わらず、資本支出(CapEx, capital expenditure)の会計上の仕組みによって企業利益が一時的にかさ上げされている、と指摘している。どういうことか。

  • テック企業がデータセンター用GPUのような高額な物理資産を購入すると、その支出は会計上「資本支出」として扱われ、一度に費用計上されない。代わりに、資産として計上された後、その価値が減価償却という形で、設定された耐用年数にわたって分割して費用化される。これにより、支出が発生した期の費用は実際よりも小さく計上され、その結果、報告される利益が大きく見える。このカラクリにより、ここ1-2年で加速したテック企業によるデータセンター投資の莫大な投資負担は、足元の企業決算では大部分は影響しない。

  • 一方でテック企業によるGPU獲得競争の結果は、営業利益率70%に達するNVIDIAの膨大な企業利益としてはすでに毎期計上されている。つまりNVIDIAを含むMag7全体でみると、AIチップへの投資で発生した利益の側は現在進行形で計上されているのに、費用の側はほとんどが表面化していない。この非対称性は、数年以内にデータセンター投資がそれに見合う莫大な利益をもたらすか、でなければテック企業が多額の損失を計上することで埋め合わせるしかない。

  • 特に問題視されるのは、GPU(AIチップ)の耐用年数の設定とされる。データセンター向けGPUは高負荷で休みなく稼働するため、物理的な故障率が高く、実質的な耐用年数はわずか1〜3年と推定する向きもある。それだけでなく、NVIDIAはおおむね2年ごとにGPU製品の世代交代を行うため、AIチップはわずか数年で機能的にも時代遅れの旧世代品となる。したがってAI開発用GPUとしての価値は2年でそのほとんどが失われる。

  • しかしMicrosoft、Meta、Alphabet (Google)、Amazonなどは、依然としてサーバーやネットワーク機器の耐用年数を5年~6年に設定しているため、AI向けデータセンターの実態と乖離が起こっている。実態より長い耐用年数を設定すると、年々の償却費用がそれだけ圧縮され、利益のかさ上げが長い期間継続することになる。

  • こうした状況は、1990年代後半のドットコムバブル期に通信会社が光ファイバー網へ巨額の投資を行った状況と類似している。当時も同様の会計処理によって見かけ上の利益が押し上げられたが、実際の収益が伴わずに2000年代前半にバブルは崩壊した。

ついでに以下の記事も面白い。というのも、もしテック企業が将来の減価償却費用に耐え続けられるとしても、生成AIブームが続く限りビッグテックのビジネスモデルそのものが根本的に変質する危険がある。

https://www.reuters.com/breakingviews/capital-intensity-will-reprogram-big-tech-values-2025-05-07/

  • もともとGAFAMに代表される大手テック企業は、ソフトウェアやプラットフォームといった「資産が軽い (asset-light)」ビジネスモデルで驚異的な利益率を誇ってきた。これらのサービスは一度開発すれば、追加コストはほとんどなく無限にスケールできるためである。

  • しかしAI開発競争によって、AmazonMicrosoft、Alphabet、Metaの4社は、データセンターやNVIDIA製チップといった物理的なインフラに巨額の資本支出(Capex)を投じることを余儀なくされている。2025年のこれら4社のCapexが合計で1700億ドル(約26兆円)に達すると予測しており、これは「資産が重い (asset-heavy)」ビジネスモデルへの歴史的な転換を意味する。※2025年8月時点では今年のCapExは3000億ドル~最大4000億ドルと推定されている。

  • 電力会社や通信会社が事業を維持するために常に送電網や通信網といったインフラに巨額の投資を続けるのと同じように、ビッグテックもAIサービスを供給するためにデータセンター投資を繰り返すインフラ企業へと変質しかねない。そうなると、これまでのような高収益体質は望めなくなる。

  • 主要4社の投下資本利益率(ROIC)は、過去3年間で平均25%から15%に低下した。ROICは、事業に投じた資本に対してどれだけ効率的に利益を生み出せているかを示す指標で、その効率が落ちていることを意味する。先にふれたように巨額の設備投資は、将来的に莫大な減価償却費となって利益を圧迫し続けるだろう。

  • 投資家もいずれこの変化に気づき、ビッグテックを評価する目線が変わるのではないか。かつてのような高い株価収益率(PER)で評価されるのではなく、ゼネラル・エレクトリック(GE)のような伝統的な産業企業に近い水準まで評価が切り下がる可能性もある。

つまり、データセンターブームが終焉を迎えれば大きな資産ショックになるが、データセンター投資が常態化してインフラ化した場合もそれはそれで大いに問題がある。AIバブルが弾ければもちろんNVIDIAが悲惨なことになるが、AIバブルがいつまでも続いてしまうと、今度は他のMag7が終わらない減価償却の波に飲み込まれてビジネスモデルを壊されかねない。

しばらく前にDeepSeek創業者が「基盤AIは未来の社会インフラになる(だからオープンにして誰でも使えるようにすべき)」という言い方をして話題になっていたと思いますが、本当にインフラになったらなったで誰かが継続的に大きな投資を続けなければいけないので、そこには負担の問題が発生するということですね。

RekaQuant:RekaAIによるGGUF量子化の新手法

  • Redditにて、米国のAIベンチャーReka AIが、新たな高精度量子化手法と、それを適用したllama.cppのGGUF量子化モデルを公開したという投稿がありました。

reka.ai

  • Reka AIはもともとクローズドな商用LLMを開発していましたが、Anthropic, Google, OpenAIあたりのトップランナーにキャッチアップしていくのが難しくなったためか、最近になってMistralやCohereのように一部のモデルをオープン化することで、コミュニティとの協力を模索する方針に舵を切ったようです。
  • 現在HuggingfaceでReka Flash 3という21BクラスのLLMを公開しており、そのバージョンアップであるFlash 3.1のリリースに合わせて、量子化による精度劣化を抑制する新たな手法を提案したという経緯のようです。
  • 公開されているのは、3ビット量子化のQ3_K_Sのみですが、量子化手法自体もGithubに公開されています。

huggingface.co

  • 冒頭のブログの内容について、NotebookLMとGeminiを使って解説してもらいました。

■NotebookLMによる説明

------------------------------------------------------

Reka Quantization Technology (Reka量子化技術) について、提供された情報に基づいて解説します。

Reka 量子化技術の概要

Reka Quantization Technologyは、Reka Flash 3.1の3.5ビット量子化バージョンであるReka Flash Quantizedのリリースとともに、内部モデル量子化ライブラリのオープンソース版であるReka Quantを公開したものです。Reka Quantは、任意の量子化プリミティブと互換性があり、キャリブレーションベースのエラー削減直接的な自己蒸留を組み合わせて、低いビット幅で最先端のパフォーマンスを実現します。

量子化の主要な概念

ほとんどの量子化アプローチは、以下の2つの要素によって特徴づけられます:

  • 量子化プリミティブ (Quantization Primitive): これは、数値の最小ブロックを取り、量子化されたデータタイプでの表現にマッピングする量子化関数そのものです。簡単に言えば、数値を量子化されたバージョンに「丸める」処理を指します。これは、量子化されるデータタイプや、数値をまとめて量子化するためのグループ化戦略(例:ビットアンドバイトのNF4やllama.cppのK-Quantメソッドが使用する階層的グループ化や「スーパーブロック」)に依存します。
  • エラー削減技術 (Error Reduction Techniques): これらの技術は、ニューラルネットワークの重みを量子化プリミティブとより互換性があるように変更し、量子化後にモデルがより良いパフォーマンスを発揮するようにします。

Reka Quantのエラー削減アプローチ

Reka Quantは、上記の2つの量子化の側面を分離し、任意の量子化プリミティブと互換性を持たせています。エラー削減のために、Reka Quantは2つの強力な技術を組み合わせています:

  1. LDLQエラー削減:

    • 個々の線形層の量子化誤差を削減するために、事前に計算された活性化統計を活用します。
    • 具体的には、各重みテンソル量子化誤差を最小化することを目指します。これは、重み行列Wが元の行列、Ŵが量子化された行列である場合に、代理損失 ℓ(Ŵ) = 𝔼ₓ [‖(Ŵ – W) x‖²] を最小化することによって行われます。
    • 重みWは列ごとに量子化され、残りの未量子化部分は最初の列の量子化誤差からの線形フィードバックによって更新されます。
    • LDLQは、この線形フィードバックアプローチを採用する特定のエラー削減方法のクラスにおいて、証明可能に最適です。
    • 代理損失は特定のキャリブレーションセット上で計算および最小化されるため、LDLQは、この入力セットに対する各層でのネットワーク活性化の統計(すなわち、代理ヘッセ行列 𝔼 [x · xᵀ])を事前に計算する必要があります。
  2. フルネットワーク自己蒸留 (Full network self-distillation):

    • LDLQによる線形層レベルでの誤差削減に加えて、フルプレシジョンBF16ニューラルネットワークを使用してログットレベルでの自己蒸留を行います。
    • 量子化モデルから開始し、パフォーマンスの損失を自己蒸留によって回復しながら、テンソルを一つずつ段階的に量子化します。
    • テンソル量子化された後、その重みは固定され、残りのネットワークは通常通りトレーニングを継続します。
    • この蒸留はフルネットワークで実行されるため、アプローチが層間依存性を効果的に考慮し修正することができます。
    • LDLQは現在のモデルからの活性化統計を必要とするため、自己蒸留と組み合わせる際に技術的な問題が生じます(量子化間で重みが変更されるため、元の未量子化モデルからこれらの統計を事前に計算することは不可能になる)。この問題は、量子化の直前に統計をオンラインで計算することで解決され、GPU上の高速な分散ヘッセ行列計算を活用して計算時間を短縮します。
    • LDLQのようなキャリブレーションベースの技術は強力ですが、一度に単一のテンソルに作用し、各テンソルの重み変更によって導入される層間相互作用を考慮できません。一方、自己蒸留はネットワークレベルで量子化誤差を削減する強力な方法であり、計算量に応じてパフォーマンスが向上することが確認されています。

QAT(Quantization-Aware Training)と比較して

QATは強力なエラー削減技術ですが、各フォワードパスでネットワーク内のすべての重みを量子化および逆量子化する必要があるため、量子化技術の範囲が非常に高速でなければ実行不可能に限定されます。LDLQのようなエラー削減方法や、llama.cppのQ4_0ではなくK-QuantベースのQ4_Kのような計算コストの高い量子化データタイプは、パフォーマンスを大幅に向上させますが、実際にはQATに組み込むには遅すぎます。実験では、これらの遅い量子化アプローチによるパフォーマンスの向上が非常に大きいため、QATが数千ステップ後でも安価なデータタイプでそれらを回復できないことが判明しています。対照的に、Reka Quantの自己蒸留は量子化の間にモデルを通常通りトレーニングするため、既存の任意の量子化プリミティブに統合できます

パフォーマンス

Reka Quantは、最新の推論モデルであるFlash 3.1に適用されました。合計1800ステップのトレーニング(事前トレーニング予算の0.1%未満)で、3.5ビットへのほぼロスレス量子化を達成しました。人気のあるQ3_K_Sデータタイプに量子化した場合、ハード推論ベンチマークで平均1.6ポイントの劣化のみ、推論データで構成された検証セットでのパープレキシティは1.9%の増加にとどまりました。

これに対し、llama.cppのimatrixベースのQ3_K_S量子化ルーチンでは、パープレキシティが5%増加し、ベンチマークで平均6.7の劣化が発生しました。Reka Quantは、llama.cppの平均ベンチマーク劣化の25%未満を同じビット幅で達成しています。

自己蒸留戦略は、パフォーマンスの回復にも効果的であり、1800ステップで強力な純粋なLDLQベースラインと比較して、パープレキシティ劣化を27.7%削減し、BF16モデルに対するKLダイバージェンスを25.5%削減しました。さらに、自己蒸留の利点は、より積極的な低ビット幅量子化に対して増加し、計算量の増加とともに予測可能に改善することが実験で確認されています。

量子化されるテンソルは7つのグループに分けられ、合計1800ステップでトレーニングされました¹。リリースされたFlash 3.1のQ3_K_S量子化では、パフォーマンスの損失が最も大きいテンソルを最初に量子化するという単純なヒューリスティックに従って量子化順序が選択されています。

¹ 量子化の順序は以下の通りです:

  • グループ1: FFN up
  • グループ2: FFN gate
  • グループ3: FFN down
  • グループ4: Attn values
  • グループ5: Attn projections
  • グループ6: Attn keys, Attn values
  • グループ7: Embeddings and LM head

量子化スタックのオープンソース

量子化に関するコミュニティによるさらなる研究を支援するため、Rekaは内部量子化スタックのオープンソース版をリリースしています。このライブラリは、自己蒸留、高速LDLQのための高速分散代理ヘッセ行列計算、そしてllama.cppの人気のQ3_KおよびQ4_Kデータタイプへのエクスポートをサポートしています。コードベースはGitHubで利用可能です。

------------------------------------------------------

■よくわからないのでGeminiでQ&A

Q. 量子化の基本的な理解は、モデルの各パラメータの数値を「丸める」ことで、モデルサイズを圧縮し、推論を高速化する、というもので妥当ですか?

量子化の核心は、まさにその通りです。もう少しだけ補足して、理解を深めてみましょう。

AIモデルのパラメータ(重み)は、通常「32ビット浮動小数点数(FP32)」という非常に精度の高い数値で保存されています。これは小数点以下も細かく表現できる数値です。

量子化では、これを例えば「8ビット整数(INT8)」や「4ビット整数(INT4)」といった、表現できる数値の種類がずっと少ない形式に変換します。

  • FP32: 約43億通りの数値を表現可能(非常に滑らか)

  • INT8: 256通り(-128~127)の整数しか表現できない(カクカクした段階的)

この変換プロセスが、直感的に言う「丸める」に相当します。たくさんの数値を、限られた代表的な数値に無理やり当てはめるため、必ず誤差が生じます。この誤差がモデルの性能低下の主な原因です。

ご指摘の通り、量子化のメリットは以下の2つです。

  1. モデルサイズの圧縮

    • 1つのパラメータを保存するのに必要なデータ量が、FP32(4バイト)からINT8(1バイト)になれば、モデル全体のサイズは単純計算で4分の1になります。

    • これにより、メモリ(特にGPUのVRAM)使用量が劇的に減り、より大きなモデルを限られたハードウェアで動かせるようになります。

  2. 推論の高速化

    • データ転送の高速化: モデルが小さいため、メモリからプロセッサへのデータ移動が速くなります。これは大規模モデルにおいて非常に重要です。

    • 計算の高速化: 最新のCPUやGPUは、整数演算を浮動小数点数演算よりもはるかに高速に実行できる専用回路を持っています。そのため、計算自体が速くなります。

Rekaのブログで紹介されているような高度な技術は、この「丸める(変換する)」際に生じる性能低下という副作用を、いかに最小限に抑えるかという点に工夫を凝らしているわけです。

---

Q.「キャリブレーションベースのアプローチ」では、すでにトレーニング済みのモデルに対し、キャリブレーション用のデータセットで計算をかけ活性化統計を取得、これに基づいて量子化の処理を行います。この処理は、わかりやすく言うと、性能に大きな影響を与えうるパラメータは「小さく丸め」、性能にあまり影響を与えないパラメータを「大きく丸める」ということですか?より適切な説明がありますか?

キャリブレーションベースのアプローチは、「どのパラメータが性能に重要か」を事前に調査(キャリブレーション)し、その情報を使って、量子化(丸め処理)による悪影響が全体として最も小さくなるように、元のパラメータを微調整する手法です。

例えるなら、「決まった形の型抜き(量子化)でクッキー生地(パラメータ)を抜く前に、重要な部分が型の中にうまく収まるように、あらかじめ生地の形を少し整えておく」ようなイメージです。型抜き(丸めるルール)自体は変えませんが、生地(元の数値)を工夫することで、最終的な仕上がり(性能)を良くします。

ブログに書かれている「活性化統計(activation statistics)」が、この「事前調査」の鍵です。

  1. パラメータの重要度は単体では決まらない:
    あるパラメータ(重み)が重要かどうかは、それ自体では分かりません。そのパラメータが、実際にどのような入力データ(活性化)と掛け合わされるかによって、最終的な出力への影響度が決まります。

  2. 典型的な入力を調べる:
    そこで、キャリブレーション用のデータセット(モデルが普段目にするような典型的なデータ)をモデルに通し、各層でどのような数値が入力されてくるか(=活性化)を記録します。これが「活性化統計の取得」です。

  3. 誤差を最小化する:
    この統計情報を使うことで、「この層では、こういうパターンの入力がよく来るから、この部分の重みを量子化すると出力にこれくらい誤差が出るな」と予測できます。
    キャリブレーションベースの手法(ブログにあるLDLQなど)は、この**「予測される出力誤差」が最小になるように**、元の重みを最適化(微調整)してから量子化を行います。

まとめると以下の通りです。

  • より技術的に正確な説明:

    • 全てのパラメータは同じルール(例:4ビット)で丸められます

    • ただし、その前に「活性化統計」という情報を使って、「どのパラメータの組み合わせが、典型的な入力に対して重要か」を把握します。

    • そして、その重要な情報が丸め処理後も失われないように、丸められる前の元のパラメータの数値を、あらかじめ賢く微調整しておきます。

したがって、「影響度に応じて丸め方を変える」というよりは、**「影響度を考慮して、丸め処理をうまく乗り切れるように元の数値を準備してあげる」**というのが、より適切な説明になります。

---

Q. Reka Quantが行っている量子化処理のうち、LDLQエラー削減については「キャリブレーションベースのアプローチ」に分類できるものですか?

 

はい、その通りです。

Reka Quantが行っているLDLQエラー削減は、まさしく**「キャリブレーションベースのアプローチ」に分類される技術**です。

ブログの記述からもそれが明確に分かります。

  • 活性化統計を利用: LDLQは「precomputed activation statistics(事前に計算された活性化統計)」を利用すると書かれています。これはキャリブレーションベースのアプローチの典型的な特徴です。

  • プロキシロスを最小化: (Ŵ – W) xの誤差(プロキシロス)を最小化することを目指しており、これも学習済みの重みに対して、特定の目的関数を最適化するキャリブレーション手法の考え方と一致します。

  • レーニングは不要: LDLQ自体は、トレーニング(勾配降下法)を必要とせず、統計情報から直接計算によって重みを調整します。

したがって、Reka Quantは「キャリブレーションベースのアプローチ(LDLQ)」と、後述する「トレーニングベースのアプローチ(自己蒸留)」の要素を組み合わせた、ハイブリッドな手法であると理解できます。

 

---

Q.「自己蒸留」という表現の含意は何ですか?未量子化モデルを教師モデル、同じモデルの量子化モデルを生徒モデルとする蒸留を実行するという意味での「自己蒸留」ですか?

 

はい、「自己蒸留(self-distillation)」という表現は、まさにご指摘の通り、**「同じモデルファミリー内での蒸留」**を意味しています。

具体的には、Reka Quantの文脈における「自己蒸留」は以下の含意を持っています。

  1. 先生と生徒が同一ファミリー:

    • 先生モデル: 量子化されていない、オリジナルの高精度モデル(BF16版)。

    • 生徒モデル: 現在、部分的に量子化が進んでいるモデル。
      この「先生」と「生徒」が、異なるアーキテクチャのモデル(例: 大規模モデルから小規模モデルへ)ではなく、元は同じモデルであるため、「自己」蒸留と呼ばれます。

  2. 知識の伝達:

    • 先生モデル(高精度版)の出力(logits)を「正解ラベル」として、生徒モデル(量子化版)がその出力を真似するように学習します。これにより、単に元のデータセットから学習するよりも、高精度モデルが持つ「知識の機微」や「判断の仕方」までをも学習でき、性能低下を効果的に補うことができます。

  3. 段階的なプロセス:

    • ブログの説明にある通り、Reka Quantは一度に全てのパラメータを量子化するわけではありません。

    • テンソル(パラメータのグループ)を一つずつ量子化し、その直後に自己蒸留を行って性能を回復させ、次のテンソル量子化に進む、というプロセスを繰り返します。

この**「同じモデルを教師役に」「段階的に性能を回復させながら」**量子化を進める手法が、Reka Quantにおける「自己蒸留」の核心です。

 

---

Q. 先のLDLQは、自己蒸留のプロセスに組み込まれ、各テンソル量子化の直前に実行されるのですか?あるいは別のタイミングで実行されますか?

 

はい、LDLQは、自己蒸留のプロセスに組み込まれ、各テンソルグループの量子化が行われる直前に実行されます。

ブログの記述から、そのプロセスは以下のように推測できます。

  1. スタート: 未量子化の高精度モデル(BF16)から開始する。

  2. グループを選択: 量子化するテンソルのグループ(例: Group 1: FFN up)を決定する。

  3. キャリブレーション (LDLQの準備):

    • 現在のモデル状態で、キャリブレーションデータを流し、対象となる層の活性化統計(Hessian)をオンラインで計算する。

    • ここが重要なポイントです。前のステップの自己蒸留によってモデルの重みが変化しているため、元のモデルの統計情報を使い回すことはできず、毎回計算し直す必要があります。

  4. LDLQによる調整と量子化:

  5. 自己蒸留による性能回復:

    • 対象グループのテンソル量子化されたモデル(生徒モデル)を、元の高精度モデル(先生モデル)の出力を真似するように、短時間トレーニング(自己蒸留)する。これにより、量子化で失われた性能をモデル全体で回復させる。

  6. 次のグループへ: ステップ2に戻り、次のテンソルグループに対して同じプロセスを繰り返す。

  7. 完了: 全ての対象テンソル量子化されたら終了。

この流れにより、

  • LDLQは**各層レベル(ミクロ)**での量子化誤差を最小化し、

  • 自己蒸留は**モデル全体(マクロ)**での性能低下を補償する、
    という2つのアプローチが、各ステップで連携して機能します。

 

---

Q. LDLQや自己蒸留にどのようなデータセットを用いているかについて言及はありますか?

 

いいえ、ブログ記事内には、LDLQのキャリブレーションや自己蒸留のトレーニングに体的にどのようなデータセットを使用したかについての直接的な言及はありません。

ただし、ヒントとなる記述はいくつか存在します。

  1. Perplexity(パープレキシティ)の評価データセット:

    "a 1.9% increase in perplexity on a validation set composed of reasoning data."
    推論データで構成された検証セットにおいて、パープレキシティが1.9%増加した。)

    この記述から、性能評価、そしておそらくは自己蒸留のトレーニングにも、一般的なウェブテキストなどではなく、何らかの推論能力を要するタスクのデータが使われている可能性が高いことが示唆されます。モデルのコア能力である「推論性能」を維持することに焦点を当てていると考えられます。

  2. キャリブレーションデータ:
    キャリブレーションに使うデータセットについては全く言及がありません。しかし、一般的には、モデルの事前学習に使われたデータや、ターゲットとするタスクのデータから、多様性がありバイアスの少ないサンプルを少量(数千〜数万トークン程度)抽出して使用することが多いです。ここでも、上記の「推論データ」と同様の性質を持つデータが使われていると推測するのが自然です。

結論として、使用されたデータセットの正確な名前や構成は不明ですが、「推論タスクに関連するデータ」が中心的に用いられている可能性が高い、と記事の内容から推測できます。

 

---

■雑感

  • なかなか手間のかかりそうな印象を受けます。量子化にあたってBF16の元モデルを動かせる必要がありそうなので、21Bモデルの量子化だと40Bを大きく超えるVRAMが必要になりそうな予感です。「Reka量子化」のレポジトリはこちらです。

github.com

メモ:スマホからPCのlocalhostにアクセスし、マイクも有効にする

  • LLMとのリアルタイム音声会話を可能にするUnmute絡みのメモです。
  • Unmuteはウェブアプリなので、Docker Composeで起動した後PCのブラウザからlocalhostにアクセスすることで使用できます。ただ、せっかくリアルタイムで会話ができるので、スマートフォンを使って電話のようにAIと会話してみようと思いました。
  • 公式のデモ(https://unmute.sh/)もスマートフォンのブラウザから普通に使えたので、基本的には問題なさそうです。
  • 簡単に調べると、PCのlocalhostスマホからアクセスするために手軽なのは、WiFi経由で接続する方法のようです。

qiita.com

  • Windowsの場合、コマンドプロンプトで ipconfig を実行し、「イーサネット アダプター イーサネット」のセクションにあるIPv4 アドレス(192.168.x.xなど)を確認したうえで、スマホのブラウザから「http://192.168.x.x」にアクセスすれば表示できます。
  • PCとスマホが同じネットワークに接続していればいいので、PCが有線LANでもルーターが共有なら大丈夫です。
  • ひとつ厄介なのは、localhostはHTTPサイトなので、同じPC以外の端末からアクセスしようとすると、音声機能などがブロックされることです。
  • Geminiに尋ねると「Android端末なら、Chromeのフラグ設定で例外を許可することができる」と教えてくれました。
  1. AndroidChromeブラウザを開きます。

  2. アドレスバーに chrome://flags と入力してアクセスします。

  3. 上部の検索バーを使い unsafely-treat-insecure-origin-as-secure を探します。

  4. 見つかった設定項目を Default から Enabled に変更します。

  5. すぐ下にテキストボックスが表示されるので、そこにマイクの使用を許可したいローカルURLを入力します。
    http://<あなたのPCのIPアドレス>
    (例: http://192.168.1.10

  6. 右下に表示される「Relaunch」ボタンをタップしてChromeを再起動します。

これで、指定したHTTPのIPアドレスが、例外的に安全なサイトとして扱われるようになり、マイクが使えるようになります。

  • ということで、AndroidであればWiFi経由でlocalhostのUnmuteとおしゃべりできました。
  • この方法はChrome以外のブラウザやiPhoneChromeからだと使えないので、その場合はngrokなどのトンネリングサービスでhttpsサイトを立てる必要があるみたいです。

 

【Unmute】LLMサーバーをvLLMからllama.cppに変更する

引き続き、LLMとのリアルタイム音声会話を可能にするUnmuteについてです。

UnmuteはバックエンドのLLMサーバーとしてvLLMを使用しています。vLLMは推論サーバー向けのライブラリで、多数のユーザーリクエストの処理に強みがあります。が、個人がローカル環境でLLMを動かす分にはllama.cppがベターです。

特に量子化によるモデルサイズの圧縮ではllama.cppのGGUFフォーマットが圧倒的に利便性が高いです。

Redditのポストで、vLLM→llama.cppに切り替えるための方法が解説されていたので、とりあえず試してみました。

https://www.reddit.com/r/LocalLLaMA/comments/1lrjkx3/unmute_llamacpp_server/

1.llm_utils.pyの差し替え

ポストの説明に従い、"\unmute\llm\llm_utils.py"を以下のファイルに差し替えます。

Fix for llama-server · GitHub

よくわかりませんが、Geminiに解説させると「autoselect_model()関数によるモデル選択の縛りを無くした」「ストリーミングにかかわるAPI周りの設定を調整した」が変更点だそうです。

2.docker-compose.ymlの修正

これだけだとllama.cppとvLLMが競合してしまうので、vLLMサーバーが立ち上がらないようにGeminiに頼んでdocker-compose.ymlを修正してもらいました。

-----------

(略)

    volumes:
      - ./unmute:/app/unmute
    environment:
      # --- 変更箇所1: LLMの接続先を修正 ---
      # Dockerホストで実行されているllama.cppサーバーに向ける。
      # 'host.docker.internal' はDockerコンテナからホストマシンを指すためのDNS名。
      # ポート番号はllama.cppサーバーを起動する際のポートに合わせる。
      - KYUTAI_LLM_URL=http://host.docker.internal:8000
      - NEWSAPI_API_KEY=$NEWSAPI_API_KEY
    labels:

(略)

  # --- 変更箇所2: vLLMサービス全体をコメントアウト ---
  # llm:
  #   image: vllm/vllm-openai:v0.9.1
  #   command:

(以下略)

-----------

3.llama.cppサーバーの起動

Windowsであれば、llama.cppのパッケージをダウンロードして(NVIDIA GPU向けはwin-cuda-12.4-x64.zip)、さらに任意のGGUFモデルをHuggingface等から保存したうえで、例えばコマンドプロンプトから以下のように起動します。

cd C:\Users\USER\llama.cpp
llama-server.exe -m "C:\Users\USER\models\gemma-3-4b-it-qat-Q4_K_M.gguf" -ngl 99  -c 1024 --port 8000 --verbose

--verboseフラグは会話のログをllama.cppサーバー上で表示したい場合に使います。

なおちゃんとやるんであれば、llama.cppもDockerの内部で起動するようにすべきなんだと思いますが、今回はテストなのでDockerの外部で普通にllama.cppサーバーを起動してます。

4.Docker Composeを再起動

あらためて「docker compose up -d --build」でビルドしました。ビルドが完了すると、vLLMを除くDockerが立ち上がり、localhostにアプリが表示されます。

今のところ、vLLMを使った場合に比べてそれほど遅延が増すような印象はありません。モデルサイズがコンパクトにできるので全体として軽快に動いています。

 

【Unmute】AIのボイスとキャラクターの設定

前回の記事の続きです。とりあえずUnmuteをローカルで動かせるようになったので、キャラのカスタマイズを試したいと思い、どのファイルでどのように設定されているのかを確認しました。

ボイスの指定

各キャラクターの声とプロンプトセットは"voices.yaml"で設定されています。例えば、プリセットキャラクターの一つ、/Explanation/の設定は下記のとおり。

- name: Explanation
  good: true
  instructions:
    type: unmute_explanation
  source:
    source_type: file
    path_on_server: unmute-prod-website/ex04_narration_longform_00001.wav
    description: This voice comes from the Expresso dataset.

・good: は、音声サンプルの品質フィルタリング用のフラグですが、現状Voice Cloning機能が削除されているので特に意味はないかもしれません。

・instructions: は、キャラ付けためのプロンプトセットです。後述の"system prompt.py"に記述されています。

・ path_on_server: は、ボイスの指定です。Unmuteの公開する100種類以上の音声から選択する方式です。現状はオープンソースの会話音声データやKyutaiのスタッフのデータを使っているようです。ファイルは以下にアップされています。

huggingface.co

共通のシステムプロンプト

instructions: で指定されたプロンプトセットは"unmute\llm\system_prompt.py"に記述されています。ざっと目を通すと、全キャラクター共通のsystem_promptは以下のような構成です。

 

1. 基礎的なシステムプロンプト

ここではLLMに対しspeech-to-textでユーザーと音声会話しているという基本的な状況を説明しています。絵文字、強調表示、(笑)みたいなテキストチャット的表現の使用はここで禁止しています。

_SYSTEM_PROMPT_BASICS = """
You're in a speech conversation with a human user. Their text is being transcribed using
speech-to-text.
Your responses will be spoken out loud, so don't worry about formatting and don't use
unpronouncable characters like emojis and *.
Everything is pronounced literally, so things like "(chuckles)" won't work.
Write as a human would speak.
Respond to the user's text as if you were having a casual conversation with them.
Respond in the language the user is speaking.
"""

 

2. デフォルトの追加指示

ここでは、人間味のある会話をすること、"um", "uh", "like..."のようなフィラーが使えることなどが追加で指示されています。1.と分割している理由は不明。

_DEFAULT_ADDITIONAL_INSTRUCTIONS = """
There should be a lot of back and forth between you and the other person.
Ask follow-up questions etc.
Don't be servile. Be a good conversationalist, but don't be afraid to disagree, or be
a bit snarky if appropriate.
You can also insert filler words like "um" and "uh", "like".
As your first message, repond to the user's message with a greeting and some kind of
conversation starter.
"""

 

3. システムプロンプトのテンプレート

上述のプロンプトを包括する共通システムプロンプトの全体です。ウェブデモを前提とした指示なので、個人的に使う場合は要らない情報も多いですね。なおUnmuteの魅力的なポイントである「ユーザーの沈黙」に対する対応も末尾に記述されています。

_SYSTEM_PROMPT_TEMPLATE = """
# BASICS
{_SYSTEM_PROMPT_BASICS}

# STYLE
Be brief.
{language_instructions}. You cannot speak other languages because they're not
supported by the TTS.

This is important because it's a specific wish of the user:
{additional_instructions}

# TRANSCRIPTION ERRORS
There might be some mistakes in the transcript of the user's speech.
If what they're saying doesn't make sense, keep in mind it could be a mistake in the transcription.
If it's clearly a mistake and you can guess they meant something else that sounds similar,
prefer to guess what they meant rather than asking the user about it.
If the user's message seems to end abruptly, as if they have more to say, just answer
with a very short response prompting them to continue.

# SWITCHING BETWEEN ENGLISH AND FRENCH
The Text-to-Speech model plugged to your answer only supports English or French,
refuse to output any other language. When speaking or switching to French, or opening
to a quote in French, always use French guillemets « ». Never put a ':' before a "«".

# WHO ARE YOU
This website is unmute dot SH.
In simple terms, you're a modular AI system that can speak.
Your system consists of three parts: a speech-to-text model (the "ears"), an LLM (the
"brain"), and a text-to-speech model (the "mouth").
The LLM model is "{llm_name}", and the TTS and STT are by Kyutai, the developers of unmute dot SH.
The STT is already open-source and available on kyutai dot org,
and they will soon open-source the TTS too.

# WHO MADE YOU
Kyutai is an AI research lab based in Paris, France.
Their mission is to build and democratize artificial general intelligence through open science.

# SILENCE AND CONVERSATION END
If the user says "...", that means they haven't spoken for a while.
You can ask if they're still there, make a comment about the silence, or something
similar. If it happens several times, don't make the same kind of comment. Say something
to fill the silence, or ask a question.
If they don't answer three times, say some sort of goodbye message and end your message
with "Bye!"
"""

キャラクター個別のシステムプロンプト

"system_prompt.py"では、各キャラ固有のプロンプト指示も記述されています。Unmuteについて解説してくれるキャラクター/Explanation/の例だと以下の通り。ユーザーにUnmuteの仕組みを伝えるための指示が書かれています。

UNMUTE_EXPLANATION_INSTRUCTIONS = """
In the first message, say you're here to answer questions about Unmute,
explain that this is the system they're talking to right now.
Ask if they want a basic introduction, or if they have specific questions.

Before explaining something more technical, ask the user how much they know about things of that kind (e.g. TTS).

If there is a question to which you don't know the answer, it's ok to say you don't know.
If there is some confusion or surprise, note that you're an LLM and might make mistakes.

Here is Kyutai's statement about Unmute:
Talk to Unmute, the most modular voice AI around. Empower any text LLM with voice, instantly, by wrapping it with our new speech-to-text and text-to-speech. Any personality, any voice.
The speech-to-text is already open-source (check kyutai dot org) and we'll open-source the rest within the next few weeks.

“But what about Moshi?” Last year we unveiled Moshi, the first audio-native model. While Moshi provides unmatched latency and naturalness, it doesn't yet match the extended abilities of text models such as function-calling, stronger reasoning capabilities, and in-context learning. Unmute allows us to directly bring all of these from text to real-time voice conversations.

Unmute's speech-to-text is streaming, accurate, and includes a semantic VAD that predicts whether you've actually finished speaking or if you're just pausing mid-sentence, meaning it's low-latency but doesn't interrupt you.

The text LLM's response is passed to our TTS, conditioned on a 10s voice sample. We'll provide access to the voice cloning model in a controlled way. The TTS is also streaming *in text*, reducing the latency by starting to speak even before the full text response is generated.
The voice cloning model will not be open-sourced directly.
"""

以上を踏まえて/Explanation/というキャラは以下のように定義されています。Unmuteは英仏語対応ですが、このキャラは英語優先の指定になっています。

class UnmuteExplanationInstructions(BaseModel):
    type: Literal["unmute_explanation"] = "unmute_explanation"

    def make_system_prompt(self) -> str:
        return _SYSTEM_PROMPT_TEMPLATE.format(
            _SYSTEM_PROMPT_BASICS=_SYSTEM_PROMPT_BASICS,
            additional_instructions=UNMUTE_EXPLANATION_INSTRUCTIONS,
            language_instructions=LANGUAGE_CODE_TO_INSTRUCTIONS["en"],
            llm_name=get_readable_llm_name(),
      )

なお会話履歴(コンテキスト)の管理は、chatbot.pyで行っているようです。

ということで、プロンプト構成はけっこう複雑で長いことがわかりました。加筆修正することで扱いやすくなりそうです。

 

メモ:Docker compose で Unmute を試す

  • 前回の記事の続きになります。LLMとリアルタイム音声チャットができる「Unmute」をさっそくローカルで動かしてみました。残念ながら日本語は非対応です。

github.com

必要なもの:16GB以上のVRAMとDocker Desktop

  • 1BモデルのLLMなら16GB程度のNVIDIA GPUで動くと説明されているので、ひとまず手元のRTX 4080でトライします。
  • 実行環境には開発者が Very Easy と推奨しているDocker composeを使います。ほんとにeasyなんでしょうな?

  • Docker composeについては無知でしたが、複数のDockerを統合して動かすための枠組みだそうで、Unmuteの場合はvLLMサーバーとTTSモデル、STTモデルをそれぞれ別個のDockerで管理するようです。
  • Windows環境ではDocker Desktopが導入済みであればそのまま扱えるようです。Docker Desktopは過去にインストールしてたので手間が省けました(Docker Desktop導入のガイドはウェブ上に数多あり)。
  • あと当然ですが音声入力なので、マイク的なものも必要です。Unmuteはブラウザアプリなので、ちょっといじればスマートフォン経由での通話もできそうです。

Docker DesktopでGPUを有効にする

  • 説明には「DockerがGPUにアクセスできるようにするには、NVIDIA Container Toolkitも必要です。NVIDIA Container Toolkitが正しくインストールされていることを確認するには、「docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi」を実行してください」と書かれています。
  • 自分の環境では、たぶん以前に設定済みだったっぽく、GPUを認識できていました。このあたりはぜんぜん覚えていないので割愛します。

あとはGeminiに丸投げする

  • DockerはよくわからんのでGeminiに手順を聞きます。最近のGeminiはURL参照が有効にできるようになって便利です。UnmuteのGithubのURLを引用しながら質問しました。

  • 以下がGeminiの回答です。

-----------------------------------------------------------------

ステップ1:Hugging Faceのアクセストークン準備

UnmuteはデフォルトでHugging Face HubにあるLLM(meta-llama/Llama-3.2-1Bなど)を利用します。[1] これらを利用するには、Hugging Faceのアカウントとアクセストークンが必要です。

  1. Hugging Faceのアカウント作成: もしアカウントがなければ、Hugging Faceの公式サイトで作成してください。

  2. モデルの利用承諾: meta-llama/Llama-3.2-1B-instruct-v0.1のモデルページにアクセスし、利用規約に同意 (Accept the conditions) してください。

  3. アクセストークンの作成:

    • Hugging Faceサイト右上のプロフィールアイコンから Settings > Access Tokens に移動します。

    • New token をクリックし、Role は read に設定してトークンを作成します。

    • 作成されたトークン(hf_...で始まる文字列)をコピーして、安全な場所に控えておいてください。

ステップ2:Unmuteリポジトリのクローンと設定

次に、Unmuteのソースコードをお使いのPCにダウンロードし、先ほど取得したアクセストークンを設定します。

  1. Gitリポジトリのクローン:
    PowerShellコマンドプロンプトを開き、作業したいディレクトリに移動してから以下のコマンドを実行します。

    Generated bash
    git clone https://github.com/kyutai-labs/unmute.git
  2. ディレクトリの移動:

    Generated bash
    cd unmute
  3. 環境変数の設定:
    DockerがHugging Faceのアクセストークンを認識できるように、環境変数を設定します。WindowsPowerShellで以下のコマンドを実行してください。<あなたのトークン>の部分は、先ほどコピーしたhf_...で始まるトークンに置き換えます。

    Generated powershell
    $env:HUGGING_FACE_HUB_TOKEN="<あなたのトークン>"

    設定されたか確認するために、echo $env:HUGGING_FACE_HUB_TOKEN を実行してトークンが表示されればOKです。

ステップ3:Docker ComposeでUnmuteを起動

いよいよUnmuteを起動します。unmuteディレクトリ(docker-compose.ymlファイルがある場所)で、以下のコマンドを実行してください。

Generated bash

docker compose up --build

 

このコマンドは、必要なDockerイメージのビルドと、すべてのサービスの起動を自動で行います。[1] 初回はビルドに時間がかかる場合があります。GPUメモリの使用量に問題がある場合は、docker-compose.ymlファイル内のNOTE:コメントを参考に設定を調整する必要があるかもしれません。[1]

ビルドと起動が正常に完了すれば、Webブラウザで http://localhost/ にアクセスするとUnmuteの画面が表示されるはずです。

-----------------------------------------------------------------

  • このGeminiの説明通りに素直に実行したところ、いくつかのポイントで引っかかったので簡単にメモしておきます。

引っかかったポイント

  • まず、しょうもない点ですがGeminiが引っ張ってきたHuggingfaceのURLが違ってました。Llama-3.2-1B-Instructの正しいページはこちらです。なおライセンスの利用申請送信→承認には10分くらいかかるようです。

huggingface.co

  • あと、Docker Desktop上でTerminalを開き、Windows PowerShellから順番にコマンドを実行したのですが、ビルドの途中でエラーになりました。PowerShellWindows)とDocker(Linux)の間で改行コード関連の問題が起こるようです。
  • Geminiに難癖をつけたところ、これは典型的なトラブルであり、PowerShellよりGit Bashを使うべきでしたね、と言われました。

  • とはいえPowerShellからでも、まず「git config --global core.autocrlf input」をしておくとこの問題を回避できるそうです。

長いビルドの末、Unmuteを起動

  • それ以外は、Geminiの説明どおりですんなりと進行しました。
  • PC環境によって違うと思いますが、私の場合はビルドに30分くらいかかりました。フロントエンド(ブラウザアプリ)はすぐ立ち上がりますが、バックエンドは立ち上がりが遅くしばらく「接続できません」のままです。

  • ログに「Application startup complete.」と表示されてからもCompleteはしておらず、ttsモデルやsttモデルのセットアップがだらだら続きます。
  • 本当に全ての処理が終わった気配を察してからブラウザ画面をリロードすると、無事にUnmuteのデモとまったく同じ画面が表示されました。

  • Unmuteのデモキャラクターは、なぜかわりとクセ強なので、一番まともそうな/Explanation/あたりと話してみました。1BモデルのLLMなのでちょっと素っ気なさはありますが、なかなかの低遅延で自然に会話できます。いい感じ。
  • 外部からテックニュースを取得して教えてくれる/Dev (news)/にはニュースが取得できないと言われたので、LLMにTool Use的なことをさせるには追加の設定が必要なのかもしれません。
  • コンテナの停止と再開はUnmuteディレクトリ上で「docker compose stop / docker compose start」とコマンドすればよいようです。docker compose downしてしまうと、次にdocker compose upするときにモデルのインストールやコンパイルやらが再度必要になり、ビルド時ほどではないですが立ち上げに時間がかかります。

Unmuteの構成

  • あらためてDocker Composeの構成を見てみると、全体を統合するtraefik、フロントエンドとバックエンド、さらにバックエンドに連なるllmサーバー, ttsサーバー, sttサーバーと合計6つのDockerで構成されています。相当複雑ですね。

追記

  • Redditに以下の投稿が上がっていました。バックエンドのLLMサーバーとして、vLLMの代わりにllama.cppを使うことができたとのこと。

Unmute + Llama.cpp server

https://www.reddit.com/r/LocalLLaMA/comments/1lrjkx3/unmute_llamacpp_server/

  • 曰く、24GB VRAMにUnmuteパーツ+Mistral 24B IQ4_XS.ggufまたはGemma 3 27B IQ3_M.ggufがフィットするらしいです。
  • vLLMで使用可能なAWQなどの量子化フォーマットよりもllama.cppのGGUF量子化のほうがコンパクトなので、llama.cppに置き換えられるとLLMの選択肢がかなり増えます。

メモ:ようやく公開されたぞ Unmute

  • 5月にデモのクオリティの高さが(ごく一部で)話題になっていたLLM向け音声会話ツール「Unmute」。
  • 最初は数週間以内に公開という話でしたが、6月中に放流されたのは一部だけで、AI界隈あるあるで先延ばしされておりました。
  • が、ついにGithubで全体が公開された様子。Redditにも投稿が上がっています

github.com

sc-bakushu.hatenablog.com

Unmuteの仕組み

  • Unmuteは、任意のLLMに対し、ユーザーの発話をテキストに変換するTTS(Text-To-Speech)モデルと、LLMの生成したテキストを音声に変換するSTT(Speech-To-Text)モデルを低遅延で接続することで、ユーザーとLLMの自然な音声会話を実現するための統合システムです。

  • バックエンドのうちLLMサーバーにはvLLMを使っているので、手持ちのGPUに合わせてモデルを選択できます。STTとTTSはそれぞれKyutaiが開発したリアルタイム生成モデルを使用します。残念ながら現状は英語と仏語のみの対応です。

huggingface.co

要求スペック

  • リポジトリの説明によると、小型言語モデルのLlama-3.2-1Bを使えば16GB程度のVRAMで十分動かせる、とあります(TTSは2B、STTは1B程度のパラメータ)。
  • 以下のコメントを見ると、例えばもう少し大きめのQwen-2.5-3Bに置き換える場合、TTS/STTと合わせて20GBになるようです。さらに、Qwen3-14BのAWQ 4bitを使って24GB VRAMで4Kコンテキストまで動かせたという報告もされています。vLLMはいくつかの量子化フォーマットに対応しています。

マルチGPU対応

  • デモ並みの低遅延を実現するためにはLLM/STT/TTSを分割稼働させるマルチGPU環境が推奨されています。

複数GPUの使用

デモ版のUnmute.shでは、Speech-to-Text、Text-to-Speech、およびVLLMサーバーを別々のGPUで実行することで、シングルGPUセットアップに比べてレイテンシを改善しています。単一のL40S GPUですべてを実行した場合、TTSレイテンシは~750msでしたが、Unmute.shでは~450ms程度に減少します。

  • 3つのGPUを用意するのはちょっとハードル高いですが、上記の書き込みを見るとTTSモデルだけを2つ目のGPUに割り当てるとかも出来るようです。

実行環境

  • さすがに3モデルを同時に走らせる仕組みなのでGoogle Colabとかで手軽に試せる感じではないようで、Docker Composeが推奨されています。めんどい!

  • とにかく試しに動かしてみてから色々考えたいと思います。

Voice Cloningは非対応

  • 当初のKyutaiの説明では任意のボイスサンプルの声を再現できるVoice Cloning機能もアピールされていたのですが、これは非公開にされ、Kyutaiが提供する音声リポジトリから選択する仕様に変わった様子。

追記:ローカルで試しました

sc-bakushu.hatenablog.com