機械学習のための音声の特徴量ざっくりメモ (Librosa ,numpy)


Introduction

この記事は基本的に自分用のメモみたいなもので、かなりあやふやな部分もあります。間違っている部分を指摘していただけると助かります。(やさしくしてね)
ネット上にLibrosaの使い方、Pythonによる音声特徴量の抽出の情報が少なかったり、難しい記事ばかりだったので、かなり噛み砕いてメモするつもりでいます。
基本的に機械学習に用いられている音声の特徴量について記述していきます。
(2019/8/20)勉強した分だけ載せました、ちょっとずつ更新していきます。
(2019/8/22)MFCCの分だけ更新しました。
(2019/8/23)ZCRについて書きました。

紹介する特徴量

  1. MFCC
  2. log-mel spectrum
  3. HNR
  4. ZCR

1.MFCC

MFCCとの出会い

音声認識に広く使われている特徴量で、だいたいの音声における機械学習の代表的な特徴量ということでだいたいの音声系の機械学習で用いられていました。この特徴量を使うと非力なマシンで機械学習をできる旨味があるとのこと。
ちょっと具体的に旨味をあげます。
・人間の声道の特性(人間の声と聴覚の仕組み)をうまく反映している特徴量
・この特徴量を使うことで、非常に大きい音声の生データ(波形データ)を用いずとも、高精度な音声認識が可能に。

しかし、現在ではlog-mel spectrumを用いることが主流になっているそうです。

log-Melspectrumについては、本記事で軽く触れるつもりではいますが、この理由についてしっかり理解したいならこのアーカイブを読むほうが早いです。
Deep Learning for Audio Processing

MFCCって要するに何?

これなんですよ。なぜか、色々なサイトでも実装方法のみでそれが何を表しているか丁寧に説明してくれるページが非常に少ないですね。これの理解には、
ケプストラム分析について調べることが早そうです。詳しくはリンクをご覧ください。

MFCCは、人間の低音に敏感で高音に鈍いという特徴を考慮しつつ、
声のスペクトル包絡(スペクトルのなだらかで少なめの変化),スペクトルの微細構造(スペクトルの細かい微妙な変化)を分離したものです。要は、長期的な変化と短期的な変化を分離することで人間の声の変化を見ようとする算段です。
「スペクトル」って何ですか?というひとは、フーリエ変換で検索もしくは書籍を漁るといいかもしれません。

MFCCの理解

数式的理解となると、ちょっとここだけ恐ろしい分量となりそうなので、他のサイトに任せますが、ここではざっくり抽出手順をまとめていきたいと思います。MFCCのメモを作るに当たって、参考にしたサイトは MFCCの最後に乗せさていただきます。

  1. プリエンファシスフィルタで高音域強調
  2. 窓関数をかけた後、FFTにより振幅スペクトルを求める
  3. メルフィルターバンクを適応させる。
  4. 離散コサイン変換
  5. 低次元成分抽出。

この5つの処理を行うことで音声からMFCCを抽出することができます。

これらの具体的な処理について親切にコード付きで(!)図を使って親切に説明してくださるサイト様をあげておきます。
メル周波数ケプストラム係数-人工知能に関する断創録
ちょっと細かい理屈が気になる、数式的に理解したい方はこちらを参照しながらどうぞ。
ケプストラム分析と主成分分析による音声の感情分析,-庄子雄貴,安藤敏彦

Python実装

実装というほど大それたものではないですけど、今回はLibrosaというパッケージを用いてMFCCの抽出を行います。

MFCC.py
import librosa
import scipy


y,sr = scipy.io.wavefile.read("audiofile.wav")
#これで音声の波形データとsr(サンプリングレート)を取り込む
mfcc_feature = librosa.feature.mfcc(y=y,sr=sr,n_mfcc=13)
#y->波形データ,sr ->サンプリングレート,n_mfcc->最後の低次元抽出で何次元とるか(今回は、13次元分取っています。)
print(mfcc.shape)
#numpyで返ってきます。形は(分割したフレームの数,低次元抽出の数)

#ここからちょっと応用でもない応用

mfcc_feature2 = librosa.feature.mfcc(y=y,sr=sr,n_mfcc=13,hop_length=hop_length,win_length=win_length)
#こんな感じに分割の仕方も指定できたりします。hop_lengthは窓をどれぐらい動かすか。win_lengthは、窓の大きさ。






英語マスターの人はLibrosaのドキュメントを読んだ方が早いかもしれませんね。動かなかったら報告してください。治します。

2. log-melspectrogram

log-melspectrogram との出会い

実際のところMFCCをしっかりおさらいしようと思ってさまよっていたら、たまたま見つけました。Qiita様様ですね。きっかけになった記事のリンクを貼っておきます。
MFCC入門 -Qiita
Google様のTTS(Text To Speech)に使われていたりして、機械学習においてはMFCCよりポピュラーな特徴量であるらしいです。生の音声データを扱うよりこっちの方がローコストでもいい感じの精度を出せるとか。
機械学習の環境がGoogleColabしかない貧乏学生には朗報ですね。GPU搭載のまともなPCが欲しい、、、。
参考にした論文はこちら
Deep Learning for Audio Signal Processing

