見出し画像

【話者分離】pyannoteをEC2にデプロイしてみた

はじめに

「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のトークン取得
https://huggingface.co/にログインし「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インスタンスの起動
AWSコンソールから「EC2」サービスへアクセス
・下図を参考にインスタンス起動

AMI:ami-0e1377c6c189e7949
インスタンスタイプ:t2.large(メモリ8GBほしいので)
ボリューム:70GiB(諸々のインストールで結構容量食う)
GPUは利用しないが「Deep Learning OSS Nvidia Driver AMI GPU PyTorch 2.3」を選択

作成したインスタンスを選択し「インスタンスを開始」

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モデルの利用環境構築に挑戦していきます!

6.参考記事


この記事が気に入ったらサポートをしてみませんか?