はじめに
「pyannote」を利用して、音声ファイルの話者分離できる環境を作ります。実際の文字起こしは「whisper」を利用します。
AWS環境にpyannoteの実行環境を構築するのに非常に苦戦したため、備忘録として記載します。
使用技術
話者分離:pyannote/speaker-diarization-3.0
文字起こし:whisper-1 (openAIのAPI利用)
実行環境サーバー:AWS EC2
前提条件
・openAIのAPIアクセストークンが取得済みであること。
・HuggingFaceのアカウントが取得済みであること
目次
1.事前準備
2.環境構築
3.ソースのデプロイ
4.コード実行
5.まとめ
それでは、実際の環境構築に進んでいきましょう!
1.事前準備
HaggingFaceのトークン取得
- huggingfaceにログインし「Setting」->「AccessTokens」にアクセス
- 「New token」ボタンからアクセストークンを追加し取得(あとから参照不可のためこのタイミングでメモしておく)
- 権限は「READ」でOK
利用モデルの利用規約を許諾する
「pyannote/speaker-diarization-3.0」モデルのページから抜粋
「2.」「3.」の手順を実施する
- 「pyannote/segmentation-3.0」のページへアクセスし、ユーザー利用条件の受け入れ(Accept)を実施
- 「pyannote/speaker-diarization-3.0」のページへアクセスし、ユーザー利用条件の受け入れ(Accept)を実施
2.環境構築
EC2インスタンスの起動
- AMI:GPUは利用しないが「Deep Learning OSS Nvidia Driver AMI GPU PyTorch 2.3」を選択
- インスタンスタイプ:t2.large(メモリ8GBほしいので)
- ボリューム:70GiB(諸々のインストールで結構容量食う)
作成したインスタンスを選択し「インスタンスを開始」
SSHクライアントからインスタンスへ接続し下記のコマンドを実行
# Anacondaのインストール(未インストールの場合)
wget https://repo.anaconda.com/archive/Anaconda3-2023.09-0-Linux-x86_64.sh
bash Anaconda3-2023.09-0-Linux-x86_64.sh
# Condaの初期化
conda init
source ~/.bashrc
「environment.yaml」「requirements.txt」のアップロード
- FTPクライアントなどでインスタンスに接続し、
「environment.yaml」「requirements.txt」を、任意のディレクトリに配置
name: pyannote-audio
channels:
- pytorch
- conda-forge
- defaults
dependencies:
- python=3.9
- pip
- pytorch=2.0.0
- torchaudio=2.0.0
- torchvision=0.15.0
- cudatoolkit=11.7
- pip:
- -r requirements.txt
asteroid-filterbanks >=0.4
einops >=0.6.0
huggingface_hub >= 0.13.0
lightning >= 2.0.1
omegaconf >=2.1,<3.0
pyannote.core >= 5.0.0
pyannote.database >= 5.0.1
pyannote.metrics >= 3.2
pyannote.pipeline >= 3.0.1
pytorch_metric_learning >= 2.1.0
rich >= 12.0.0
semver >= 3.0.0
soundfile >= 0.12.1
speechbrain >= 1.0.0
tensorboardX >= 2.6
torch >= 2.0.0
torch_audiomentations >= 0.11.0
torchaudio >= 2.2.0
torchmetrics >= 0.11.0
matplotlib==3.5.3
numpy==1.23.5
- 配置したディレクトリに移動
仮想環境の作成
conda env create -f environment.yaml
仮想環境を有効化
conda activate pyannote-audio
pyannote.audioのインストール
pip install pyannote.audio==3.3.1
コード実行に必要なその他のパッケージをインストール
pip install pydub flask python-dotenv polars openai tqdm onnxruntime
3.ソースのデプロイ
「app.py」と「.env」ファイルを任意のディレクトリにデプロイする
from pyannote.audio import Pipeline
from pyannote.core import Segment, notebook, Annotation
from openai import OpenAI
from pydub import AudioSegment
from dotenv import load_dotenv
from huggingface_hub import login
from tqdm import tqdm
import os
import shutil
import polars as pl
load_dotenv() # 環境変数をロード
token = os.getenv("HF_TOKEN")
file_name = "pyannote_test.wav"
if token:
# トークンを設定
login(token)
print("Successfully logged in to Hugging Face")
else:
print("HF_TOKEN environment variable not set")
print("話者分離処理_開始")
pipeline = Pipeline.from_pretrained("pyannote/speaker-diarization-3.0",
use_auth_token=token)
diarization = pipeline(file_name, num_speakers=2)
print("話者分離処理_終了")
# Annotationオブジェクトをリストに変換
diarization_list = [
{"start": segment.start, "end": segment.end, "label": track}
for segment, _, track in diarization.itertracks(yield_label=True)
]
df = pl.DataFrame(diarization_list)
audio_segment: AudioSegment = AudioSegment.from_file(file_name, format="wav")
# OpenAIクライアントを作成
client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
transcript_text = ""
# tempフォルダ内のファイルを一括削除
os.makedirs("temp", exist_ok=True)
shutil.rmtree("temp")
counter = 1 # 連番用カウンタ
# tqdmを使用して進捗バーを表示
for seg in tqdm(df.iter_rows(named=True), total=len(df)):
# pyannote.audioの結果は秒、Pydubはミリ秒で範囲を指定するので、1000倍する
start = seg["start"] * 1000
end = seg["end"] * 1000
# 開始から終了までの秒数が1秒未満の場合はスキップ
if (end - start) < 1000:
continue
audio_file = audio_segment[start:end]
# 一時ファイルに保存
temp_audio_file_path = f"temp/{counter:04d}_segment.wav"
audio_file.export(temp_audio_file_path, format="wav")
# セグメントごとに文字起こしを行う
transcription = client.audio.transcriptions.create(
model="whisper-1",
file=open(temp_audio_file_path, "rb"),
response_format="verbose_json",
timestamp_granularities=["word"]
)
transcript_text += seg["label"] + ":" + transcription.text + "\n" # 'text'属性を使ってテキストを取得
counter += 1 # カウンタをインクリメント
print("文字起こし処理_終了")
with open("transcript.txt", "w", encoding="utf-8") as f:
f.write(transcript_text)
※変数「file_name」に、ご自身の環境で利用する音声ファイルの名称を指定してください
OPENAI_API_KEY="sk-proj-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
HF_TOKEN="hf_XXXXXXXXXXXXXXXXXXXXXXX"
※"XXXX…"の部分は自身の環境で利用するAPI_KEYの値を代入してください
「app.py」の処理概要
- tokenを使ってHuggingFaceへログイン
- pyannoteを利用して音声ファイルを解析し、話者分離情報(diarization)を生成
- polarsによりDataFlameに変換・話者分離情報を繰り返し処理し、切り出した音声ファイルをwhisper(openAI API)で文字起こし
- 「transcript.txt」に話者+文字起こし内容を書き込む
4.コード実行
デプロイしたディレクトリに移動して、app.pyの実行
python app.py
いかがでしたでしょうか?話者分離&文字起こしはできたでしょうか?
こちらの手順ではGPUではなくCPUを利用する想定のため、比較的処理に時間がかかります。
1時間の音声ファイルを処理するのに、1時間~2時間ほどかかるため、ご注意ください。
5.まとめ
EC2インスタンスにAIモデルをデプロイして利用するという体験自体初めてだったため、めちゃくちゃハマりました。とにかくパッケージ依存関係のエラーが解決できずに、数日頭を抱えていました。最終的には、公式のREADMEを参照したり、Claude(Sonnet 3.5)にエラー内容を投げ込んで得られた回答を試してみたりと……久しぶりに試行錯誤しながら今回の手順にたどり着きました。
今回得た対処ポイントは下記の通り・依存関係エラーはよく観察する・パッケージのインストールごとに依存関係を解決しようとするのではなく、一通りインストールしてから最後に「pip check」で確認し、それを解決する・各パッケージの公式ドキュメントも確認してみる・AIへの質問と実施、公式情報の参照を常に行ったり来たりする
今後もいろいろなAIモデルの利用環境構築に挑戦していきます!
6.参考記事