post Image
畳込みニューラルネットワークの基本技術を比較する ー音でもやってみたー

前回の投稿では、多くの皆様から「いいね」を頂きました。
この場を借りて御礼申し上げます。

前回は画像ファイルでしたが、音ファイルでもやってみたいと思います。

やりたいことは、音ファイルでどの技術が一番効果があるのか数値化します。
以下の流れでやっていきます。

(基本のCNN) → (3つの技術を追加していく)

基本のCNNに、3つの技術を追加しながら、分類精度の上昇幅を比較します。
コードはkerasで書いています。

画像ファイルと同じ結果になるのか?
乞うご期待!

データのダウンロード

使うデータはESC-50です。
これは、人の音声や自然界の音を集めたデータで、50個のラベルが付与されています。

データの前処理

音の生データは波になっています。

import librosa
import pandas as pd
import os

# define directories
base_dir = "./"
meta_file = os.path.join(base_dir, "meta/esc50.csv")

# load metadata
meta_data = pd.read_csv(meta_file)
x, fs = load_wave_data(audio_dir, meta_data.loc[5,"filename"])

#show wave
plt.plot(x)
plt.show()

Wave.png

ついでに、以下のようにコマンドすると音の再生ができます。

import IPython.display as ipd
ipd.Audio(x, rate=fs)

スペクトログラム

波のデータのままでは、うまく特徴が捉えられないので、周波数帯域に
変換してやります。

import librosa.display

# change wave data to stft
def calculate_sp(x, n_fft=512, hop_length=256):
    stft = librosa.stft(x, n_fft=n_fft, hop_length=hop_length)
    sp = librosa.amplitude_to_db(np.abs(stft))
    return sp

# display wave in spectrogram
def show_sp(sp, fs, hop_length):
    librosa.display.specshow(sp, sr=fs, x_axis="time", y_axis="log", hop_length=hop_length)
    plt.colorbar(format='%+2.0f dB')
    plt.title('Spectrogram')
    plt.show()

sp = calculate_sp(x)
show_sp(sp, fs, hop_length=256)

Spectrogram0.png

横軸は時間(sec)、縦軸は周波数(Hz)です。
科捜研のドラマとかで出てくるスペクトログラムの完成です。

メルスペクトログラム

前項で得られたスペクトログラムを、ゴニョニョと処理してメルスペクトログラムを求めます。

 スペクトログラム → ゴニョニョ → メルスペクトログラム → (MFCC)

ゴニョニョが気になる方は以下のリンクを参考にしてください。
音楽と機械学習 前処理編 MFCC ~ メル周波数ケプストラム係数
ケプストラム分析

メルスペクトログラムへ変換することにより、以下の効果があるそうです。
 ・次元が下がる(本稿の場合、513次元 → 128次元)
 ・低音域では敏感に、高音域では鈍感になる(人間の耳の仕様に近づく)
具体的に可視化してみます。

# change wave data to mel-stft
def calculate_melsp(x, n_fft=1024, hop_length=128):
    stft = np.abs(librosa.stft(x, n_fft=n_fft, hop_length=hop_length))**2
    log_stft = librosa.power_to_db(stft)
    melsp = librosa.feature.melspectrogram(S=log_stft,n_mels=128)
    return melsp

# display wave in heatmap
def show_melsp(melsp, fs):
    librosa.display.specshow(melsp, sr=fs, x_axis="time", y_axis="mel", hop_length=128)
    plt.colorbar(format='%+2.0f dB')
    plt.title('Mel spectrogram')
    plt.show()

# example data
melsp = calculate_melsp(x)
show_melsp(melsp, fs)

Mel Spectrogram.png

横軸は時間(sec)、縦軸はメル周波数(Hz)です。

基本のCNN

基本のCNNは@cvuskさんのコードを参考にしています。
コードは以下の通りです。

import keras
from keras.models import Model
from keras.layers import Input, Dense, Activation
from keras.layers import Conv2D, GlobalAveragePooling2D, Add

# redefine target data into one hot vector
classes = 50

def cba(inputs, filters, kernel_size, strides):
    x = Conv2D(filters, kernel_size=kernel_size, strides=strides, padding='same')(inputs)
    x = Activation("relu")(x)
    return x

# define CNN
inputs = Input(shape=(x_train.shape[1:]))

x_1 = cba(inputs, filters=32, kernel_size=(1,8), strides=(1,2))
x_1 = cba(x_1, filters=32, kernel_size=(8,1), strides=(2,1))
x_1 = cba(x_1, filters=64, kernel_size=(1,8), strides=(1,2))
x_1 = cba(x_1, filters=64, kernel_size=(8,1), strides=(2,1))

x_2 = cba(inputs, filters=32, kernel_size=(1,16), strides=(1,2))
x_2 = cba(x_2, filters=32, kernel_size=(16,1), strides=(2,1))
x_2 = cba(x_2, filters=64, kernel_size=(1,16), strides=(1,2))
x_2 = cba(x_2, filters=64, kernel_size=(16,1), strides=(2,1))

