「Phonon-2」音声認識モデル:必要VRAM 4GB〜

「Phonon-2」音声認識モデル:必要VRAM 4GB〜

基本情報

項目 内容
リポジトリ FermionResearch/Phonon-2
公開元のまとめ NVIDIA のモデルとライセンスのまとめ
公開日 2026-09-28
ライセンス cc-by-4.0
配布形式 MLX
出典の種類 公開元の一次情報(HuggingFace公式モデルページが一次情報)

情報を集めた時点で、当サイトのコードが確定させた値です。日付はJSTで表示しています。

概要

FermionResearchは、英語の音声認識(ASR)において極めて高い精度と軽量性を両立したオープンウェイトモデル「Phonon-2」を公開しました。このモデルは、音声ファイルを入力として受け取り、句読点や大文字小文字、数値の表記を適切に含んだテキストを出力するSpeech-to-Textモデルです。

Phonon-2は、NVIDIAの「nvidia/parakeet-tdt-0.6b-v3」をベースモデルとして採用し、独自の量子化技術を施すことで、900 MB以下のオープンな英語音声認識モデルの中で最も正確であると報告されています。約2.5 GBあるフル精度の教師モデルと比較して、ダウンロードサイズを15倍縮小しながらも、同等の精度を維持している点が大きな特徴です。

スペック

資料に基づいたPhonon-2およびそのベースモデルの主要なスペックは以下の通りです。

  • パラメータ数: 0.6B(6億パラメータ)
  • アーキテクチャ: parakeet_tdt_five_value(NVIDIAのFastConformer-TDTをベースとした構造)
  • 量子化手法: Quantization-Aware Training(QAT)により、エンコーダーの各重みを5つの学習済みレベル(約2.1ビット相当)に保持
  • 入力仕様: 16kHzのモノラルオーディオ(.wavおよび.flac形式に対応)
  • 出力仕様: 句読点、大文字小文字、数値の表記を含むテキスト。タイムスタンプ(単語レベルおよびセグメントレベル)の出力も可能
  • 推論速度(報告値):
    • M5 MacBook Air:1時間の音声を約20秒で処理(リアルタイム比174倍) – Zen 5コア(16 vCPU):リアルタイム比143倍 – H100(バッチサイズ128):リアルタイム比6,680倍
  • ライセンス: CC-BY-4.0(商用・非商用を問わず利用可能。ただし、NOTICEファイルに記載された変更点のリストを確認する必要があります)

性能・品質

公開元であるFermionResearchは、Open ASR Leaderboardのコードを使用したベンチマーク結果を公表しています。以下の表は、Phonon-2と、その教師モデルを含む主要なモデルとのWER(単語誤り率)を比較したものです。

→ 横にスクロールできます

Model Download LS clean LS other AMI Earnings-22 GigaSpeech SPGISpeech VoxPopuli Average
Phonon-2 164 MB 1.72 3.92 9.37 6.96 8.35 3.70 2.46 5.21
Parakeet TDT 0.6B v3, teacher† 2,508 MB 1.52 3.13 9.42 5.85 7.99 3.63 3.19 4.96
Parakeet Redux 178 MB 1.94 4.35 9.16 7.90 8.62 4.01 3.87 5.69
Phonon-1 415 MB 2.11 5.03 10.31 12.34 8.73 3.67 3.73 6.56
Canary 180M Flash† 737 MB 1.52 3.42 12.09 8.33 8.87 2.04 3.57 5.69
Voxtral Mini 4B Realtime† ≈8,000 MB* 1.62 4.94 13.34 9.31 8.80 2.23 2.60 6.12
Whisper large-v3-turbo† 1,618 MB 2.13 3.71 13.88 8.09 8.47 2.79 7.02 6.58
Nemotron 3.5 ASR Streaming 0.6B† 2,368 MB 2.83 6.79 13.43 15.30 9.86 3.27 4.24 7.96

このベンチマークにおいて、Phonon-2は平均WER 5.21%を記録しており、Whisper large-v3-turboやVoxtral Mini 4Bといった、ファイルサイズが数倍から数十倍大きいモデルを上回る精度を示しています。特にVoxPopuliセットにおいては、教師モデルであるParakeet TDT 0.6B v3(3.19%)を上回る2.46%という最も優れたスコアを達成しています。

