0
0

はじめに

「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

利用モデルの利用規約を許諾する

スクリーンショット 2024-07-05 130101.png
「pyannote/speaker-diarization-3.0」モデルのページから抜粋
「2.」「3.」の手順を実施する

  • 「pyannote/segmentation-3.0」のページへアクセスし、ユーザー利用条件の受け入れ(Accept)を実施
  • 「pyannote/speaker-diarization-3.0」のページへアクセスし、ユーザー利用条件の受け入れ(Accept)を実施

2.環境構築

EC2インスタンスの起動

  • AWSコンソールから「EC2」サービスへアクセス
  • 下図を参考にインスタンス起動
    スクリーンショット 2024-07-05 144355.png

スクリーンショット 2024-07-05 145116.png

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

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

SSHクライアントからインスタンスへ接続し下記のコマンドを実行

command
# 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」を、任意のディレクトリに配置
environment.yaml
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
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
  • 配置したディレクトリに移動

仮想環境の作成

command
conda env create -f environment.yaml

仮想環境を有効化

command
conda activate pyannote-audio

pyannote.audioのインストール

command
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の実行

command
python app.py

いかがでしたでしょうか?話者分離&文字起こしはできたでしょうか?

こちらの手順ではGPUではなくCPUを利用する想定のため、比較的処理に時間がかかります。
1時間の音声ファイルを処理するのに、1時間~2時間ほどかかるため、ご注意ください。

5.まとめ

EC2インスタンスにAIモデルをデプロイして利用するという体験自体初めてだったため、めちゃくちゃハマりました。とにかくパッケージ依存関係のエラーが解決できずに、数日頭を抱えていました。最終的には、公式のREADMEを参照したり、Claude(Sonnet 3.5)にエラー内容を投げ込んで得られた回答を試してみたりと……久しぶりに試行錯誤しながら今回の手順にたどり着きました。

今回得た対処ポイントは下記の通り・依存関係エラーはよく観察する・パッケージのインストールごとに依存関係を解決しようとするのではなく、一通りインストールしてから最後に「pip check」で確認し、それを解決する・各パッケージの公式ドキュメントも確認してみる・AIへの質問と実施、公式情報の参照を常に行ったり来たりする

今後もいろいろなAIモデルの利用環境構築に挑戦していきます!

6.参考記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0