【話者分離】pyannoteをEC2にデプロイしてみた
はじめに
「pyannote」を利用して、音声ファイルの話者分離できる環境を作ります。
実際の文字起こしは「whisper」を利用します。
AWS環境にpyannoteの実行環境を構築するのに非常に苦戦したため、備忘録として記載します。
使用技術
話者分離:pyannote/speaker-diarization-3.0
文字起こし:whisper-1 (openAIのAPI利用)
実行環境サーバー:AWS EC2
前提条件
・openAIのAPIアクセストークンが取得済みであること。
・HuggingFaceのアカウントが取得済みであること
目次
事前準備
環境構築
ソースのデプロイ
コード実行
まとめ
それでは、実際の環境構築に進んでいきましょう!
1.事前準備
HaggingFaceのトークン取得
・https://huggingface.co/にログインし「Setting」->「AccessTokens」にアクセス
・「New token」ボタンからアクセストークンを追加し取得(あとから参照不可のためこのタイミングでメモしておく)
・権限は「READ」でOK
利用モデルの利用規約を許諾する
・「pyannote/segmentation-3.0」のページへアクセスし、ユーザー利用条件の受け入れ(Accept)を実施
・「pyannote/speaker-diarization-3.0」のページへアクセスし、ユーザー利用条件の受け入れ(Accept)を実施
2.環境構築
EC2インスタンスの起動
・AWSコンソールから「EC2」サービスへアクセス
・下図を参考にインスタンス起動
作成したインスタンスを選択し「インスタンスを開始」
SSHクライアントからインスタンスへ接続し下記のコマンドを実行
Anacondaのインストール
# 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」を、任意のディレクトリに配置
・配置したディレクトリに移動
仮想環境の作成
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」ファイルを任意のディレクトリにデプロイする
app.py
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」に、ご自身の環境で利用する音声ファイルの名称を指定してください
.env
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モデルの利用環境構築に挑戦していきます!