一方で、LibriSpeech(LS clean/other)やEarnings-22といった一部のデータセットでは、フル精度の教師モデルには及ばない結果となっています。しかし、モデルサイズが164 MBと極めて軽量であることを考慮すると、オンデバイスでの運用において非常に高い投資対効果を持つモデルであると言えます。

ベースモデルである nvidia/parakeet-tdt-0.6b-v3 の特性として、ノイズ耐性の高さも挙げられています。元モデルの評価では、SNR 10からSNR 0といった厳しいノイズ環境下でも、一定の認識精度を維持できることが示されています。Phonon-2はこの優れたアーキテクチャを継承しつつ、極限まで軽量化されたモデルです。

得意なこと・想定用途

Phonon-2は、リソースが限られたオンデバイス環境やエッジデバイスにおいて、高品質な英語の文字起こしを高速に実行する用途に特化しています。Mac向けのディクテーションアプリである「Detta」の内部エンジンとして採用されている実績があり、個人のデスクトップ環境における音声入力やリアルタイム書き起こしに最適化されています。

本モデルは、会議や対話の書き起こしにおいて特に高い適性を発揮します。ベンチマーク結果にも示されている通り、会議音声を扱うAMIデータセットや議会演説を扱うVoxPopuliデータセットにおいて、フル精度の教師モデルに匹敵あるいはそれを上回る認識精度を記録しています。そのため、ビジネスミーティングの議事録作成、講演や講義のテキスト化、インタビューの文字起こしといった実務用途に十分対応できます。

ベースモデルである「parakeet-tdt-0.6b-v3」が備える仕様を継承しており、出力テキストには文脈に応じた適切な句読点(ピリオドやカンマ)、大文字と小文字の使い分け、数値表現が最初から含まれます。一般的な音声認識モデルで必要となる後処理(句読点の復元やフォーマット整形)を別途行わずにそのまま自然なテキストとして利用できるため、字幕生成パイプラインや会話型AI、音声アシスタントの入力フロントエンドとしても扱いやすい構成となっています。

また、単語レベルやセグメントレベルでのタイムスタンプ出力にも対応しているため、動画コンテンツへの自動テロップ付けや、音声検索インデックスの作成、長尺オーディオの編集作業支援といった用途にも適しています。高い推論スループットを備えていることから、手元のノートPCでの日常的なディクテーションだけでなく、サーバー環境でのバッチ処理による大量の音声ファイル高速処理まで幅広く活用できます。

動作環境

動作環境の目安(Local Model Watch 算出) — パラメータ数 627M(元モデル nvidia/parakeet-tdt-0.6b-v3 の値)

手持ちのVRAM 選べる量子化 ファイルサイズ 必要メモリの目安
4GB(ノートPCの内蔵GPU・スマートフォンなど) Q8_0 0.7GB 0.8GB

推論エンジンの対応状況(各プロジェクトのソースにあるモデル登録表とアーキテクチャ名を当サイトが機械的に照合。2026-10-01 時点): llama.cpp: 未登録、vLLM: 未登録、MLX (mlx-lm): 未登録。「未登録」はその時点の登録表に名前が無いという意味で、動かないことの断定ではありません。

必要メモリは配布ファイルの実サイズに実行時のオーバーヘッド(KVキャッシュ等)を20%見込んだ概算で、文脈長・バッチサイズ・推論エンジンによって増減します。公開元の公称値ではなく、当サイトがファイルサイズから機械的に算出した値です。 他のモデルとの比較はVRAM別の早見表を参照してください。 量子化の名前の読み方は用語集にあります。

手元で動かせるか

公開元の配布形式は MLX です。

ライセンス cc-by-4.0(商用利用可): 商用利用が可能ですが、クレジット表示が義務です(表示を欠くと違反になります)。

量子化の圧縮率: Q8_0 は実測 9.59 bit/weight で、元の16bitの重みの約60%のサイズです(配布ファイルの実サイズから当サイトが算出)。

