music2vecを用いた音楽ジャンル分類モデル

# はじめに
[Rajat Hebbarの記事](https://medium.com/@rajatheb/music2vec-generating-vector-embedding-for-genre-classification-task-411187a20820)を参考にして、music2vecを用いた音楽ジャンル分類モデルを実装しました。

実装のコードは[Github](https://github.com/KMASAHIRO/music2vec)に公開してあります。
[Google Colaboratory](https://colab.research.google.com/drive/1TlhN6ZW9ytXwIsxFFB0fYdUSfuz5DwLz?usp=sharing)上にモデルの実装、学習、評価を簡単に実行できるようにまとめてあります([Github](https://github.com/KMASAHIRO/music2vec)のmusic2vec.ipynbと同じもの)。

- 追記(2021/04/25)  
関連記事  
[DANet(Deep Attractor Network)の実装と解説](https://qiita.com/KMASAHIRO/items/3b87fd67949f3445b23b)  
[DANetとmusic2vecによるノイズ除去と音楽ジャンル分類](https://qiita.com/KMASAHIRO/items/85023b7a999aa46751c6)

- 追記(2024/05/14) 
GTZANのリンクが[切れていた](http://opihi.cs.uvic.ca/sound/genres.tar.gz)ので、[別リンク](https://www.kaggle.com/datasets/andradaolteanu/gtzan-dataset-music-genre-classification?resource=download)に変更しました。

# 概要
1. [実行したPythonのパージョンと使用したパッケージ](#1-実行したpythonのバージョンと使用したパッケージ)
2. [使用したデータ](#2-使用したデータ)
3. [モデルの構成](#3-モデルの構成)
4. [結果と評価](#4-結果と評価)
5. [パッケージとしての利用](#5-パッケージとしての利用)


# 1. 実行したPythonのバージョンと使用したパッケージ
- Python 3.7.10
- TensorFlow 2.4.1  
モデルの構築に利用
- numpy 1.19.5  
各種計算、配列処理等に利用
- librosa 0.8.0  
音声のファイルからのロード、リサンプリングといった音声処理に利用

# 2. 使用したデータ
[GTZAN](https://www.kaggle.com/datasets/andradaolteanu/gtzan-dataset-music-genre-classification?resource=download)をデータとして使用しました。
1000個の音楽データの内950個を訓練データとして学習させ、50個をテストデータとして用いました。
[SoundNetの論文](https://arxiv.org/pdf/1610.09001.pdf)3ページ目の"2 Large Unlabeled Video Dataset"に従い、入力音源はサンプリングレート22050Hzにし、-256から256までの範囲の数値にしました。

<!--
GTZANのリンク(切れている)
http://opihi.cs.uvic.ca/sound/genres.tar.gz
-->


# 3. モデルの構成

<img width="500" alt="article" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896745/3a0bdc58-6c6e-be59-912e-4b6e8abf0d5e.png">

[Rajat Hebbarの記事](https://medium.com/@rajatheb/music2vec-generating-vector-embedding-for-genre-classification-task-411187a20820)で紹介されている上の写真のモデルをもとに、下のモデルを作成した。

<img width="800" alt="model_architecture" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896745/7d9ab4c4-71de-7766-bf4e-d5db19e746ac.png">

SoundNetベースのCNNを実際のSoundNetに変えたのが主な変更点です。
それによりCNNの層が増えて入力を長くする必要が出てきたため、入力サイズが大きくなりました。

# 4. 結果と評価
学習の10epochs後と20epochs後に50個のテストデータで推論させて混同行列の作成とAccuracy・Precision・Recall・F1の求値を行いました。

<img width="1000" alt="confusion_matrix" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896745/c59b27f2-cf99-d62c-2999-4917317424bf.png">

ここで、Precision・Recall・F1の値は各ラベルごとの値をデータ数に応じて重み付けをして平均したものです。例えば、下のような混同行列であれば下の計算式によりPrecisionはおよそ0.58になります。

<img width="500" alt="example_matrix" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896745/ce359602-2a62-0936-59f9-6b746fa2b955.png">

```math
\frac{10}{19}\times\frac{15}{50}+\frac{12}{18}\times\frac{25}{50}+\frac{6}{13}\times\frac{10}{50}\fallingdotseq0.58
```


また、学習前と学習後でモデル中のSoundNetの部分の出力を平坦化したものをPCAやt-SNEで可視化しました。
学習後ではt-SNEでジャンルごとにある程度分離されていることがわかります。特にclassicalやmetalはよく分離されています。

<img width="1000" alt="analysis" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896745/dd910225-2566-7def-fbe9-125d614f31a0.png">

# 5. パッケージとしての利用
[Githubに載せた実装](https://github.com/KMASAHIRO/music2vec)をパッケージとして利用することで、[GTZAN](https://www.kaggle.com/datasets/andradaolteanu/gtzan-dataset-music-genre-classification?resource=download)に含まれる音楽のジャンル分類を学習させることが簡単にできます。

また、データ処理に関する関数をすべてそのまま使うことはできなくなりますが、パッケージを利用することで他のデータを用いてこのモデルに音声分類させることも簡単にできます。

1. パッケージのインストール、インポート

    ```
    $pip install git+https://github.com/KMASAHIRO/music2vec
    ```
    ```python
    import music2vec
    ```

2. GTZANデータセットの用意

    ```
    # (注意!)以下のリンクは切れているので、新しいリンク(https://www.kaggle.com/datasets/andradaolteanu/gtzan-dataset-music-genre-classification?resource=download)にしてダウンロードしてください。パスも少し変わります。
    $wget http://opihi.cs.uvic.ca/sound/genres.tar.gz
    $tar -zxvf genres.tar.gz
    ```

3. データの前処理
    
    ```python
    # データをシャッフルして訓練データとそのラベル、テストデータとそのラベルを用意する
    # genres_pathはGTZANデータが含まれるgenresディレクトリのパス、testdata_numはテストデータの数
    train_filenames, test_filenames, train_labels, test_labels = music2vec.data_preparation.gtzan_preparation(genres_path="genres/", testdata_num=50)
    ```

4. モデルを構築

    ```python
    model = music2vec.music2vec.create_model()
    ```

5. モデルの学習

    ```python
    # 訓練後のモデルを返す
    model = music2vec.music2vec.train(model=model, train_filenames=train_filenames, train_labels=train_labels, batch_size=25, epochs=20)
    ```

6. テストデータによる推論

    ```python
    # テストデータとなる音楽をロードして前処理する
    test_inputs = list()
    for file in test_filenames:
        test_inputs.append(music2vec.data_preparation.load_audiofile(file))
    test_inputs = np.asarray(test_inputs)

    # 推論
    result = model.predict(test_inputs, batch_size=25)
    
    # Accuracyを求める
    m = tf.keras.metrics.CategoricalAccuracy()
    m.update_state(test_labels, result)
    print(m.result().numpy())
    ```

# おわりに
[Rajat Hebbarの記事](https://medium.com/@rajatheb/music2vec-generating-vector-embedding-for-genre-classification-task-411187a20820)を参考にして、music2vecを用いた音楽ジャンル分類モデルを実装しました。

記事ではテストデータでの精度は66.32%となっており、今回の結果はおよそ62%であるので少し低い結果となりました。
しかし、データセットの違いにより

・分類ジャンル数が記事では8つなのに対して今回は10個で分類をしている
・記事のモデルでは入力が小さいこともありおよそ158,200個のデータを使用しているのに対し、今回は1,000個のデータを使用している

という違いがあるので、今回の結果は悪くないと考えられます。

今回作成したパッケージを使い、ぜひ様々な音声分類をしてみてください。
不明な点、実装コードに関するアドバイス、パッケージとして利用する際の問題などありましたらコメントお願いします。

(この記事は研究室インターンで取り組みました：https://kojima-r.github.io/kojima/)