x_3 = cba(inputs, filters=32, kernel_size=(1,32), strides=(1,2))
x_3 = cba(x_3, filters=32, kernel_size=(32,1), strides=(2,1))
x_3 = cba(x_3, filters=64, kernel_size=(1,32), strides=(1,2))
x_3 = cba(x_3, filters=64, kernel_size=(32,1), strides=(2,1))

x_4 = cba(inputs, filters=32, kernel_size=(1,64), strides=(1,2))
x_4 = cba(x_4, filters=32, kernel_size=(64,1), strides=(2,1))
x_4 = cba(x_4, filters=64, kernel_size=(1,64), strides=(1,2))
x_4 = cba(x_4, filters=64, kernel_size=(64,1), strides=(2,1))

x = Add()([x_1, x_2, x_3, x_4])

x = cba(x, filters=128, kernel_size=(1,16), strides=(1,2))
x = cba(x, filters=128, kernel_size=(16,1), strides=(2,1))

x = GlobalAveragePooling2D()(x)
x = Dense(classes)(x)
x = Activation("softmax")(x)

model = Model(inputs, x)

色々なサイズのフィルターを通すことで、短期から長期の特徴を捉えることができるそうです。
早速、以下のように学習させます。入力データはスペクトログラムを使用しています。

# initiate Adam optimizer
opt = keras.optimizers.adam(lr=0.00001, decay=1e-6, amsgrad=True)

# Let's train the model using Adam with amsgrad
model.compile(loss='categorical_crossentropy',
              optimizer=opt,
              metrics=['accuracy'])

hist = model.fit(x_train,y_train,
                 validation_data=(x_test,y_test),
                 epochs=50, 
                 verbose=1,
                 batch_size=20)

学習結果↓

base.png

Validationの分類精度は36.2%となりました。
まだ伸びる余地はありますが、行っても40%くらいという印象です。

各技術の追加

これより、各技術を追加します。

基本のCNNと同じ条件にするために、畳込み層は同じ構造にして、epochも20で固定します。
その他、全結合層や正則化層などは無制限です。

前回の結果を受け、追加する技術はData AugmentationとBatch Normalizationに絞ります。
そして、技術というよりは、前処理に近いメルスペクトログラムの有無によって精度が
どれくらい変わるのか観察します。

メルスペクトログラムの効果

基本のCNNの入力は、スペクトログラムを使っていました。
ここでは、入力をメルスペクトログラムに変えてみます。

学習結果↓

mel.png

Validationの分類精度は28.2%となり、基本のCNNより6.4%ダウンしました。
メルスペクトログラムは、音声認識では適しているかもしれませんが、自然界の音は
スペクトログラムの方が良いのかもしれません。

Batch Normalizationの効果

前項のモデルにBatch Normalizaion(BN)を追加します。

def cba(inputs, filters, kernel_size, strides):
    x = Conv2D(filters, kernel_size=kernel_size, strides=strides, padding='same')(inputs)
    x = BatchNormalization()(x)
    x = Activation("relu")(x)
    return x

学習結果↓

Batch.png

Validationの分類精度は46.2%で、前項より17.8%アップしました。
BNの効果は絶大です。動作は軽い上に、良い仕事をします。

Data Augmentationの効果

Data Augmentationを追加します。こちらも@cvuskさんのコードを参考にしています。
音程を少し変えたり、ノイズを加えたり、時間をずらしたりしています。

# data augmentation: add white noise
def add_white_noise(x, rate=0.002):
    return x + rate*np.random.randn(len(x))

# data augmentation: shift sound in timeframe
def shift_sound(x, rate=2):
    return np.roll(x, int(len(x)//rate))

# data augmentation: stretch sound
def stretch_sound(x, rate=1.1):
    input_length = len(x)
    x = librosa.effects.time_stretch(x, rate)
    if len(x)>input_length:
        return x[:input_length]
    else:
        return np.pad(x, (0, max(0, input_length - len(x))), "constant")

x_w = add_white_noise(x)
x_s = shift_sound(x)
x_st = stretch_sound(x)

学習結果↓
Aug.png

Validationの分類精度は56%となり、前項より10%アップしました。
まだまだ伸びる余地はあり、エポックを増やせば70%くらいまで行けるかもしれません。

まとめ

以上の結果をまとめると、以下のようになります。
result.png

前回同様、ここだけで判断するのはちょっと乱暴ですが、音ファイルでは
「Batch Normalization」が一番効果的であることが確認されました。

BNとData Augmentationは、画像ファイルでも良い作用をしましたし、これは外せない技術といえます。
一方、メルスペクトログラムやresblockは慎重に取り扱わないと、悪影響を及ぼす可能性があるので注意が必要です。

感想

今回使用したデータは、1つのファイルサイズが128×1723×1でとんでもなく重く、保存や学習でかなり時間がかかりました。

前回のCIFAR-10(サイズ:32×32×3)は、100エポックの学習で2時間かかり、気軽にできるレベルでした。しかし、今回は50エポックの学習で4時間かかりました(Colaboratory)。

また、batchsizeは20が限界で、これ以上だとColaboratoryからメモリーエラーで怒られました。
ColaboratoryでESC-50を使う際は、気長に待ちましょう。


『 機械学習 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。