配布形式とライセンス表記から当サイトのコードが組み立てた判定です。ライセンスの要約は法的助言ではないため、実際の利用にあたっては公開元の原文を確認してください。

当サイトでの実測

当サイトのサーバー(GPUなし)で、このモデルのファイルを実際に読み込み・動かして確かめた値です。モデルカードの記載ではなく、当サイトが測った結果です。測り方と全モデルの一覧は観測データにまとめています。

当サイトが作った英語の音声の文字起こし(当サイトのCPU)

FermionResearch/Phonon-2 は、重みを独自のコンテナ形式で配布しています。配布元の Python コードは動かさず、この形式の読み取り処理を当サイトで書いて、標準の transformers の ParakeetForTDT(このモデルの土台になっている nvidia/parakeet-tdt-0.6b-v3 と同じ構造)に重みを読み込み、当サイトのサーバーの CPU で fp32 のまま動かしました。読ませた音声は他所の録音ではなく、当サイトが固定の英文3つを音声合成(en_US-ljspeech-medium・MIT(音声モデルの配布)・学習データ LJ Speech はパブリックドメイン)で読み上げて作ったもので、1つずつ1回だけ文字起こしさせました。選別や加工はしておらず、聞き間違いも含めて1回目の出力をそのまま載せています。このモデルの対応言語は英語だけなので、英語だけを試しており、ほかの言語についてはなにも測っていません。

読ませた音声(4.7秒)と、読み上げた文:

It had been raining since the morning, but it gradually cleared up in the afternoon.

モデルの文字起こし(原文のまま。単語誤り率 0.0%:15語中0語の誤り・文字起こしにかかった時間 4.6秒):

It had been raining since the morning, but it gradually cleared up in the afternoon.

読ませた音声(4.7秒)と、読み上げた文:

The next meeting will be held from 2 p.m. on March 15 in meeting room B.

モデルの文字起こし(原文のまま。単語誤り率 12.5%:16語中2語の誤り・文字起こしにかかった時間 4.63秒):

The next meeting will be held from two PM on march fifteenth in meeting room B.

読ませた音声(3.61秒)と、読み上げた文:

Oh, it’s already finished? That was much quicker than I expected.

モデルの文字起こし(原文のまま。単語誤り率 0.0%:11語中0語の誤り・文字起こしにかかった時間 4.17秒):

Oh, it's already finished. That was much quicker than I expected.
項目 結果
3つの音声を通した単語誤り率 4.8%(42語中2語の誤り)
このCPUでの速さ 実時間の1.0倍(13.0秒の音声を13.4秒で処理)

条件: CPU Neoverse-N1・3スレッド(GPUなし)・fp32・transformers 5.13.0・PyTorch 2.14.1+cpu・重みの版 429f35b9c8(設定の土台は 541d1f99c6)・貪欲デコード・2026-10-01に測定しました。最初の1回は測らずに流しています。

単語誤り率は、当サイトのコードが小文字にして句読点を除いたうえで数えています。数字の表記は揃えないので、「2 p.m.」と「two p.m.」は別の語として数えます。合成音声1種の短い3つの音声では、実際の録音・訛り・雑音での精度は分かりません。速さはこのCPUでの短い音声の値で、GPU の目安にはなりません。重みは圧縮された形式で配布されており、動かすために fp32 に展開しているので、ここでのメモリ使用量は配布ファイルの大きさではありません。

環境構築・ダウンロード・実行の手順(当サイトで実行したもの)

当サイト自身のサーバーで動かしました。重みのコンテナと土台のモデルの設定ファイルを、版を固定して Hugging Face からダウンロードし、コンテナは使う前に SHA-256 を確かめています。次のスクリプト(asr_cpu_run.py、当サイトが書いたもの。全文)は、コンテナから重みのファイル1つだけを取り出して SHA-256 を確かめ、pickle を使わずに numpy でバイト列を読み、標準の ParakeetForTDT へ名前を厳密に照合して読み込み、当サイトの音声を文字起こしします。重みは終わったら消します。入れたパッケージは次のとおりです。

