PLaMo翻訳のモデルで動画の字幕を翻訳する
前日、Preferred Networks (PFN) が開発している LLM を使った PLaMo翻訳 がリリースされました。
PLaMo翻訳は LLM を使った翻訳なので、従来のニューラル機械翻訳に比べて、文脈から 空気を読んで いい感じに翻訳してくれるという特徴があります。X で見かけた以下のポストでは、構造を持ったテキストをうまく元の構造を維持したまま翻訳してくれているのが確認できます。
PLaMo 翻訳はデモサイトで簡単に試せるほか、モデル自体も PLaMo Community License で huggingface 上で公開されており、 8B モデルが動く GPU があればローカルで自分で動かすこともできるようになっています。
この記事では「huggingface 上で公開されているモデルを利用してローカルで実行する形で」「構造をもった大きいテキストを翻訳する」例として、動画の字幕 (.srt
ファイル) の翻訳の実装を紹介します。今回 .srt
を取り上げますが、format に関してはできるだけ LLM に丸投げする形で実装してみたので、他の format でも広く使えるような実装になっているのではないかと思います。
準備
必要な package の install
PLaMo 2 は vllm に実装がマージされているため vllm が入っていれば推論を実行できます。
pip install "vllm>=0.8.5"
vllm による推論は transformers による推論に比べて大幅に高速なため、追加で学習を行うような場合以外は vllm の利用をおすすめします。
.srt
ファイルの用意
翻訳元の字幕が存在せず、動画の文字起こしから始める場合は OpenAI が公開している Whisper が便利です。
これを使う場合は、ffmpeg なりを使って動画から音声を抽出し、whisper で書き起こして .srt ファイルを作成する、という流れになります。
# ffmpeg を使って音声を mp3 として抽出する
ffmpeg -i input_video.mp4 -vn -acodec libmp3lame -q:a 2 audio.mp3
# whisper を使って書き起こしをする
pip install -U openai-whisper
# この例では large-v3 という大きい強力なモデルを利用
whisper audio.mp3 --model large-v3 --language en
実装
適当な1文を翻訳させてみる
まずは vllm を import して、vllm.LLM の instance を作成します。
import vllm
llm = vllm.LLM(model="pfnet/plamo-2-translate", trust_remote_code=True, max_model_len=16 * 1024, max_num_seqs=16)
このとき、max_model_len
は扱う最大 token 数、max_num_seqs
は1バッチで並列に処理する request の数を制御します。両方とも、増やすと要求される GPU メモリが大きくなるパラメータで、今回は GeForce RTX 4090 (24GB VRAM) に載せられる最大の max_model_len
を指定して、OOM しないように max_num_seqs
を絞っています。
次に、公式のサンプルにある例を実行してみます
prompt = r'''<|plamo:op|>dataset
translation
<|plamo:op|>input lang=English
Write the text to be translated here.
<|plamo:op|>output lang=Japanese
'''
responses = llm.generate([prompt], sampling_params=vllm.SamplingParams(temperature=0, max_tokens=1024, stop=["<|plamo:op|>"]))
print(responses[0].outputs[0].text)
prompt の <|plamo:op|>input lang=English\n
の後の Write the text to be translated here.
が翻訳対象の文字列になります。上記のコードを実行すると翻訳結果として ここに翻訳するテキストを入力してください。
と print されます。
ファイル全体を翻訳する
LLM による翻訳では、ある程度長い文章をまとめて翻訳させることで前後の文脈も加味した翻訳が可能になりますが、ファイルが大きくなると、GPU メモリやモデルの context-length の制約により、全文を一度に入力するのは難しくなります。
今回は、以下のようなアプローチで前後の文脈を加味しつつ入力を分割することにします。
- 入力ファイルを行ごとに分割
-
lines_per_window = 64
行をまとめて入力 - 入力のうち最初の数行 (
lines_per_window - stride = 16
行) が前回の翻訳と被るようにして、前回の翻訳結果とうまくつながる翻訳を生成させるようにする
また、生成結果が必ず元の format に従うとは限らないため、チェックして、うまく言っていない場合は再生成を行ってあげるようにします。具体的なチェック方法は翻訳したい対象によって様々な実装が考えられますが、今回はできるだけ汎用な方法で行いたいため、生成結果の行数のチェックだけ行うことにします。
具体的な実装は以下のとおりです。
.srt
ファイルは 4行ごとにまとまりのあるデータになっているので、被せる行数を 4 の倍数にすることで、変な分割にならないようにしています。逆に、それ以外の .srt
固有の工夫はしておらず、.srt
format 固有の、番号や timestamp などの情報を翻訳後も保持するというところは LLM にまる投げしています。そのため、.srt
以外のフォーマットでも利用可能なアプローチになっているのではないかと思います。
結果のサンプル
音声は、Gemini に「翻訳モデルのデモとして、英語のプレゼンの書き起こしを翻訳する、ということを行いたいと思っています。そのために適当な英語のプレゼンの原稿が必要です。適当な原稿を考えていただけないでしょうか?」という prompt で作成してもらった原稿を、GCP の Text-to-Speech AI で音声に変換したものです。これを上記の手順で、whisper で英語 .srt に変換、plamo-2-translate で日本語 .srt に変換して、字幕付きの動画を作成しました。
英語 .srt
翻訳後の日本語 .srt
一部、英語と日本語の語順の関係で、字幕としては不自然な翻訳になっていたりする部分もありますが、全体的に機械翻訳としては十分満足できるレベルのものができているのではないかと思います。
Discussion
タイムリーで有益な記事の公開をありがとうございます。自分の手持ちの専用メモリ6GBのノートブック用3060ではmax_model_lenやmax_num_seqsを小さくしても動作することができませんでしたが正しいインストール方法がわかってよかったです。