Open4

iOSでWhisper.cppとpyannoteの一部を実行する

sarutabikosarutabiko

次作ろうと思っているiPhoneアプリに必要な要素だったので、試しながらメモ。

  • 環境はiPhoneで動くこと
  • Whisper.cppで音声を認識させたい
  • Speech Diarizationも行いたい

Whisper.cppにはswiftuiのデモもあり使い勝手が良さそう。SwiftからCが呼び出せるらしくそれに乗っているプロジェクトがあるのでそれを使う。本当は、話者のダイアライゼーションも一緒にやって欲しかったが、"Stereo"または"英語(tiny-diarize)"でないとWhisper.cppではできない様子。

使えるモデルはsmallまでが推奨とのこと。-enがついていないファイルを選択する。

whisper.cpp以外の選択肢も検討したが、多くの場合(WhisperX等々)はiOSで動けるようになっていないものが多い。

sarutabikosarutabiko

作戦

  1. whisper.cppで音の範囲と内容を認識
  2. pyannoteのembeddingでその範囲の話者の特徴量を計算
    2.1. pyannoteの識別と同様にこれをClusteringする

実作業

whisper.cppから音の範囲を取って、wavファイルからその部分を抜き出して、embeddingに処理をかける。本当はcoreMLを使いたかったが、

  • pyannote embeddingのtorchデータ→ onnxはOK. onnx->coreMLで失敗
ModuleNotFoundError: No module named 'coremltools.converters.nnssa'

下記の問題を踏んだ
https://github.com/onnx/onnx-coreml/issues/585

コメントを信じて、CoreMLへの直接変換がよかろうと思い、

  • pyannnoteのembeddingのtorchモデル→CoreMLへの直接変換
RuntimeError: PyTorch convert function for op 'conv1d' not implemented.

に当たる。

https://github.com/apple/coremltools/pull/2011

上記のプルリクの変換を取ってきて、若干整形したものの、どうも噛み合わせが悪い。

input_shape....のエラー

coremltoolsがconv1dに対応していないせいでこれもダメ、
途中"warn op"がないよというエラーもあったが、これは無視するaliasに加えたら通過。
しかしその先も罠が多く、諦め。

  • pyannnoteのembeddingのtorchモデル→onnxでonnx runtimeで実行.

本当はこれを避けた買ったが、やむなし。。。

sarutabikosarutabiko

色々調整は必要だったが、onnxに変換したデータでは、適切にembeddingの結果をiPhone上でも得ることができた。diarization精度はいまいち.

sarutabikosarutabiko

pyannoteのembeddingのモデルをonnxに変換

import torch
import os
import onnxruntime as ort
from pyannote.audio import Model
model = Model.from_pretrained("pyannote/embedding",
                              use_auth_token="YOUR_HUGGNG_CODE_SESSION")


max_length = int(model.specifications.duration * 16000)
dummy_input = torch.zeros(32, 1, max_length)

onnx_filepath = "embedding.onnx"

torch.onnx.export(
        model,
        dummy_input,
        onnx_filepath,
        do_constant_folding=True,
        input_names=["input"],
        output_names=["output"],
        dynamic_axes={
            "input": {0: "B", 1: "C", 2: "T"},
        },
    )

so = ort.SessionOptions()
so.optimized_model_filepath = onnx_filepath
ort.InferenceSession(onnx_filepath, sess_options=so)