# 実行環境を作る(GPU は要りません)
python3.12 -m venv asr-venv
asr-venv/bin/python -m pip install 'torch' 'transformers==5.13.0' 'numpy' 'zstandard' 'librosa'
"""
独自形式の重み(Phonon-2 の fermion-five-value-parakeet-v1)を、**当サイトが書いた読み取り処理**で標準の transformers の
ParakeetForTDT に読ませて、CPU で文字起こしする(lmw/lab/asr_cpu.py から、専用の venv の Python で呼ばれる)。
配布元の Python ファイル(fermion_container.py・reference_transformers.py)は読み込まない・実行しない。
重みは pickle を使わず、バイト列を numpy で読む。記事の手順にこのファイルの全文が載る。

    python asr_cpu_run.py <job.json> <out.json>
"""
import hashlib
import json
import os
import platform
import sys
import tarfile
import time
import wave
from datetime import datetime, timezone

import numpy as np

MAX_INNER_BYTES = 1024 ** 3

def sha256_of(path: str) -> str:
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for chunk in iter(lambda: f.read(1 << 20), b""):
            h.update(chunk)
    return h.hexdigest()

def extract_inner(archive: str, inner: str, dest: str) -> str:
    """tar.zst から、名前が inner の通常のファイル1つだけを取り出す(リンク・ほかのファイルは読まない)。"""
    import zstandard
    with open(archive, "rb") as raw, zstandard.ZstdDecompressor().stream_reader(raw) as stream:
        with tarfile.open(fileobj=stream, mode="r|") as tar:
            for member in tar:
                if member.isfile() and os.path.basename(member.name) == inner:
                    if member.size > MAX_INNER_BYTES:
                        raise ValueError("展開後のファイルが大きすぎます")
                    path = os.path.join(dest, inner)
                    with open(path, "wb") as f:
                        f.write(tar.extractfile(member).read())
                    return path
    raise ValueError(f"アーカイブに {inner} がありません")

