😊

WSL2 + Docker で faster-whisper を使ってみる

2023/12/13に公開

前提

前提の環境は、WSL2とDockerが使用可能なNVIDIAのGPUを搭載したWindows PCです。WSL2でnvidia-smiコマンドを打つとGPUのステータスが正常に出てくればOKです。GPU関連はかなり昔に設定したので記憶がありません..。ごめんなさい。

手順

faster-whisperの公式リポジトリのREADME.mdを参考にします。

  1. 'cuBLAS for CUDA 11'と'cuDNN 8 for CUDA 11'のような必要なライブラリを含む公式Dockerイメージをpullします。
docker pull nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04
  1. コンテナを作成して入ります。
docker run --gpus all -it nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04 /bin/bash

VScodeで作業する場合は以下のように実行し、VScode側でこのコンテナにアタッチします。

docker run --gpus all -d --name cuda_container nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04 tail -f /dev/null
  1. この記事を参考にしてpython3.8以上をインストールします。今回は安定している3.10.13にしました。

システムのPythonが既に3.10系統なので、pyenvで新たにインストールするかどうかはオプションです。私は今後のためにインストールしておきましたが、意外と時間がかかりました。ちょっと試したいだけの人はスキップしてください。

途中で以下のエラーが発生するので対処します。

error: please install `aria2c`, `curl`, or `wget` and try again

対処のためのコマンドは以下です。

apt-get install -y curl wget

ロケールの問題が発生した場合は以下を実行します。

apt-get install -y locales
locale-gen en_US.UTF-8
update-locale LANG=en_US.UTF-8
  1. faster-whisperをインストールします。
pip install faster-whisper

ただし、このコンテナを他のLLM等を使用するときに使いまわしたい場合は、以下のように仮想環境でパッケージをインストールします。

cd ~/ && mkdir workspace && cd workspace
python3 -m venv myenv
source myenv/bin/activate
pip install faster-whisper

ここでdockerコンテナをcommitしてimageとして保存しておきましょう。これでコンテナを閉じた後もすぐに再利用できます。

docker commit [コンテナID] faster-whisper

保存したらコンテナを終了します。

docker stop [コンテナID] && docker rm [コンテナID]
  1. 先ほど作成したimageから新しくコンテナを開きます。
docker run --gpus all -it -w /root/workspace faster-whisper /bin/bash

VScodeで作業する場合は以下のように実行してもいいです。

docker run --gpus all -d --name faster-whisper faster-whisper tail -f /dev/null
  1. 動作確認
    まずは作業ディレクトリに移動して仮想環境をアクティベートします。
cd ~/workspace
source myenv/bin/activate

公式のサンプルプログラムをそのまま使用してみます。

sample.py
from faster_whisper import WhisperModel

model_size = "large-v3"

# Run on GPU with FP16
model = WhisperModel(model_size, device="cuda", compute_type="float16")

# or run on GPU with INT8
# model = WhisperModel(model_size, device="cuda", compute_type="int8_float16")
# or run on CPU with INT8
# model = WhisperModel(model_size, device="cpu", compute_type="int8")

segments, info = model.transcribe("audio.mp3", beam_size=5)

print("Detected language '%s' with probability %f" % (info.language, info.language_probability))

for segment in segments:
    print("[%.2fs -> %.2fs] %s" % (segment.start, segment.end, segment.text))

文字起こしをしたい入力ファイルとしてaudio.mp3を同じディレクトリに用意し、プログラムを実行しましょう。

python sample.py

正常に稼働すれば成功です。お疲れ様でした🎉

トラブルシューティング

エラーメッセージ「Killed」で終了してしまう

文字起こしプログラムを実行すると、エラーメッセージ「Killed」で終了することがあります。これはWSL2に割り当てられているメモリのリソースが少ないことが原因かもしれません。'.wslconfig'をWindowsの自分のユーザー名のディレクトリに配置して再設定しましょう。私はメモリが32GBなので以下のように設定しています。

[wsl2]
memory=12GB
swap=0

おまけ

進捗状況を表すシークバーとsrt, ass形式の字幕ファイルを出力するプログラムを作成してみました。参考にしていただければ幸いです。

transcribe.py
# AIによる文字起こしに使用する
from faster_whisper import WhisperModel
# 字幕を作成するために使用する
import pysubs2
# 進行状況バーに使用する
from tqdm import tqdm
# コマンドライン引数を受け取るために使用する
import argparse
# 入力ファイルからファイル名を抽出するのに使用する
from pathlib import Path

# コマンドライン引数を規定する
parser = argparse.ArgumentParser(description='入力したファイルの字幕ファイルを生成するプログラム.')
parser.add_argument('input_file_path', type=str, help='入力ファイルのPath')
args = parser.parse_args()

# モデルのサイズを指定する
model_size = "large-v3"
# 入力ファイルのPathを指定する
# input_file: str = 'input.mp4'
input_file: str = args.input_file_path
# 出力ファイルの名前を指定する
output_name: str = Path(input_file).stem
# 無音部分のカット機能を ( 有効 / 無効 ) ( True / False )にする
vad_filter_flag: bool = False

# モデルのインスタンスを作成する
model = WhisperModel(model_size, device="cuda", compute_type="float16")
# 文字起こしの結果を取得する。segmentsに結果の本体がある。
segments, info = model.transcribe(audio=input_file, vad_filter=vad_filter_flag)

# to use pysubs2, the argument must be a segment list-of-dicts
# pysubs2に対応するように字幕情報を変換する
results = []
timestamps = 0.0  # for progress bar
with tqdm(total=info.duration, unit=" audio seconds") as pbar:
    for s in segments:
        segment_dict = {'start':s.start, 'end':s.end, 'text':s.text}
        results.append(segment_dict)
        pbar.update(s.end - timestamps)
        timestamps = s.end
    if timestamps < info.duration:  # silence at the end of the audio
        pbar.update(info.duration - timestamps)

# 字幕オブジェクトを生成する
subs = pysubs2.load_from_whisper(results)
#save srt file
subs.save(output_name+'.srt')
#save ass file
subs.save(output_name+'.ass')
python transcribe.py 入力ファイルのPath

さいごに

本家のWhisperと比べてかなり速くて驚きました。誰でも無料で高精度の文字起こしができるとはすごい時代になりましたね。今後のAIの進歩にわくわくが止まりません!

Discussion