年明け早々の2025年1月2日、前年に北朝鮮国内での公開が確認されていた新作映画「72시간(72時間)」が朝鮮中央テレビで放送され1、日本をはじめとする諸外国の人々の初めて目にするところとなった。
本映画は2022年公開の「하루낮 하루밤(一昼一夜)」に続き、2020年代に入って2作目の長編映画であり、冒頭で説明がある通り、金正恩氏が直々に指導を行い、また一部シーンはカザフスタンにて撮影される2など、大掛かりな撮影が行われた力作であることが以前から示唆されており3、北朝鮮について調べている人々の間では話題となっていた。
十分な大きさのパラボラアンテナが入手できず、映像を受信できなかったことは痛恨の極みであったが、1月4日、朝鮮総連が保有していると思われるYoutubeアカウント「elufa tv」に、前後編がそれぞれアップロードされた4。
無論これらは朝鮮語のままであり、字幕なども付けられていないので、日本語でこの映画を楽しみたいと求める人々の間で、全編翻訳の機運が高まった。
しかしながらこの映画、前編2時間11分、後編1時間51分と、長さが合計4時間近くもある。すべて人力で聞き取り、書き起こしを行おうとするなら、どれだけ手間がかかるか計りしれない。
折しも、将来的に入手した映像の機械的な音声文字起こしが必要になるだろうと考えていたため、せっかくならこの機会にと、AIによる文字起こしを試してみることにした。
筆者はAIについての専門家ではないので、改善の余地は至る所にあると考えられるが、一見したところかなり精度の良い5書き起こしを得られたと思っているので、ぜひその成果物を活用してもらいたい(ただし成果物を活用する際は少なくともintchoson.comのURLを出典として記載していただけるよう、お願い申し上げる)。
firefoxプラグインの「Video DownloadHelper」と「えこでこツール」を使って音声を取得、「Online MP3 Cutter」を使って前編7分割、後編6分割にする。分割したファイルをGoogleDrive上にアップロードし、GoogleColab上に書いたpythonのコードで処理を行う。
ここでOpenAIの開発しているAI、「Whisper」を使うが、無音シーンが多いとrepetition(繰り返し、幻聴)が起こるので、「Silero VAD」という音がある部分とない部分を判別してくれるAIで下処理をする。が、どうもこの処理を行うとセリフの最初の部分が切れがちになってしまう模様である。
VADを使ったものと使わないでそのままWhisperに投げたもの、どちらも作成したので、両方を見比べながら翻訳をしていくのがよいかと思われる。
なお、Whisperのモデルにはtinyからlargeまで種類があり、精度と情報の処理量に違いがあるが、今回はlargeに次いで大きいmediumを使用した。largeでも試行してみたものの、モデルが大きすぎて処理が追い付いていないのか、むしろmediumよりも聞き取り精度は落ちているように思われた。
以下にそれぞれ実行した際の結果(テキストファイル、ログをコピーアンドペーストしたもの)のダウンロードリンクを設ける。
前編、VADなし:72hours1_novad.txt 前編、VADあり:72hours1_vad.txt 後編、VADなし:72hours2_novad.txt 後編、VADあり:72hours2_vad.txt googlecolab上に書いたpythonのコードは以下の通り。
VADなし
!pip install git+https://github.com/openai/whisper.git import whisper lang = "ko" tra_model = whisper.load_model("medium") name = 72hours1 #今回は前編を7等分して72hours1_番号.wavという形でGoogleDrive上にupしている。その72hours1の部分 for i in range(1,8): audio = whisper.load_audio(f"/content/drive/MyDrive/"+name+"_"+str(i)+".wav") results = tra_model.transcribe(audio,verbose=True,language=lang) for result in results["segments"]: with open(f"/content/drive/MyDrive/72hours.txt", "a") as txt1: txt1.write(result["text"]+"\n") VADあり
!pip install git+https://github.com/snakers4/silero-vad.git !pip install git+https://github.com/openai/whisper.git import whisper import torch import torchaudio from silero_vad import load_silero_vad, read_audio, get_speech_timestamps from torchaudio.transforms import Resample vad_model = load_silero_vad(onnx=True) lang = "ko" tra_model = whisper.load_model("medium") name = 72hours1 #同上、GoogleDrive上にupした音声ファイルの名前。 for i in range(1,7): waveform, sample_rate = torchaudio.load(f"/content/drive/MyDrive/"+name+"_"+str(i)+".wav") #Silero VADはサンプリングレート16000に最適化されているようなので、サンプリングレートを変換 if sample_rate != 16000: resample_transform = Resample(orig_freq=sample_rate, new_freq=16000) waveform = resample_transform(waveform) sample_rate = 16000 #ステレオ音源だとWhisperがエラーになるので、モノラル音源に変換 #参考:https://note.com/owlet_notes/n/n4ba64137456a if waveform.shape[0] > 1: waveform = torch.mean(waveform, dim=0, keepdim=True) #VADで音声を切り出し、tempファイルとしてdriveに一時保存、逐次Whisperで聞き取り speech_segments = get_speech_timestamps(waveform,vad_model,sampling_rate=sample_rate) for segment in speech_segments: segment = waveform[:, (segment["start"]):(segment["end"])] temp_audio_path = "/content/drive/MyDrive/temp_audio.wav" torchaudio.save(temp_audio_path, segment, sample_rate) results = tra_model.transcribe(temp_audio_path,verbose=True,language=lang) for result in results["segments"]: with open(f"/content/drive/MyDrive/72hours.txt", "a") as txt1: txt1.write(result["text"]+"\n") 参考文献 磯部太郎丸(@iso_taro_maru)氏のツイート
ののじのじ(@nnjnoji)氏のツイート ↩︎
...