def _trits(buf: bytes, rows: int, cols: int) -> np.ndarray:
    """1バイトに3値(0〜2)を5つ詰めた符号を、(rows, cols) の 0/1/2 に戻す。"""
    row_bytes = (cols + 4) // 5
    x = np.frombuffer(buf, dtype=np.uint8, count=rows * row_bytes).reshape(rows, row_bytes).astype(np.uint16)
    out = np.empty((rows, row_bytes, 5), dtype=np.uint8)
    for k in range(5):
        out[:, :, k] = (x // (3 ** k)) % 3
    return out.reshape(rows, row_bytes * 5)[:, :cols]

def five_value(blob: bytes, shape: tuple) -> np.ndarray:
    """符号(-1/0/+1)と、行ごとの2つの大きさ(lo/hi)から重みを作る。符号が0でない要素は1ビットで lo か hi を選ぶ。"""
    rows, cols = shape
    row_bytes = (cols + 4) // 5
    codes = _trits(blob[: rows * row_bytes], rows, cols)
    nonzero = codes != 1
    count = int(nonzero.sum())
    bit_bytes = (count + 7) // 8
    off = rows * row_bytes
    if off + bit_bytes + 4 * rows != len(blob):
        raise ValueError("five_value の大きさが合いません")
    bits = np.unpackbits(np.frombuffer(blob[off: off + bit_bytes], dtype=np.uint8), bitorder="little")[:count].astype(bool)
    off += bit_bytes
    lo = np.frombuffer(blob[off: off + 2 * rows], dtype=np.float16)
    hi = np.frombuffer(blob[off + 2 * rows: off + 4 * rows], dtype=np.float16)
    is_hi = np.zeros((rows, cols), dtype=bool)
    is_hi[nonzero] = bits
    magnitude = np.where(is_hi, hi[:, None], lo[:, None])
    sign = codes.astype(np.int8) - 1
    return (sign.astype(np.float16) * magnitude).astype(np.float16)

def int_n(blob: bytes, shape: tuple, bits: int) -> np.ndarray:
    """行ごとの尺度(fp16)を掛ける 6bit / 8bit の整数の重み。"""
    rows = shape[0]
    total = int(np.prod(shape))
    cols = total // rows
    body, scales = blob[: -2 * rows], np.frombuffer(blob[-2 * rows:], dtype=np.float16)
    if bits == 8:
        q = np.frombuffer(body, dtype=np.int8).astype(np.int32)[:total]
    elif bits == 6:
        b = np.frombuffer(body, dtype=np.uint8).reshape(-1, 3).astype(np.uint32)
        packed = b[:, 0] | (b[:, 1] << 8) | (b[:, 2] << 16)
        q = np.stack([(packed >> s) & 0x3F for s in (0, 6, 12, 18)], axis=1).ravel()[:total].astype(np.int32) - 32
    else:
        raise ValueError(f"対応していないビット数です: {bits}")
    if q.size != total:
        raise ValueError("int の大きさが合いません")
    return (q.reshape(rows, cols).astype(np.float32) * scales.astype(np.float32)[:, None]).reshape(shape)

def read_container(path: str, fmt: str) -> dict:
    """先頭8バイトが見出しの長さ、続く JSON の index に従って、各テンソルの値を並べたファイルを読む。"""
    tensors = {}
    with open(path, "rb") as f:
        header = json.loads(f.read(int.from_bytes(f.read(8), "little")))
        if header.get("format") != fmt:
            raise ValueError(f"形式が違います: {header.get('format')}")
        for e in header["index"]:
            blob = f.read(e["b"])
            if len(blob) != e["b"]:
                raise ValueError("ファイルが途中で終わっています")
            kind, shape = e["k"], tuple(e["shape"])
            if kind == "five_value":
                tensors[e["n"] + ".weight"] = five_value(blob, shape)
            elif kind in ("int6", "int8"):
                tensors[e["n"]] = int_n(blob, shape, int(kind[3:]))
            elif kind == "fp16":
                tensors[e["n"]] = np.frombuffer(blob, dtype=np.float16).reshape(shape).copy()
            else:
                raise ValueError(f"対応していない種類です: {kind}")
        if f.read(1):
            raise ValueError("末尾に余りのバイトがあります")
    return tensors

def state_dict(tensors: dict):
    import re

    import torch
    out = {}
    for name, value in tensors.items():
        if name.endswith("num_batches_tracked"):
            count = float(np.asarray(value, dtype=np.float32).reshape(-1)[0])
            out[name] = torch.tensor(int(count) if np.isfinite(count) else 0, dtype=torch.int64)
            continue
        arr = np.ascontiguousarray(value.astype(np.float32))
        if arr.ndim == 2 and re.search(r"\.conv\.pointwise_conv[12]\.weight$", name):
            arr = arr[:, :, None]
        out[name] = torch.from_numpy(arr)
    return out

def waveform(path: str) -> np.ndarray:
    with wave.open(path, "rb") as r:
        if (r.getframerate(), r.getnchannels(), r.getsampwidth()) != (16000, 1, 2):
            raise ValueError("16kHz・モノラル・16bit の WAV ではありません")
        pcm = r.readframes(r.getnframes())
    return np.frombuffer(pcm, dtype=np.int16).astype(np.float32) / 32768.0

def installed_packages() -> list:
    from importlib import metadata
    seen = {}
    for dist in metadata.distributions():
        name = dist.metadata["Name"]
        if name and name.lower() not in seen:
            seen[name.lower()] = f"{name}=={dist.version}"
    return sorted(seen.values(), key=str.lower)

def main(job_path: str, out_path: str) -> None:
    import torch
    import transformers
    from transformers import AutoProcessor, GenerationConfig, ParakeetForTDT, ParakeetTDTConfig
    with open(job_path, encoding="utf-8") as f:
        job = json.load(f)
    os.environ["HF_HUB_OFFLINE"] = "1"
    os.environ["TRANSFORMERS_OFFLINE"] = "1"
    torch.set_num_threads(job["threads"])
    t0 = time.time()
    record = {"transformers": transformers.__version__, "torch": torch.__version__, "dtype": "float32",
              "threads": job["threads"], "python": platform.python_version(), "packages": installed_packages(),
              "measured_at": datetime.now(timezone.utc).isoformat()}
    inner = extract_inner(job["archive"], job["inner"], job["work"])
    if sha256_of(inner) != job["inner_sha256"]:
        raise ValueError("展開したファイルの SHA-256 が固定した値と違います")
    tensors = read_container(inner, job["format"])
    model = ParakeetForTDT(ParakeetTDTConfig.from_pretrained(job["base_dir"]))
    missing, unexpected = model.load_state_dict(state_dict(tensors), strict=False)
    if missing or unexpected:
        raise ValueError(f"テンソルの名前が合いません: 不足 {list(missing)[:5]}・余り {list(unexpected)[:5]}")
    record["tensors"] = len(tensors)
    record["parameters"] = sum(p.numel() for p in model.parameters())
    model.eval()
    model.generation_config = GenerationConfig.from_pretrained(job["base_dir"])
    processor = AutoProcessor.from_pretrained(job["base_dir"])
    record["load_sec"] = round(time.time() - t0, 1)

    def decode(item: dict):
        wav = waveform(item["path"])
        started = time.time()
        inputs = processor([wav], sampling_rate=16000, return_tensors="pt", padding=True)
        with torch.no_grad():
            out = model.generate(input_features=inputs["input_features"], attention_mask=inputs.get("attention_mask"))
        text = processor.batch_decode(getattr(out, "sequences", out), skip_special_tokens=True)[0].strip()
        return text, time.time() - started, wav.size / 16000

    decode(job["inputs"][0])  # 最初の1回は初期化の時間が入るので、測らずに流す
    outputs = []
    for item in job["inputs"]:
        text, seconds, audio_seconds = decode(item)
        outputs.append({"id": item["id"], "language": item["language"], "hypothesis": text,
                        "decode_sec": round(seconds, 2), "audio_sec": round(audio_seconds, 2)})
        print(f"[asr-cpu] {item['id']}: {audio_seconds:.1f}秒の音声を {seconds:.1f}秒で文字起こし", flush=True)
    record["outputs"] = outputs
    with open(out_path, "w", encoding="utf-8") as f:
        json.dump(record, f, ensure_ascii=False)

if __name__ == "__main__":
    main(sys.argv[1], sys.argv[2])

asr-venv/bin/python asr_cpu_run.py job.json out.json で実行しました。渡した job.json は次のとおりです(実際に使った値。音声は SHA-256 で示しています)。

{
  "archive": "/tmp/lmw-asr-cpu-lcq29pwq/phonon-2.bps.tar.zst",
  "inner": "model.fermion",
  "inner_sha256": "4b6bfa3a12cc3c4e0a54f2ab3ec4ca7a842b09e5c7ecfc8e7ca0ac6cc8c11468",
  "format": "fermion-five-value-parakeet-v1",
  "work": "/tmp/lmw-asr-cpu-lcq29pwq",
  "base_dir": "/tmp/lmw-asr-cpu-lcq29pwq/base",
  "threads": 3,
  "inputs": [
    {
      "id": "weather",
      "language": "en",
      "wav_sha256": "1258dcd9f83234db2601a928bd8facddc1c0c2751d7a90765375cc9197dc0651"
    },
    {
      "id": "numbers",
      "language": "en",
      "wav_sha256": "ce0b8d12768dd1d9f5fdbf5fd0a0a98c35b5f5b7c522b814c5da01579812f430"
    },
    {
      "id": "surprise",
      "language": "en",
      "wav_sha256": "fcd7c8d3f8cce918a56d959071a298d3a994d29c78586a2868b2a0a0c7c56e40"
    }
  ]
}
ダウンロードしたファイル(SHA-256)
98125795b6dda72f5c6eee9ba33d19815df65dcb18b50a357bf9f73c9935309e  phonon-2.bps.tar.zst None  None 4b6bfa3a12cc3c4e0a54f2ab3ec4ca7a842b09e5c7ecfc8e7ca0ac6cc8c11468  model.fermion
実行環境に入っていたパッケージの版(全文)
annotated-doc==0.0.5 annotated-types==0.8.0 anyio==4.15.1 certifi==2026.7.22 cffi==2.1.1 charset-normalizer==3.5.2 click==8.5.0 cloudpickle==3.1.2 decorator==5.3.1 filelock==3.32.3 fsspec==2026.7.0 h11==0.16.0 hf-xet==1.6.0 httpcore2==2.13.1 httpcore==1.0.9 httpx2==2.13.1 httpx==0.28.1 huggingface_hub==1.33.0 idna==3.20 Jinja2==3.1.6 joblib==1.6.0 lazy-loader==0.6 librosa==1.0.0 llvmlite==0.50.0 markdown-it-py==4.2.0 MarkupSafe==3.0.3 mdurl==0.1.2 mpmath==1.3.0 msgpack==1.2.3 narwhals==2.26.0 networkx==3.6.1 numba==0.68.0 numpy==2.5.3 packaging==26.3 pip==24.0 platformdirs==4.12.2 pooch==1.9.0 pycparser==3.0 pydantic==2.13.5 pydantic_core==2.46.5 Pygments==2.21.0 PyYAML==6.0.3 regex==2026.9.29 requests==2.34.2 rich==15.0.0 safetensors==0.8.0 scikit-learn==1.9.1 scipy==1.18.1 setuptools==78.1.0 shellingham==1.5.4 sniffio==1.3.1 soundfile==0.14.0 soxr==1.1.0 sympy==1.14.0 threadpoolctl==3.7.0 tokenizers==0.22.2 torch==2.14.1+cpu tqdm==4.70.1 transformers==5.13.0 truststore==0.10.4 typer==0.27.2 typing-inspection==0.4.4 typing_extensions==4.16.0 urllib3==2.8.0 zstandard==0.25.0

入手方法

Phonon-2はHugging Faceにてオープンウェイトとして公開されており、ゲート付きモデルではないため、事前の利用申請やライセンス同意手続きを行わずにダウンロードして利用できます。配布形式としては、Apple Silicon向けに最適化されたMLX対応の重みなどが提供されています。

Apple Siliconを搭載したMac環境では、公式に提供されているPythonパッケージとMLX関連ライブラリをインストールすることで、コマンドラインから直接文字起こしを実行できます。ターミナルで以下のコマンドを実行して必要な依存関係をセットアップします。

pip install fermion-research
pip install mlx mlx-audio mlx-lm soundfile scipy zstandard

インストールが完了したら、以下のいずれかのコマンドを用いて音声ファイル(.wav形式など)の書き起こしを行います。

phonon transcribe recording.wav
fermion transcribe phonon-2 recording.wav

Linux(x86-64およびArmアーキテクチャ)やWindowsのCPU環境向けには、専用の実行エンジンがGitHubリポジトリ(github.com/fermionresearch/phonon)にて公開されています。また、環境構築を簡略化したい場合やGPUアクセラレーションを利用したい開発者向けに、公式のDockerイメージも提供されています。

CPU環境でDockerコンテナを実行する場合は、以下のコマンドを使用します。

docker run --rm -v "$PWD":/audio -v phonon-cache:/home/phonon/.cache ghcr.io/fermionresearch/phonon-cpu:2.0.3 transcribe phonon-2 /audio/recording.wav

NVIDIA GPUを搭載したCUDA環境で実行する場合は、以下の通りGPUオプションを指定してコンテナを起動します。

docker run --rm --gpus all -v "$PWD":/audio -v phonon-cache:/home/phonon/.cache ghcr.io/fermionresearch/phonon-cuda:1.0.4 transcribe phonon-2 /audio/recording.wav

ライセンス面について、モデルの重み自体はベースモデルと同じ「CC-BY-4.0」の下で公開されており、変更点についてはリポジトリ内のNOTICEファイルに記載されています。また、提供されているコマンドラインツールおよびリポジトリ内のコードは「Apache 2.0」ライセンスが適用されています。

同じ用途の既報モデル

当サイトが取り上げた音声のモデルを新しい順に並べています。用途は配布元がHugging Faceに付けたタスク(pipeline_tag)から機械的に分けたもので、最小のVRAM階層は当サイトの概算です。

音声のモデルをすべて見る →

次に読むなら

出典

更新履歴

  • 2026-10-01: 当サイトでの実測(当サイトが作った英語の音声の文字起こし)を追加しました。