[QoreSDK]人工知能はハーモニカの種類を聞き分けられるのか？

# はじめに
みなさんこんばんは。
Qiitaユーザーの中で最もハーモニカの所有数の多い男(推定)ことkon2です。

![harmonicastrim.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203101/c55b455c-465b-a0c4-8689-0c12308f69ab.jpeg)

日々いろんなハーモニカを吹いていて、思うんですよね。
実際、<b>メーカーや機種ごとに音、変わんなくない？</b>　って。

そう思って、同じリフを8つのハーモニカで録音してみました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">8本のハーモニカで同じブルースのリフを演奏したやつのまとめ。<br>Have you heard ‘Blues Harmonica Comparison’ by konkon on <a href="https://twitter.com/hashtag/SoundCloud?src=hash&amp;ref_src=twsrc%5Etfw">#SoundCloud</a>? <a href="https://twitter.com/hashtag/np?src=hash&amp;ref_src=twsrc%5Etfw">#np</a> <a href="https://t.co/jByNu6BI1t">https://t.co/jByNu6BI1t</a></p>&mdash; konkon (@konkon28983820) <a href="https://twitter.com/konkon28983820/status/1206397700771479553?ref_src=twsrc%5Etfw">December 16, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

う～ん・・・。
録音を聞く限りでは、正直あんまりわからない・・・。


本当に違いがあるのか確かめるために、人工知能(QuantumCoreのQoreSDK)にこの2つのリフを聞き分けてもらいます。
ちなみにQoreSDKを使ったまじめな記事は下にあります。こっちも見てね！

