【18日目】様々な機械学習モデルを試す【Pythonで音楽系人工知能を作るまでの日記】

プログラミング

2023年6月26日

※手探りで学んでいるので、何か間違っている、冗長なところはあると思われます。本当に参考程度にしてください。

昨日の続きを。

とりあえず、それぞれのジャンルの確率を出してあげなきゃいけないのだけど、SVMは学習してできた関数が正か負かによって判定を出すものだから、確率を出すのは本質的じゃないらしい。一応、無理やり出す方法はあるっぽいんだけど、色んなモデルを経験したいので、今回は色んな機械学習モデルを試そう! なんちゃって交差検証編!にしたいと思う。

深層学習はまだちょっと置いといて、他の有名機械学習モデルをいろいろ試して、交差検証……といっても、いつも通りランダムにテストデータと学習データに分けるってのを100回やってその平均を見てみるものをやって、どのモデルがいいのかを見ていくよ。

さて、今回試す機械学習モデルだけど……
うーん。機械学習モデルがありすぎてどれを試せばいいか本当にわからん。

うーーーーーん……

なんだかんだ色々調べて、思ったのは「情報がマジでないから、いろいろ試そう」ということ。

ちょこっと調べたけど、今回は分類問題・教師あり学習・確率を出したい、が条件なのでこれ等の条件を満たす「決定木」「ランダムフォレスト」「勾配ブースティング決定木」「K近傍法」らへんをやってみる。

決定木の応用がランダムフォレストと勾配ブースティング決定木なので決定木はやんなくてもいい気するけど、基礎は大事だし、経験として。

勾配ブースティング決定木ってKaggleで定番のやつだよね? 自ら使う日が来るとは思わなかった。感動。

というか、「機械学習 分類 音」で調べたら自分のブログ出てきたわ。我ながら邪魔だ。本当に情報がないことがわかる。

出来ることならは人工知能学会みたいなとこの会員になって論文読んで~とかするのがいいと思うんだけど、ちょっと時間が足りないし、文系学生が出来るのかわからないので一旦がむしゃら戦法で行く。

先ずは決定木からやりますか。

決定木

モデルの詳しい説明は先人のわかりやすい記事と、少し理論的な記事にお任せして、とりあえず簡易な説明を。

少し決定木を学んでみて思ったのは。決定木が未だに使われてるのは、モデルの分かりやすさと、決定木で起きてることがブラックボックス化されてないからじゃないかな。と思うなどした。

以下が少し学んで得たもの。

  • 決定木自体は機械学習の手法ではなく、概念。私たちが選択する時のルールとして自分たちで組み立てて使う事もできる。しかし、便宜上今回は決定木と言ったほうがわかりやすいので、今回は決定木=決定木を作成する機械学習モデルとして扱う。
  • 決定木は選択肢をYes/No→閾値以上未満で分岐させていって分類する手法。
  • このYes/Noの判定の閾値を動的に決めて決定木を作る機械学習を決定木と言ってしまっている?
  • 深層学習と違い、決定木はどこでどう分岐して分類されているのかが分かりやすいので、説明が必要な時とかに重宝する。
  • 分類・回帰どっちも行ける。非線形も行けるが、あまり向いてはいない。

といった感じ?

間違っているところはあるかもしれないので、参考程度に。

では、実装していきたいんだけど、これもしかしてSVMのプログラムをmodel = DecisionTreeClassifier()にして、model.predict_proba(X_test)ってやれば各ジャンルに合う確率出る!? 保守性ってこういうことか。

とりあえず、決定木のMax階層を3に設定してやってみた。

[0.1047619  0.04761905 0.33333333 0.02857143 0.08571429 0.4       ]っていうのが、ある1つのテストデータがそれぞれのジャンルにこれだけ近い可能性がありますよっていう確率。この場合0.4のStabsに分類されて、次点が0.333…のLeadsっていう感じか。すんげえなこれ。

しかし、SVMと比べ正答率はやっぱり結構落ちている。Max3層にしてるからっていうのもありそうなので、5層にしてみる。

うーん。正答率は上がってない割に、多様性が減って結構極端に回答するようになった。

↓0の回答が多く、0.9以上の回答が増えた。

理想とするものは、音源に対し偏見なく「この音源はBassにもFXにも使えますね!」って言ってくれる機械学習なので、もし決定木でやるなら何層にするかが重要そう。

正直、多様性という意味で3層の決定木は悪くない気がする。ベース音突っ込んでみたら「この音はLeadで使えそうですね~」って判定するみたいなのも可愛くていいんじゃないだろうか。しかし、実用性には欠けるだろうので、他のも試す。

ランダムフォレスト

なんだぁ、ランダムフォレストって。

少し調べてみた感じ、バギング形式アンサンブル学習の結果を出す為に、多様性のある決定木を複数作ってその決定木で多数決をとる方法みたい。

はい、もう意味わからん。

専門用語で説明されると、ちょっと何言ってるのかわかんない状態に陥りがちではあるんだけど、分かりやすい記事があったのでバギングとアンサンブル学習の説明はそちらに任せて、大まかな説明を。

アンサンブル学習は複数の分類器(今回は決定木)で多数決を取って分類または回帰するというもの。バギングは、その複数の分類器を並列的に学習させることを言う。だから、ある程度学習の効率はいいのかな。

ここまではどの記事にも書いてあったから、何故バギングなのか、何故アンサンブル学習なのかみたいなところを知りたいんだけど、因果関係みたいなものになると情報がやっぱりない。バギングの論文とか読むと何か掴めるかもしれないんだけど、英語だけじゃなく、数学も入ってくると如何せん学習コストが高い。

とりあえず、やってみる。

やってみた結果、以下の通り。

やはり正答率は決定木より高いので、優秀。

