post Image
DeepLearningで楽曲特徴量を抽出し、タグを予測する

モチベーション

従来の音楽推薦技術は協調フィルタリングを用いることが多かったようですが、協調フィルタリングではマイナーな曲、新曲など「ユーザーからの評価が集まらない」作品をうまく扱えないという欠点があります。

音楽推薦技術のもう一つのアプローチ、「楽曲特徴量を抽出して推薦に活かす」という方法ならば、前述の問題を回避することができそうです。

そこで’End-to-end learning for music audio’1という論文を使って勉強しようとしたところソースコードが見つからなかったので、自力で再現して「DeepLearningで楽曲特徴量を抽出し、タグを予測する」タスクを行うことにしました。(なお、一部作業を変更し、完全な再現ではないことをご了承くださいませ。)

音楽をPython, DeepLearningで処理する記事があまり見つからなかったので、何かの参考になれば幸いです。

データセットの入手

MagnaTagATune Dataset2を使います。1曲につき29秒の楽曲が25863曲、188個のタグとセットになっています。

# MP3データの入手
$ wget http://mi.soi.city.ac.uk/datasets/magnatagatune/mp3.zip.001
$ wget http://mi.soi.city.ac.uk/datasets/magnatagatune/mp3.zip.002
$ wget http://mi.soi.city.ac.uk/datasets/magnatagatune/mp3.zip.003

# 分割zipファイルを統合、解凍する
$ cat mp3.zip* > ~/music.zip
$ unzip music.zip

# タグデータの入手
$ wget http://mi.soi.city.ac.uk/datasets/magnatagatune/annotations_final.csv

MP3をNumpyで扱えるようにする

pydubのインストール

通常音声認識やMIR(music information retrieval)で使われる音声特徴量は、RAWデータに特徴量抽出を施した後のメル周波数ケプストラムなどです。しかしこの論文では、RAWデータをそのまま音声特徴量として用いています。画像と同様、生のデータをDeepLearningにぶっ込んで自動で特徴量抽出させようって魂胆なわけです。

MP3をRAWに変換するために、pydubというパッケージを使いました。libavかffmpeg(音声のエンコード、デコードをしてくれるらしい)も必要です。詳しくは公式のGithub

$ pip install pydub

# macの場合
$ brew install libav --with-libvorbis --with-sdl --with-theora

# linuxの場合
$ apt-get install libav-tools libavcodec-extra-53

また、私のubuntu環境では公式の方法が効かなかったので、こちらの記事を参考にしました。

ファイルのインポートとndarrayへの変換

mp3ファイルのパスを引数にndarrayを生成する以下の関数を定義しておきましょう。

import numpy as np
from pydub import AudioSegment

def mp3_to_array(file):

    # MP3からRAWへの変換
    song = AudioSegment.from_mp3(file)

    # RAWからbytestring型への変換
    song_data = song._data

    # bytestringからNumpy配列への変換
    song_arr = np.fromstring(song_data, np.int16)

    return song_arr

データセットの準備

楽曲タグ(y)の準備

先ほどダウンロードしたタグデータを読み込みましょう。
また、以下の2点にご留意ください。

  • タグをよく使われる50個に限定していること
  • メモリに乗り切らないのでサンプルを3000個に限定していること
import pandas as pd

tags_df = pd.read_csv('annotations_final.csv', delim_whitespace=True)
tags_df = tags_df.sample(frac=1)
tags_df = tags_df[:3000]

top50_tags = tags_df.iloc[:, 1:189].sum().sort_values(ascending=False).index[:50].tolist()
y =  tags_df[top50_tags].values

RAWデータ(X)の準備

  • tags_dfにmp3ファイルへのパスが含まれているので利用します。
  • Xは[samples(曲数), features, channel(今回は1)]にreshapeしておきます。
  • RAWデータは16kHzなので、1秒あたり16000個、約30秒で465984個のfeaturesを持ちます
  • 元論文では音源を3秒に区切って訓練させていましたが、面倒なので30秒のままぶっ込みます。
files = tags_df.mp3_path.values
X = np.array([ mp3_to_array(file) for file in files ])
X = X.reshape(X.shape[0], X.shape[1], 1)

訓練データ、テストデータの準備

from sklearn.model_selection import train_test_split
random_state = 42

train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.2, random_state=random_state)

学習&テスト(7/9 改正)

モデル構築

Kerasを使ってみました。
元の論文とは違ってxの次元が465984次元と長いので、少しだけ層を深く積みます。


import keras
from keras.models import Model
from keras.layers import Dense,  Flatten, Input
from keras.layers import Conv1D, MaxPooling1D

features = train_X.shape[1]

x_inputs = Input(shape=(features, 1), name='x_inputs') # (特徴量数, チャネル数)
x = Conv1D(128, 256, strides=256,
           padding='valid', activation='relu') (x_inputs)
x = Conv1D(32, 8, activation='relu') (x) # (チャネル数, フィルタの長さ )
x = MaxPooling1D(4) (x) # (フィルタの長さ)
x = Conv1D(32, 8, activation='relu') (x)
x = MaxPooling1D(4) (x)
x = Conv1D(32, 8, activation='relu') (x)
x = MaxPooling1D(4) (x)
x = Conv1D(32, 8, activation='relu') (x)
x = MaxPooling1D(4) (x)
x = Flatten() (x)
x = Dense(100, activation='relu') (x) #(ユニット数)
x_outputs = Dense(50, activation='sigmoid', name='x_outputs') (x)

model = Model(inputs=x_inputs, outputs=x_outputs)
model.compile(optimizer='adam',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
model.fit(train_X1, train_y, batch_size=600, epochs=50)

計算グラフ可視化

''' pngへ出力 ''' 
from keras.utils.visualize_util import plot
plot(model, to_file="music_only.png", show_shapes=True)


''' interactiveに可視化 '''
from IPython.display import SVG
from keras.utils.visualize_util import model_to_dot
SVG(model_to_dot(model, show_shapes=True).create(prog='dot', format='svg'))

music_only.png

テスト

元の論文ではAUC: 0.87 ほどでしたが、今回の実験では0.66しか出ていません。
サンプルサイズを5分の1以下にしているので低く出ていまいますが、生の(かつ30秒のままの)音声データをそのまま食べさせてある程度予測が出来たのでよしとしましょう。

from sklearn.metrics import roc_auc_score
pred_y_x1 = model.predict(test_X1, batch_size=50)
print(roc_auc_score(test_y, pred_y_x1)) # => 0.668582599155

まとめ

  • 音声ファイルをndarrayに変換することができた。
  • 特徴量抽出なしのRAWファイルをぶっ込んでタグを予測することが出来た
  • もう少しで研究用環境が整うので、サンプル増やして試したいです。

  1. Sander Dieleman and Benjamin Schrauwen. End-to-end learning for music audio. In Acoustics, Speech and Signal Processing (ICASSP), 2014 IEEE International Conference on, pages 6964–6968. IEEE, 2014. 

  2. Edith Law, Kris West, Michael Mandel, Mert Bay and J. Stephen Downie (2009). Evaluation of algorithms using games: the case of music annotation. In Proceedings of the 10th International Conference on Music Information Retrieval (ISMIR) 


『 機械学習 』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

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