marcy's Lab

理系大学生のブログ

Pythonで機械学習に音声データを使うときのメモ

はじめに

機械学習コンペティションで音声データからクラス分類する問題をやることになりました。

これまではベクトルデータの入ったCSVファイルや画像ファイル、文字列などを扱ってきました。

音声データを使った機械学習は初めてだし、それ以外でもPythonで音声ファイルを使ったことがないのでいろいろ調べてまとめてみました。

参考記事

qiita.com

qiita.com

二つの記事を参考にしました。

記事を参考に実装してみて、バージョンや環境の関係でエラーが出たところ、分かりづらかったところを中心に書こうかなと思います。

ライブラリ

librosaというライブラリが一般的に使われるそうです。

あと、Pythonの標準ライブラリにWaveモジュールがあり、これも使うらしいです。

Waveモジュールよりもlibrosaの方が機械学習向けって感じなのかな。あんまり調べてないからわかんないですけど。

上の記事ではWindows環境で、pip install librosaに失敗したと書いてありましたが、僕もWindows環境で失敗しました。

もともとAnaconda環境だったので、conda install librosaでインストールしました。

librosaのバージョンは0.6.2でした。

読み込み・プロット・編集

import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
import wave
import librosa as lr
import librosa.display

インポートします。

librosa.display は波形の表示に使います。ちゃんとインポートしましょう。(インポートせずに使おうとして、何回もエラー吐かれた。よく分からずコピペはダメ、絶対。)

waveモジュール

filename = "sound.wav"
with wave.open(filename, 'r') as wr:
    data = wr.readframes(wr.getnframes())
X = sp.fromstring(data, dtype=sp.int16)
plt.plot(X)

readframes関数で得られるdataはbytes型というものでpython使ってて初めて出会いました。

これをscipyのfromstring関数でbytes型から整数型のnumpy配列に変換します。

それをプロットしたものが以下の図になります。

f:id:marc326marcy:20190118023401p:plain

変換する前はbytes型という気持ち悪さと、変換したあともfloat型じゃなくてint型のnumpy配列という気味の悪さ。

waveモジュールは、ファイルのフレームレートやフレーム数を取得する程度で、編集に関しては軽くトリミングするくらいが主な用途みたいです。

librosa

y, sr = lr.load(filename)
totaltime = len(y) / sr
time = np.arange(0, totaltime, 1/sr)
plt.plot(time, y)

lr.load関数でデータがfloat型のnumpy配列でyに出力され、サンプリングレートがsrに出力されます。

f:id:marc326marcy:20190118024913p:plain

データのプロットを見て一番大きな違いは縦軸の大きさですかね。

librosaはここからさらにスペクトログラムを作成することが出来ます。

S = lr.feature.melspectrogram(y, sr=sr, n_mels=128)
log_S = lr.amplitude_to_db(S, ref=np.max)
librosa.display.specshow(log_S, sr=sr, x_axis='time', y_axis='mel')
plt.colorbar(format='%+02.0f dB')
plt.tight_layout()

f:id:marc326marcy:20190118031541p:plain

参考にした記事では

log_S = librosa.logamplitude(S, ref_power=np.max)

を使ってましたが、バージョンの関係で使えなくなってました。

機械学習での扱い

ニューラルネットワークを用いる手法では、上のスペクトログラムを二次元画像データとして、CNNに入力するのが主流(?)らしいです。



いろいろ調べてまとめてみました。と序盤に書いておきながら、気力が尽きたので

おわり!

すぐ追記するか新しい記事書きます、きっと。