多様性もある程度確保できており、素晴らしい。(優柔不断とも言う)↓

しかし、Colabの無料GPUを使ってるけど学習時間は時間がかかるようになってきていて、今まで2、3分で終わってたのが今回は5分半くらいになっている。

決定木を使うよりはランダムフォレストを使うほうが良さそうだね。

勾配ブースティング決定木

Kaggleで人気なあれ。勾配ブースティング決定木だとちょっと長いからGBDT(Gradient Boosting Decision Tree)と呼ぶことにする。

超おおざっぱに言うと、ランダムフォレストが並列で複数の決定木を学習させたのに対し、GBDTは直列で分類器を学習させる。直列だから、前の分類器が間違えたところを重点的に学習することができて、最終的に作った分類器に重みをつけて、そこから答えを導くといったもの。

先人の記事だと、これがマジでわかりやすい

さっき言った、直列で学習というのがブースティングというもので、前のモデルの間違ったところを重点的に学習するというのが、勾配降下法というもの。勾配降下法って深層学習でも使うやつだよね?

GBDTのモデルはscikit-learnにもあるんだけど、Kaggleとかで使われるXGBoostLightGBMを使いたい場合は別に入れる必要あり。

今回はとりあえずscikit-learnを使ってGBDTを実装する。

こちらの方の、scikit-learnのGBDTの使い方を見たんだけど、交差検証ってライブラリに実装されてたのか。わざわざforで回すのって結構アホなことやってたんだなこれ。
交差検証について調べてみると色んな意見が見られるので、単純なものではなさそう。
とりあえず、scikit-learnの機能にある交差検証を使ってGBDTを回してみる。

うーん。流石に学習が遅いなぁ……って思ったらこんな通知が。

いや、私はちゃんとGPUに設定したし、GPUに設定されていることも確認したぞ??

と思ったんだけど、処理時間がやけに長いから色々調べたんだけど……scikit-learnってもしかしてGPUに対応してない!?

SKlearnのF&Qによると「依存関係があーだこーだで、アルゴリズムである程度速くはなるから、GPUに対応する予定はないよ」と言っている。

まじか。知らなかった。
結構普通に対応してるもんだと思ってたよ私は。確かに、ローカル環境でGPUアリの深層学習を動かそうとすると面倒くさかった記憶があるから、色々あるんだろうなぁ。
じゃあ今まで意味もなくGoogleColabの無料GPU枠を使ってたのか。申し訳ない。

先にも紹介したXGBoostやLightGBMはGPUに対応しているらしいので、それを使うか?
でも、今思ったんだけどこれってもし、ソフトウェアとして配布する場合、GPUが無いと動かないソフトウェアになってしまうのだろうか?
そこら辺の知見がなさ過ぎて本当にわからない。別に学習させたモデルであればCPUだけで動くのか??

色々調べてやってみるしかないね。

やっと、32分29秒でGBDTの交差検証終了。k=5でやった結果は。

で大体平均は43%くらい。

結果としてはランダムフォレストとあまり変わらない結果に。
しかし、GBDTはハイパーパラメータを調整する必要があるっていうのと、XGBoost、LightGBMがあることを考慮すると、やっぱり調整さえすれば一番精度は高いのかなと思う。
というか、SVMが50%台叩き出してたのすごいんだなあれ。過学習してた説はあるけど。

最後にK-近傍法いってみよう。

K-近傍法

ちょっと疲れてきたので、K-近傍法の解説は先人の素晴らしい記事にお任せ。しかし、考え方は結構シンプルで面白いので、是非見てほしい。人間って色んなアプローチ考えるなぁ、すげえなぁと思う。

実践!

k=3~49でさっきの交差検証の方法で実施。

結果は、パーセントが最も高かったのがk=5の時で平均50%くらい。最小はk=47の時で46%くらい。
分類精度は結構良さげ。速度も50回くらいの実行が46秒で終わるので、滅茶苦茶早い。
なんか別に悪くない気がするんだけど、どうなんだろう。

k-近傍法に正直そこまで期待してなかったから、こうなるとは思わなかったんだけど、一応デメリットを挙げると、学習データが増えると計算量も増える&データの次元数が増えると精度が悪くなるといったものらしい。


今回は学習データが400程度だと思うので、少なくて爆速だったという訳だ。今回MFCCの次元数は40なので精度も悪くなかった? ということ?
というか、MFCCのどういった要素を特徴量にしているのかが直感的にわからなくて、そこらへんが何も見えないのはちょっと課題かもしれない。

ちょっとk=8で今まで通りの100回検証もしてみる。

結果は

という感じで、悪くない気がするぞ。

今回k=8なので各データの各ジャンル予想は0.125単位みたいになってる。

みたいな感じになってる。
使いやすくて滅茶苦茶いいと個人的には思う。

うーん。精度的に言えば最終的にGBDTがいいとしても、今回の目的と使い勝手を考えるとK-近傍法が結構魅力的に感じる。

結論

本当に素人の雑感としては今回の条件の場合、K-近傍法>ランダムフォレスト>=GBDT>決定木の順で、使いやすくて、精度も悪くないなと感じた。

K-近傍法に正直全然期待してなかったので結構驚きなんだけど、軽い+わかりやすい+精度もある程度良いことを考えると、今のところK-近傍法が一番有力かな。

これを、ソフトにして、自分の好きな音源を入れたらそれがどの確率が高いかというところを明日やろう。
一応バックエンドはこのままPythonで問題ないと思うんだけど、フロントエンド系の言語はSwiftと学校で習った程度のPHPとかしか技術がないので、そこが課題になるかなぁと思う。

理想は、Windowsのローカル環境で動くソフトウェアにすることなんだけど、叶うかはわからない。できるだけやろう。