Python + ESPnetで長い音声データにおける日本語の文字起こし(ASR)を実装する
Python + ESPnetで長い音声データにおける日本語の文字起こし(ASR)を実施します.
今回はGoogle ColabとGoogle Driveを連携させて,notebook形式で実行してます.
Google Colaboratory(以下Google Colab)は、Google社が無料で提供している機械学習の教育や研究用の開発環境です。開発環境はJupyter Notebookに似たインターフェースを持ち、Pythonの主要なライブラリがプリインストールされています。
引用元:Google Colabの使い方 (opens new window)
全国630店舗以上!もみほぐし・足つぼ・ハンドリフレ・クイックヘッドのリラクゼーション店【りらくる】
# Google Colabのファイル構成
プロジェクトディレクトリはASRとしています.度々,省略しています.
本稿では,岡田斗司夫さんの切り抜き動画 (opens new window)を文字起こしします.
ASR
├── /ASR_FILES
| ├── okada.mp4 <- 文字起こし動画
| └── /output/okada.txt <- 文字起こしたテキスト
└── ESPnetASR.ipynb <- 実行用ノートブック
# Google Driveと連携
Google ColabとGoogle Driveを連携させて,作業ディレクトリを作成します.
# Google Driveと連携
from google.colab import drive
drive.mount('/content/drive')
# 作業ディレクトリの作成
%cd /content/drive/MyDrive/
!mkdir -p ASR
%cd ASR
!ls
# モジュールのインストール
下記のコマンドでモジュールをインストールします.
# ffmpeg
!apt-get install ffmpeg
# pip
!pip install torch
!pip install espnet_model_zoo
# 長い音声データでのASR実行
実行過程は下記の通りです.
- ライブラリのインポート
- 動画データから音声データへ(mp4→wav)
- wavファイルの分割(60sごとに)
- 複数のwavファイルを順にテキストに変換
- 0〜3をdefでまとめる
- ASR実行
# ライブラリのインポート
import wave
import struct
import math
import os
from scipy import fromstring, int16
import subprocess
import shutil
import glob
import soundfile
from espnet_model_zoo.downloader import ModelDownloader
from espnet2.bin.asr_inference import Speech2Text
# 動画データから音声データへ(mp4→wav)
ffmpegで動画から音声への変換を実行します.
ESPNetでは下記のwavファイルの設定でないと,ちゃんと文字起こしされません.
- Channel num : 1
- Sample width : 2
- Sampling rate : 16000
上記の設定を加味した変換は下記の通りとなります.
# 音声ファイルへの変換
def mp4_to_wav(mp4f):
wavf = mp4f.replace('.mp4', '.wav')
subprocess.run(['ffmpeg', '-i', mp4f, '-ar', '16000', '-ac', '1', '-y', '-f', 'wav' ,wavf],
encoding='utf-8', stdout=subprocess.PIPE)
return wavf
# wavファイルの分割(60sごとに)
# 音声ファイルの分割(デフォルト60秒)
def cut_wav_espnet(wavf,time=60):
# timeの単位は[sec]
# ファイルを読み出し
wr = wave.open(wavf, 'r')
# waveファイルが持つ性質を取得
ch = wr.getnchannels()
width = wr.getsampwidth()
fr = wr.getframerate()
fn = wr.getnframes()
total_time = 1.0 * fn / fr
integer = math.floor(total_time) # 小数点以下切り捨て
t = int(time) # 秒数[sec]
frames = int(ch * fr * t)
num_cut = int(integer//t)
# waveの実データを取得し、数値化
data = wr.readframes(wr.getnframes())
wr.close()
X = fromstring(data, dtype=int16)
# wavファイルを削除
os.remove(wavf)
wavf_list = []
for i in range(num_cut):
# 出力データを生成
output_dir = os.path.dirname(wavf) + '/output/cut_wav/'
os.makedirs(output_dir,exist_ok=True)
outf = output_dir + str(i).zfill(3) + '.wav'
start_cut = i*frames
end_cut = i*frames + frames
Y = X[start_cut:end_cut]
outd = struct.pack("h" * len(Y), *Y)
# 書き出し
ww = wave.open(outf, 'w')
ww.setnchannels(ch)
ww.setsampwidth(width)
ww.setframerate(fr)
ww.writeframes(outd)
ww.close()
# リストに追加
wavf_list.append(outf)
return wavf_list
# 複数のwavファイルを順にテキストに変換
# 複数ファイルの音声のテキスト変換
def wavs_asr_espnet(wavf_list, asr_model):
output_text = ''
# 複数処理
print('音声のテキスト変換')
for wavf in wavf_list:
# wavファイルの読み込み
speech, _ = soundfile.read(wavf)
# 音声のテキスト変換
nbests = asr_model(speech)
text, *_ = nbests[0]
# 各ファイルの出力結果の結合
output_text = output_text + text + '\n\n'
# wavファイルを削除
os.remove(wavf)
print(wavf)
return output_text
# 1〜4をdefでまとめる
# mp4からwavへの変換から音声のテキスト変換まで
def mp4_asr_espnet(mp4f):
# mp4のディレクトリ
input_dir = os.path.dirname(mp4f)
# 学習済みをダウンロードし、音声認識モデルを作成
d = ModelDownloader()
speech2text = Speech2Text(
**d.download_and_unpack("kan-bayashi/csj_asr_train_asr_transformer_raw_char_sp_valid.acc.ave"),
device="cuda" # CPU で認識を行う場合は省略
)
# 出力ディレクトリ
if os.path.exists(input_dir + '/output/cut_wav/'):
shutil.rmtree(input_dir + '/output/cut_wav/')
os.makedirs(input_dir + '/output/cut_wav/', exist_ok=True)
else:
os.makedirs(input_dir + '/output/cut_wav/', exist_ok=True)
# 音声ファイルへの変換
wav_file = mp4_to_wav(mp4f)
# 音声ファイルの分割(デフォルト60秒)
cut_wavs = cut_wav_espnet(wav_file)
# 複数ファイルの音声のテキスト変換
out_text = wavs_asr_espnet(cut_wavs, speech2text)
# テキストファイルへの入力
mp4f_name = os.path.basename(mp4f)
txt_file = input_dir + '/output/' + mp4f_name.replace('.mp4', '.txt')
print('テキスト出力')
print(txt_file)
f = open(txt_file, 'w')
f.write(out_text)
f.close()
# ASR実行
mp4_files = glob.glob('./ASR_FILES/*.mp4')
for mp4_file in mp4_files:
mp4_asr_espnet(mp4_file)
# まとめ
本稿では,Python + ESPnetで長い音声データにおける日本語の文字起こし(ASR)を実施しました.
# 参考サイト
ESPnet2で始めるEnd-to-End音声処理 (opens new window)
複雑な音声処理タスクを一気通貫で実装できる! ESPnetの概念と特徴について (opens new window)
簡単に作れるTTSモデル:ESPnetを用いたつくよみちゃんTTSモデル作成 (opens new window)
ESPnet による音声認識入門 ~ESPnet Model Zoo 編~ (opens new window)