[QoreSDKを使ってリチウムイオン電池の劣化を予測してみた](https://qiita.com/kon2/items/0066d904dcf513b61b9e)

今回の内容も全部(音源も含めて)GitHubに投稿してます！

https://github.com/konkon3249/HarmonicaLearning

# データ概要

学習用データには2種のハーモニカ(SuzukiのManjiとHohnerのMarineBand)の以下の演奏を、

* Walles Coleman's Liff (29 sec)
* SecondLine Intro (12 sec)
* Juke Intro (23 sec)
* The Sailor & The Maid Intro (12 sec)

テスト用データは以下の演奏の別テイクを使います。

* Walles Coleman's Liff (29 sec)

#トレーニングデータの読み込み

以下のように、Manjiによる演奏のデータを取り込みます。

```python
path = glob.glob('./train/Manji/*.wav')
dataset = []
shapes = []
for p in path:
    sound = AudioSegment.from_file(p)
    data = np.array(sound.get_array_of_samples())
    dataset.append(data)
```

取り込んだデータを可視化するとこんな感じです。

```python
fig = plt.figure(figsize=(12,5))
plt.subplots_adjust(hspace=0.35)
for i in range(4):
    plt.subplot(2,2,i+1)
    plt.title(path[i])
    x_range = np.linspace(0,dataset[i].shape[0]-1,dataset[i].shape[0])
    plt.plot(x_range/44100,dataset[i])
```

![ダウンロード (56).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203101/101c77dd-328a-9c97-57bc-db5d0607e6af.png)

よく見る感じのデータになってますね。
ちなみにMarineBandの演奏はこちら。

![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203101/b6b2215b-c6b1-1b5e-6ce3-c7b07ba09814.png)

やっぱよくわかんない。
とりあえず4つしかデータがないのではよくないので、以下の関数で各演奏をだいたい1秒ごと(44000サンプルごと)に分割して、まとめます。

```python
# decは正解ラベル。0 or 1の値を入力。
def SplitTune(dataset,dec,width = 44000):
    print('Width:',width)
    dataset_separate = []
    for n,d in enumerate(dataset):
        start = int(d.shape[0]*0.01)
        end = int(d.shape[0]*0.99)
        num = int((end-start)/width)
        print(start,end,num)
        for i in range(num):
            hoge = d[(start+(i*width)):(start+(i*width))+width]
            if(len(hoge) == width):
                dataset_separate.append(hoge)
            else:
                pass
    dataset_separate = np.array(dataset_separate)
    answer = np.zeros(dataset_separate.shape[0])+dec
    print('Shape of separated dataset:',dataset_separate.shape)
    return(dataset_separate,answer)

```

正解データ(y_train)は、0がManji, 1がMarineBandに対応するようにします。

```python
X_train_manji,y_train_manji = QoreTrain.SplitTune(dataset,dec=0)
```

# テストデータの読み込み
トレーニングデータの読み込みと同様です。
今回は、別テイクのWallas Coleman's Riffを使います。
可視化するとこんな感じ。この2つを同様に44000サンプルで分割して、それぞれ分類します。

![ダウンロード (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203101/72072c9d-529a-2fc3-4896-d21b0f356aec.png)

このリフ、昔はYouTubeで公開されていたんですが、今は非公開になっちゃったんですよね。
かわりに同じ人物の超かっこいい演奏を貼っておきます。
https://www.youtube.com/watch?v=aMHjCT9Y2bs

# データの前処理

パラメータを除けば、ほぼ以下の記事と同様です。
[QoreSDKの紹介とQoreで不整脈検出](https://qiita.com/sk1010k/items/d8ca3332e6a1f1f939a1)

まず、トレーニング用、学習用データをそれぞれまとめます。
ついでに次元も確認。

```python
X_train = np.vstack((X_train_manji,X_train_marine))
y_train = np.hstack((y_train_manji,y_train_marine))
print('X_train.shape:', X_train.shape)
print('y_train.shape:', y_train.shape)

>> X_train.shape: (157, 44000)
>> y_train.shape: (157,)

X_test = np.vstack((X_test_manji,X_test_marine))
y_test = np.hstack((y_test_manji,y_test_marine))
print('X_train.shape:', X_test.shape)
print('y_train.shape:', y_test.shape)

>>X_train.shape: (58, 44000)
>> y_train.shape: (58,)
```

まずは、この細切れにした音声データを、さらに分割します。

```python
width = 11000
stepsize = 2000
X_train = sliding_window(X_train, width, stepsize)
X_test = sliding_window(X_test, width, stepsize)
print('X_train.shape:', X_train.shape)
print('X_test.shape:', X_test.shape)

>> X_train.shape: (157, 17, 11000)
>> X_test.shape: (58, 17, 11000)
```

その後、qore_sdk.utilsのFeaturizerを使って、分割されたそれぞれのデータから20次元の特徴量を抽出します。

```python
n_filters = 20
featurizer = Featurizer(n_filters)
X_train = featurizer.featurize(X_train, axis=2)
X_test = featurizer.featurize(X_test, axis=2)
print('X_train.shape:', X_train.shape)
print('X_test.shape:', X_test.shape)

>> X_train.shape: (157, 17, 20)
>> X_test.shape: (58, 17, 20)
```

# QoreSDKを用いた学習

username, password, endpointは申請が必要です。
詳細は:point_down:
[深層学習以外の機械学習と応用技術 by QuantumCore Advent Calendar 2019](https://qiita.com/advent-calendar/2019/quantumcore_reservoir)

```python
client = WebQoreClient(username, password, endpoint
client.classifier_train(X_train, y_train)
```

まずはトレーニングデータがうまく学習できているかをsklearn.metricsのclassification_reportで検証します。

```python
res = client.classifier_predict(X_train)
report = classification_report(y_train, res['Y'])
print(report)
>>              precision    recall  f1-score   support

         0.0       0.95      0.91      0.93        79
         1.0       0.91      0.95      0.93        78

   micro avg       0.93      0.93      0.93       157
   macro avg       0.93      0.93      0.93       157
weighted avg       0.93      0.93      0.93       157
```

とりあえず学習はできてる、かな？
ではテストデータでの検証です。

```python
res = client.classifier_predict(X_test)
report = classification_report(y_test, res['Y'])
print(report)

>>              precision    recall  f1-score   support

         0.0       0.86      0.83      0.84        29
         1.0       0.83      0.86      0.85        29

   micro avg       0.84      0.84      0.84        58
   macro avg       0.85      0.84      0.84        58
weighted avg       0.85      0.84      0.84        58
```

F1スコアで0.84！　これは結構いいんじゃないでしょうか？
少なくとも自分の耳よりは……。

では、分類結果を可視化してみます。
青色が演奏のうちハーモニカの機種を正しく見分けられた部分、赤色が見分けられなかった部分です。

![ダウンロード (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203101/1529e2dc-5223-4688-c1af-d15b6edc247f.png)
![ダウンロード (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203101/682c5365-726f-6bf4-f606-e572c55e900d.png)

1分ちょいのトレーニングデータで、人工知能(QoreSDK)にはハーモニカの機種が聞き分けられるみたいです。

# まとめ

というわけで、ちょっとしたお遊びでした。
さすがQoreは音声処理が得意というだけあり、ちょっとのデータですが一応結果を出すことができました。
実際のところ学習はちょっと不安定で、うまくいったりいかなかったりなので、データを増やすかパラメータの調整が必要だと思います。
(そのためにももっと演奏のレパートリーを増やさなければ……)


![20191214_040520997_iOS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203101/8cceb6ef-d04a-40fc-aa7e-fd9e0a3371b6.jpeg)


将来的には8つのハーモニカ全部で多クラス分類でもやってみたいですね。
あと、木製ボディとプラスチックボディで違いはあるのかとか、リードの材質(真鍮 or ステンレス)を見分けられるのかとか、演奏者ごとの音色にどんな特徴があるのかとか、興味は尽きません。

今後もちまちまと遊びつつ、音響処理について勉強もしていきたいなと思います。

それでは～