とあるプログラミング学習サイトで以下のような講座を見つけました。
Python×AI・機械学習入門編2: 話者認識をしよう
機械学習で音声認識を行います。音声データから特徴量を抽出する方法を学習し、SVMで分類します。
とても面白そうな記事ですが、残念ながら有料プランの講座でした。
概要とコードをチラ見したところ、3人の声優を話者識別するために音声データから特徴量(MFCCなど)を抽出して、SVM(サポートベクターマシン)で分類しているようです。
Google検索してみると、話者識別の記事のほとんどがSVMを用いていますが、
「SVMは本当にベストプラクティスなのか」
「声優を100人に増やしても、高い予測精度を維持できるか」
を中心に(もちろん無料の)記事を書いていきます。
▼ 動画の冒頭を見ていただけると、タスクの難易度と概要が分かります
0. 話者識別とは
話者認識(Speaker Recognition)の1つです。
話者照合(Speaker Verification)... ある人物が本人の主張している通りの個人であるかを照合する
話者認識(Speaker Identification)... 誰だかわからない声を誰のものか識別する
ということだけ抑えておけば大丈夫そうです。
この記事では、誰だか分からない声から声優を識別する後者を扱います。
1. 学習データの収集
有料プランの講座でもなければ、声優でもないので、学習用のデータセットは自分で用意しなければなりません。
ふさわしいデータセットを検索していたら、
JVS(Japanese Versatile Speech) corpus
という、東京大学の猿渡研究室が無償で公開している音声コーパスを見つけました。
日本声優統計学会が独自に構築した音素バランス文を、100人のプロフェッショナル話者(声優・俳優など)が読み上げた音声(parallel100
)が含まれています。
今回は、このparallel100
を使って学習を行います。
2. 特徴量の抽出
いよいよ音声データから特徴量を抽出します。
特徴量には、音声認識の分野では馴染みが深いとされているMFCC(メル周波数ケプストラム係数)を用います。
「メル尺度」 という人間の聴覚に基づいた尺度がポイントになります。
変換手順も含めて以下の記事を参考にさせていただきました。
MFCC(メル周波数ケプストラム係数)入門 - Qiita
(すごく分かりやすい記事なので、見るだけで感動します。オススメです!!)
原理に沿って計算するとステップはやや多いですが、PythonではLibrosaというライブラリを使って簡単に各フレームのMFCCを求めることができます!
import os
import numpy as np
import pandas as pd
import librosa
X_data = [] # 特徴行列
y_data = [] # クラスラベルデータ
for speaker_num in range(1, 101): # 声優No.1~100
# parallel100の音声データが入っているディレクトリ名
dir_name = f'../input/jvs-ver1/jvs_ver1/jvs{str(speaker_num).zfill(3)}/parallel100/wav24kHz16bit'
for file_name in os.listdir(dir_name):
file_path = os.path.join(dir_name, file_name) # 音声ファイルへのパス
y, sr = librosa.load(file_path) # 音声ファイルを読み込む
mfcc = librosa.feature.mfcc(y, sr) # MFCC
mfcc = np.average(mfcc, axis=1) # 時間平均を取る
mfcc = mfcc.flatten()
mfcc = mfcc.tolist()
mfcc = mfcc[1:13] # 低次の係数を取り出す(12次まで取り出すことが多い)
X_data.append(mfcc)
y_data.append(speaker_num)
X = pd.DataFrame(X_data, columns=[f'mfcc_{n}' for n in range(1, 13)])
y = pd.DataFrame({'target': y_data})
df = pd.concat([X, y], axis=1)
df.to_csv('mfcc.csv', index=False) # csvで保存
df.head()
すると、このように1つの音声ファイルにつき12個の特徴量が得られます。
(データセットも含めて)使用したKaggle Notebookはこちらで公開しています。
3. モデルの学習・予測
分類モデルにSVM(サポートベクターマシン)を使っている記事が多いですが、ドメイン知識を持っているわけではないので、とりあえずPyCaretでモデル比較を行います。
【参考】【5分で分かる】PyCaretについて徹底解説!|スタビジ
事前準備
ライブラリのインストール
import numpy as np
import pandas as pd
from pycaret.classification import *
データセットを読み込む
data = pd.read_csv('../input/100-speakers-mfcc/mfcc.csv') # 保存したcsvファイルへのパス
data['target'] = data['target'] - 1 # クラスラベルを1ずらす
data.head()
データの前処理はたった1行で完結します。
reg = setup(data=data, target='target', data_split_shuffle=True, use_gpu=True, silent=True, fold=5, n_jobs=-1)
モデリングもたった1行で完結します。
compare_models()
# compare_models(exclude=['catboost', 'xgboost', 'gbc', 'rf']) # 極端に遅いモデルを避ける書き方
どの評価指標においても、qda(Quadratic Discriminant Analysis)がトップでした。
正解率97.98%と、想像よりはるかに良い精度が出ました。
このモデルをチューニングして、予測結果を出します。
lda = create_model('lda', verbose=False)
tuned_qda = tune_model(qda, optimize='AUC')
predict_model(tuned_qda)
なんと、正解率98.57%です!
声優100人の話者識別問題に、ほぼ全問正解することができます。
ちなみに冒頭で紹介した(非線形)SVM は、PyCaretのモデル比較リストには入っていませんでしたが、'rbfsvm'
で直接モデル指定して予測したところ正解率は 約78% でした。100クラスの分類には向いていないのかもしれません。
(データセットも含めて)使用したKaggle Notebookはこちらで公開しています。
4. さいごに
精度が良すぎてビックリしてしまいました。
JVS(Japanese Versatile Speech) corpusには、parallel100
の他にも裏声やささやき声の音声データも入っているので、これらも識別できれば面白いなと思いました。
98.57%をたたき出したモデルが間違えた問題を動画の最後に紹介しているので皆さんでAIに勝てるかどうか、ぜひ挑戦してみてください!!