log-melspectrogramって要するに何?

MFCCの離散コサイン変換無いバージョンです。
だと不親切なので念のため
振幅スペクトル(角周波数に対する音量の大きさ)に対し、人間の聴覚特性を適応(Mel-filterbank)を考慮したもの。これに対数を取ることによって得られるものです。

log-melspectrogramの理解

ここではざっくり抽出手順を。
1. プリエンファシスフィルタで高音域強調
2. 窓関数をかけた後、FFTにより振幅スペクトルを求める
3. メルフィルターバンクを適応させる。
とこんな感じです。
MFCCの計算過程で得られるものということがわかると思います。

Python実装

今回もLibrosaを使って特徴量抽出を行います。

log-mel.py
import librosa
import scipy


y,sr = scipy.io.wavefile.read("audiofile.wav")
librosa.feature.melspectrogram(y=y, sr=sr,hop_length=hop_lemgth, win_length=win_length )
#パラメーターの意味はMFCCと一緒
#(フレーム分割数,時間)で返ってきます。

3.Harmonics noise to ratio

HNRとの出会い

Microsoft社の人間の発声から感情を推定する研究の論文 で、有効な特徴量としてあげられていました。日本語の記事が見つからなくて非常に困りました。あまりメジャーではないのかな?

HNRって要するに何?

人間の声の識別に有効な特徴量で、ノイズに対する倍音の割合を指すようですね。
この場合の、ノイズは声帯の閉鎖が対称でないときに引き起こされるガラガラとした声です。これが、ひどいとしゃがれた声になります。つまりHNRが低ければ低いほど透き通った声ってことが言えそうです。
この論文 のabstractに詳しく載っています。Jitterという特徴量より、上手く発生者の年齢を識別しやすいようですね。
こっちの方が英語に自信があるなら参考になるかもしれませんね。(https://www.bartleby.com/essay/Compare-Jitter-Shimmer-and-Harmonics-to-Noise-P3CDRT2KVJ)

数式的理解

HNR  =
10log \frac{ACF\tau_0(m)}{ACF(0)-ACF(\tau_0(m)}

https://www.isca-speech.org/archive/archive_papers/interspeech_2014/i14_0223.pdf より引用
この論文では、一旦音声をフレーム処理をおこなってから計算しています。mはmフレーム目のことです。
ACFは自己相関関数,τはPitch周期をさします。(声に対してHNRをはかりたいから、Pitch?)
これで各フレームに対してHNRを計算して機械学習に用いるというわけです。
自己相関関数の理解はwikipediaの記事 がよい気がします。

Python 実装

ここでは、フレーム処理後に対してのHNRを計算するPythonプログラムを書きます。フレーム処理に関しては、別の記事で触れるつもりです。また、Pitchに関してもこの記事の別の項目で触れたいと思います。
ライブラリーはnumpyをnpとしてインポートして扱います。

HNR.py
import numpy as np
def _acf(x):
    x = x-np.mean(x)
    correlation = np.correlate(x,x,mode='ful')/np.sum(x**2)
    return correlation[int(len(correlation)/2):]

def HNR(x,pitch):
    acf = _autocorrelation(x)
    t0 = acf[0]
    t1 = acf[pitch]

    return 10*np.log(np.abs(t1/(t0-t1)))


#https://github.com/eesungkim/Speech_Emotion_Recognition_DNN-ELM より引用

4.Zero Crossing Rate

Zero Crossing Rate との出会い

ZCRを使って、音楽ジャンルを識別しようという試みをする論文がありました。Computational Models of Music Similarity and their Application in Music Information Retrieval
2005年の音楽ジャンルコンテストにて受賞した技術でもZCRが用いられていたとか。

ZCRって要するに何?

ZCRによって、ノイジーさを測ることができます。
デスメタルとかに対して特徴量抽出したらZCRとっても高く出そうですね。
こちらのサイトが大変参考になりそうです。この記事を書くに当たって参考にさせていただきました。ありがとうございます。
Zero Crossing Rate -えたがわにっき

ZCRの理解


[1]Dipl.-Ing et al. - Computational Models of Music Similarity and their Application in Music Information Retrieval
ZCRとは、名前の通り音の波形が縦軸を振幅,横軸を時間としたとき、横軸を波形が横切る時間あたりの平均頻度のことを示します。
図1で示した赤い部分がゼロを横切っている部分ですね。任意の時間で区切ってその中での平均頻度を計算すればZCRの完成です。
これなら自力でPython実装できそうなので余裕がある方は是非(今回もLibrosa使います。)
ここで、勘の鋭い方だわかってしまうと思うのですが、周波数が高いとZCRが高くなってしまいます。これ単体ではなく、他の特徴量のサポーターとして期待。

Python実装

ZCR.py
y,sr = scipy.io.wavefile.read("audiofile.wav")

librosa.feature.zero_crossing_rate(y=y, frame_length=2048, hop_length=512, center=True)
#y ->波形 ,frame_length ->切り取るフレームのサイズ hop_length ->フレームを切り取る窓をどれだけ動かすのか,center ->端を0でパディングするのかどうか。
#numpyの(1,フレーム数)の形で返ってきます。