hama-matcha’s blog

思ったことを書き残すモノ

続 ピアノの音判別をしてみた

はじめに

前回はドとレだけの判別でしたが今回はド、レ、ミ、ファ、ソ、ラ、シの7音階をクラス分類していきます。

作成したもの

GitHubにおいてます。

詳細

データセット

生成方法 : Garage Band の Steinway Grand Piano
高さ: C0~C5
ベロシティ(音の強弱) : 86, 96, 106, 116 データ数 : 24個ずつ(全168個)
データセットの分け方 : 学習 : チューニング : テスト = 17 : 5 : 2

import random

random.seed(5)

piano_notes = ['do', 're', 'mi', 'fa', 'so', 'ra', 'si']
piano_all_sounds = list(range(24))

piano_train_sounds = random.sample(piano_all_sounds, 17)

set_tune = set(piano_all_sounds) - set(piano_train_sounds)
piano_tune_sounds = random.sample(list(set_tune), 5)

set_test = set(piano_all_sounds) - set(piano_train_sounds) - set(piano_tune_sounds)
piano_test_sounds = random.sample(list(set_test), 2)

print("all_sounds : {}".format(sorted(piano_all_sounds)))
print("train_sounds : {}".format(sorted(piano_train_sounds)))
print("tune_sounds : {}".format(sorted(piano_tune_sounds)))
print("test_sounds : {}".format(sorted(piano_test_sounds)))

前処理

データセットをランダムで抽出固定したいためrandom.seedを使いました。
LibROSAを用いてmfcc(メル周波数ケプストラム係数)を抽出しています。これは音声データをそのまま使うと次元がとても大きくなり処理が大変なため次元を圧縮して使いやすくしようという考え方です。ついでに音声の特徴も出やすいため、mfccを採用しています。

import scipy.io.wavfile as wav
import librosa
from sklearn.svm import SVC
import numpy

def get_mfcc(fname):
    y, sr = librosa.load(fname)
    return librosa.feature.mfcc(y, sr)

if __name__  ==  '__main__':

    piano_note_training = []
    piano_sound_training = []

    for piano_note in piano_notes:
        print('Reading data of {}...'.format(piano_note))
        for piano_sound in piano_train_sounds:
            
            # get mfcc 173次元
            mfcc = get_mfcc('{}/{}{}.wav'.format(piano_note, piano_note, piano_sound))
            piano_sound_training.append(mfcc.T)
            
            label = numpy.full((mfcc.shape[1], ), 
                               piano_notes.index(piano_note), dtype=numpy.int)
            piano_note_training.append(label)
    
    piano_sound_training = numpy.concatenate(piano_sound_training)
    piano_note_training = numpy.concatenate(piano_note_training)
    print('done.\n')

学習&チューニング&テスト

この部分は一気にやっています。
理由としては学習の際にSVCのみを使用しているため、gamma値の違いで結果が変わるからです。
なので学習、チューニング、テストを一気に行っています。

gamma_list = [1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7]

for gamma in gamma_list:
    print('\n----- gamma={} -----\n'.format(gamma))
    svc = SVC(gamma = gamma)
    svc.fit(piano_sound_training, piano_note_training)
    print('----- Learning Done -----\n')

    # 正答率
    sounds_num = 0
    correct_sounds = 0
    correct_rate = 0.0

    print("----- tune -----")
    for piano_note in piano_notes:
        for piano_sound in piano_tune_sounds:
            sounds_num += 1
            mfcc = get_mfcc('{}/{}{}.wav'.format(piano_note, piano_note,piano_sound))
            prediction = svc.predict(mfcc.T)
            counts = numpy.bincount(prediction) 
            result = piano_notes[numpy.argmax(counts)] # 音階の判定
            original_title = '{}'.format(piano_note)

            if result == original_title:
                correct_sounds += 1
                
    correct_rate = correct_sounds / sounds_num
    print('{} : correct rate : {}%.'.format(gamma,correct_rate*100))
    
    # 正答率
    sounds_num = 0
    correct_sounds = 0
    correct_rate = 0.0
    
    print("----- test -----")
    for piano_note in piano_notes:
        for piano_sound in piano_test_sounds:
            sounds_num += 1
            mfcc = get_mfcc('{}/{}{}.wav'.format(piano_note, piano_note,piano_sound))
            prediction = svc.predict(mfcc.T)
            counts = numpy.bincount(prediction) 
            result = piano_notes[numpy.argmax(counts)] # 音程の判定
            original_title = '{}'.format(piano_note)

            if result == original_title:
                correct_sounds += 1

    correct_rate = correct_sounds / sounds_num
    print('{} correct rate : {}%\n\n.'.format(gamma, correct_rate*100))

出力結果

----- gamma=0.1 -----

----- Learning Done -----

----- tune -----
0.1 : correct rate : 48.57142857142857%.
----- test -----
0.1 correct rate : 42.857142857142854%

.

----- gamma=0.01 -----

----- Learning Done -----

----- tune -----
0.01 : correct rate : 74.28571428571429%.
----- test -----
0.01 correct rate : 50.0%

.

----- gamma=0.001 -----

----- Learning Done -----

----- tune -----
0.001 : correct rate : 94.28571428571428%.
----- test -----
0.001 correct rate : 100.0%

.

----- gamma=0.0001 -----

----- Learning Done -----

----- tune -----
0.0001 : correct rate : 91.42857142857143%.
----- test -----
0.0001 correct rate : 92.85714285714286%

.

----- gamma=1e-05 -----

----- Learning Done -----

----- tune -----
1e-05 : correct rate : 77.14285714285715%.
----- test -----
1e-05 correct rate : 64.28571428571429%

.

----- gamma=1e-06 -----

----- Learning Done -----

----- tune -----
1e-06 : correct rate : 42.857142857142854%.
----- test -----
1e-06 correct rate : 21.428571428571427%

.

----- gamma=1e-07 -----

----- Learning Done -----

----- tune -----
1e-07 : correct rate : 20.0%.
----- test -----
1e-07 correct rate : 0.0%

感想

gamma=1e-3がとても良い結果だったテストが14個しかないから正答率100%でもゆるして・・・
データを三分割することによってより正確な判定が行えたと思う。
はじめは学習、チューニング、テストを分けてやっていたがそれは良くないと指摘を受けたため一度にすべてのことをするようにした。NNやDNNだとこの方法は使えないためモデルの保存を考えていきたい。

Pythonのrandom.seedでデータセットをランダムに分ける

はじめに

今回はデータセットをランダムに分ける時random.seedを使用すると便利だったので書き残しときます。

抽出

0~23までの数値を17 : 5 : 2 の24個のデータから重複なしで値を抽出します。
順番は17個抽出、5個抽出、2個抽出します。
3分割している理由は 学習用 : チューニング用 : テスト用 です。

コード

# ランダムな整数値の生成(0~24) seed有り
# 24個の数値を17 : 5 : 2 でランダムに分ける

import random
random.seed(1) # seed一度ランダム抽出された値を固定

all_list = list(range(24))
random_a = random.sample(all_list, 17)
print("a_list : {}".format(sorted(random_a)))

set_all_a = set(all_list) - set(random_a)
list_all_a = list(set_all_a)
random_b = random.sample(list_all_a, 5)
print("b_list : {}".format(sorted(random_b)))

set_a_b = set(all_list) - set(random_a) - set(random_b)
list_a_b = list(set_a_b)
random_c = random.sample(list_a_b, 2)
print("c_list : {}".format(sorted(random_c)))

見やすいように一応昇順ソート。
random.seedの引数を変えることにより固定する値を変更できます。

結果

a_list : [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 19, 22]
b_list : [11, 13, 17, 20, 21]
c_list : [5, 23]

終わりに

enumerate関数と併用するといい感じかも?

ピアノの音判別をしてみた

はじめに

今回はクラス分類の練習として、ピアノの単音(ドとレ)の判別器を作ったのでいろいろと書き残していきます。

作成したもの

GitHubにおいてます。

必要そうな説明

データセット(zipで固めておいています)

  • ドとレの音源
    生成方法 : Garage Band の Steinway Grand Piano
    高さ: C0~C5
    ベロシティ(音の強弱) : 86, 96, 106
    データ数 : 18個ずつ(36個)
    学習と評価比率 : 学習:評価 = 9:1

前処理

LibROSAを用いてmfcc(メル周波数ケプストラム係数)を抽出
抽出の際設定はデフォルトのままなのでサンプルレートは22050Hz
学習で使用する音声データからmfccとlabel(0がド, 1がレ)を抽出

import scipy.io.wavfile as wav
import librosa
from sklearn.svm import SVC
import numpy

def get_mfcc(fname):
    y, sr = librosa.load(fname)
    return librosa.feature.mfcc(y, sr)

if __name__  ==  '__main__':

    piano_notes = ['do', 're']
    piano_sounds = list(range(16))

    piano_note_training = []
    piano_sound_training = []

    for piano_note in piano_notes:
        print('\nReading data of {}...\n'.format(piano_note))
        for piano_sound in piano_sounds:
            print('{}/{}{}.wav'.format(piano_note, piano_note, piano_sound))
            
            # get mfcc
            mfcc = get_mfcc('{}/{}{}.wav'.format(piano_note, piano_note, piano_sound))
            piano_sound_training.append(mfcc.T)
            
            label = numpy.full((mfcc.shape[1], ), 
                               piano_notes.index(piano_note), dtype=numpy.int)
            piano_note_training.append(label)
    
    piano_sound_training = numpy.concatenate(piano_sound_training)
    piano_note_training = numpy.concatenate(piano_note_training)
    print('done')

学習と評価

SVCを使用し学習をさせる。(今回は線形ですが非線形の学習にも対応したいため)
残りの評価用データを用いて判定
チューニングは

C = 1 # デフォルト
gamma = 1e-3 

となった。

# gammaの値を変更 * 1e-3より正しく分けられている
svc = SVC(gamma = 1e-3)
svc.fit(piano_sound_training, piano_note_training)
print('Learning Done')

piano_sounds_test = list(range(16,18))

for piano_note in piano_notes:
    for piano_sound in piano_sounds_test:
        print('piano test sound {}{}'.format(piano_note, piano_sound))
        mfcc = get_mfcc('{}/{}{}.wav'.format(piano_note, piano_note,piano_sound))
        prediction = svc.predict(mfcc.T)
        counts = numpy.bincount(prediction) 
        result = piano_notes[numpy.argmax(counts)] # 音程の判定
        original_title = '{}'.format(piano_note)
        print('original note is {}. Prediction of note is {}'.format(original_title, result))

評価結果

Learning Done
piano test sound do16
original note is do. Prediction of note is do
piano test sound do17
original note is do. Prediction of note is do
piano test sound re16
original note is re. Prediction of note is re
piano test sound re17
original note is re. Prediction of note is re

ちゃんと分けることが出来ました!

今後の課題

今回はデータセットを学習:評価のみで分けていましたがハイパーパラメータのチューニングも必要なので学習:チューニング:評価で分ける必要がありそうです。
次は[ド、レ、ミ、ファ、ソ、ラ、シ]のクラス分類に挑戦してみます。
データ数も足りないのでデータセットのとり方も調整が必要ですね。
機械学習してるのかな〜っと思いながらまだ出来てないので頑張ります・・・

PyConJPにPythonの可能性を求めるのは間違っているのだろうか(後編)

~はじめに~

この記事は後半単体でも読めますがよければ前半も見てください。

 

Keynote

磯蘭水さんの発表はPythonで音楽を奏でることを題材にされていました。諸事情で遅れてしまい後半のお話だけ聞いていたのですが、考え方のして大事だなっと感じたことを上げておきます。

 

動くいいライブラリはどんどん使うOSSのことを指しているのかなと思いました。自分ですべて作るのはすごいことですが、時間が限られている中でモノを作り出すには、人の既にできているモノを組み合わせて作る必要があります。なのでこの考え方は大事なのかなと感じます。

めんどうは自動化して面白そうは人がするは当たり前だけどなかなかできないので、早く実践に移したいです。何かを作るときに、本質に関係ない環境構築は、自動化することが身近な目標ですかね・・・

プログラムは何度でもやり直せる作品は「何かを想像して出力まで作り出す」という点では芸術と同じなのですが、その過程で「プログラムは何度でもやり直せる」という強みを知っておくべきだと思いました。なので、動くものを短期間で作って改善していく工程は、身につけると強くなれそうな感じがします・・・。

複雑なものは簡単なものに分解するは複雑な構造は一度に処理するのではなく、単純な構造まで落とし込むのが大事だと感じました。逆に単純な構造を組み合わせて複雑にしていくことも大事だと感じました。

技術勉強ではなく、したい!という気持ちが大事はやっぱりそうだなって感じです。私も勉強ではあまり知識として覚えることができないのですが、したいことに向けての知識はどんどん吸収できていると感じています。ただ、複雑なことを一気にする傾向があるため、上の複雑なものは簡単なものに分解するを適応して頑張りたいです。

 

~SymPyによる数式処理~

このセッションではHayao SuzukiさんがSymPyのいいところについて話していました。冒頭で「数学ヤバい人は逃げてね」と言われていたので逃げたいなぁーっと思いながら、部屋の前列でドアから一番遠い位置だったので、あきらめて聞きました。数式は摩訶不思議なものが多かったですが、SymPyの強みである記号を使って人間が分かりやすい数値(記号)などで出力してくれるのはとても助かるなっと感じました。

 

~お昼~

 今回のお昼は汽車弁当をいただきました!やっぱり海苔がのってるのはうまい!

 

Pythonでざっくり学ぶUnixプロセス~

このセッションではtell-kさんがUnixのプロセスについて、Pythonを使用しながら説明をされていました。OSの知識なしに働き始めるととても苦労すると話されていたので、私は学生のうちにある程度学んでおかなければ・・・と感じています。「なるほどUnixプロセス」という本がとっかかりやすいらしいので、読みましょ読みましょ!

 

Working With Unix Processes (English Edition)

Working With Unix Processes (English Edition)

 

 なぜかAmazonさんでは英語版しか出てこないんですよね・・・

 

~おやつタイム~

待ち望んでたおやつタイムです!今回はちゃんとゲットできました。

女性受けを狙ったのかとにかく可愛いお菓子がたくさんありました。

 

~1次元畳み込みフィルターのオートエンコーダ~

このセッションでは朝倉涼太さんが、音楽データの容量をオートエンコーダを用いて下げる試みをされていました。デモでは音は少しこもっていましたが、学習済みのオートエンコーダを用いて、学習したことのない音声データも、音が壊れることなく圧縮出来ていたのがすごかったです。音楽だけでなく音声にも適応できそうな気がしたので、試してみたいところです。

 

~最後に~

Pycon JP お疲れさまでした!私は初めて参加したので、勢いがすごくとても疲れました。でもほんとにPythonが好きな人たちが多く、初心者も上級者も関係なく話せるといったのは、とてもいい空間でした。ただ、会場が全体的にちょっと寒かったのと、学生とほぼエンカウントできなかったのが残念です。あと、知識不足も大きく知れたので、来年に向けてインプットをしていかなければ!っと感じています。強くなってPyconに参加します。それではまた来年!

PyConJPにPythonの可能性を求めるのは間違っているのだろうか(前編)

結論:間違ってないです!

〜はじめに〜

 こんにちは、みなさん!hama-matchaです。今回はPyCon JPに行ってきました!

会場の開演が9:00からだったので少し早めに行って待とうと思ったらすごい行列が出来てました!

早速HPが削られましたね。

なんとか並んで入ったらまだ朝食が余っていてのでいただきました!

 

Keynote

 さて、まずはManuel Kaufmannさんの講演を聞きました!英語でのプレゼンだったので、通訳用のレシーバを借りることが出来たのですが、知らずにそのまま聞きました!おかげでほとんどわからなかったですが、print "Hello world"を物理的に各地へ伝えに行ったすごい人ということが印象に残りました。

 

〜お昼時〜

 一旦下に降りてお昼からのクエストボード一覧の確認ですね!

それと、お昼ご飯!

 

午後からはクエストボードで決めた各クエストに行って来ました。

 

〜PyCharm実践入門〜

このセッションではKashun YoshidaさんがDjangoを使ってpycharmの実践的な操作を学ぶことを登壇されてました。部屋に入ったら学生がほとんどいなかったのでちょっとびっくりしました。ただ講演を聞いていると一番重要なのはPycharmのバグは invalidate Caches/Restartしようということでしたね!やっぱり便利なところとかは聞くのも大事ですがほとんどチュートリアルにあるので使ったらできるぜ!っていう実演がとても良かったです!環境構築で時間かかるのは辛いですしね〜(よく完全敗北する)

 

Pythonを使ったハードウェア開発〜

このセッションでは北神雄太さんがPythonでハード以外のすべての部分をまかなえるよ!っということをデモを含めて登壇されていました。その中で印象に残ったのが北神さんのスライドの進め方です。少しづつ目に見える形でアウトプットを繰り返して「それで? or それで何ができるの?」と自問自答して自身が作られていた作品をより進化させていく過程が聞いてて「なるほど!」ってなりました。また、ハードウェアでどのOSでも動作が保証されているところが個人的にはすごいなと思いました。「まずはPythonで試してみる!」とても大事な言葉です。

 

〜LT&Party〜

LT会の規模が違いすぎてただただ、どこで聞こう??ってなってました。

少し興味を引いたのが、Twitterの文章を解析してそのアカウントの気持を知る、という取り組みの中でエゴグラムという言葉ですね。

そして最後にPartyで美味しいものをたくさん食べデザートもたくさんいただきました〜

風邪がなかなか治らないので辛いですが後半も頑張って聞きに行きます。

俺の初インターンがこんなに忙しい訳がない。

〜はじめに〜

今回始めてブログを書きますhama-matchaです。いきなりなんですが、ブログを書こうと思ったのがインターン先の人に「アウトプットは早いうちに絶対したほうが良いよ!」と教えられたので書いてみようと思いました。

 

そして、今回行ってきたインターン先はエウレカのサマーインターンです。

 

 〜Welcome Party〜

自分はAIエンジニアとして参加しました。

印象的だったのがメンターさんの紹介時に「AIチームの人達は脳死するほど考えてもらいます」みたいなことを言われたことです。「初インターンでヤヴァイしねるな!」っと思いつつ、半分打ち解けるために冗談なのかな、っと思ってその時は聞いていました。

 

〜一週間目〜

一週間目の課題は青空文庫の文章データを渡され「一週間で分類またはクラスタリングのモデルを作ってね」という課題でした。ここで一番の課題が前処理の難しさを知ることが出来ました。この週はとにかく動くものを要求されたので、先に少量のサンプルデータで動くモデルをつくりその後データの特徴量選定と適切なパラメータを探す作業をしました。

 

〜二週間目〜

 二週間目の課題は「よりよい自己紹介とは?」と抽象度の高い問いかけをされ、チーム全体で課題を設定し問題を解決するというチーム課題でした。ここでは最初の課題設定を少しでも見誤ってしまうと、ユーザのことを考えない自己満足な作品が出来てしまう難しい課題でした。この課題からは、チーム開発における課題設定の背景を、データで証明しつつ開発していくことが非常に重要だと思いました。

 

 ここで大きく学べたことはSQLでした。普段はデータがほとんど無く、自分で作ってSQLを操作するのは、コストがかかりしなかったのですが、企業が貯めた大量のデータを見ながら、クエリを叩くのは気持ちがよく勉強になりました。

 

〜二週間の講義を通して学んだこと〜

 このインターンではほぼ毎日業務内に講義が入っていたので、印象に残った部分を自分の経験と混ぜつつ書いていこうと思います。

 

 理論を考えることは大事だがまずは手を動かして動くものを作るは二週間ずっと持ち続けた考え方です。どうしても理論をしっかり構築しないと動けないことがあるので、まずは小さく理論を考えて小さく作って動かすが大事でした。これを繰り返すと自分の中の「考える -> 作る」が早くなり結果的に同じ期間内でも大きな成果を出せるようになっていくと感じました。

 

 モノづくりにおいて重要なのが作り込む熱と第三者人たちの意見です。これは、相手に自分のアイデアを伝えるとき、必要となります。インターン中、欠けていたのは第三者たちの意見でした。二週目の課題においてチーム全体の熱はあったのですが、課題の軸となる部分の裏付けが客観的に判断していなかったため、スライドでまとめた際にツッコミどころの多い資料となってしまいました。いくらスライドを見やすくしても、この部分は隠せないのでしっかりと考える必要があります・・・(一敗)

 

 時間計画をちゃんと立てようは大雑把にすると後でデスマになります(一敗)。時間計画を緻密に立てることは難しいですが、時間管理のマトリックスを使って、本当にその実装は必要なのかどうか。これを決めることは大事です。余談ですが時間管理はみんなが常に見えるところに置きましょう。ホワイトボードとかのアナログ系が良いです。デジタルだと失敗があったので・・・

時間管理のマトリクス図

f:id:hama-matcha:20180916160632p:plain

 狭い意見に固執せずたまには広い意見を取り入れてみようは二週目の課題で取り入れるべきだと強く感じました。機械学習において目的のデータは多ければ多いほど、良いのですが、条件を強く固定するとデータ数がとても少なくってしまいます。こうなってくると、自分たちが作ったモデルが悪いのかどうか、またはデータの前処理が間違っているのかが、判断ができなくなります。なので広い意見を取り入れてデータ数を多くすることがとても良いです(一敗)。

 

 専門用語をちゃんと理解して一般の人たちにも聞きやすいスライドを作るは発表時に意見を頂いて初めて気づけたことです。情報系に3年も接していると専門用語ってとっても多くなりますよね?同じ界隈の人と話をするときにはとても便利なのですが、一般の方と話をするときは、全く通じずストレスが貯まりますよね?自分の経験上聞いている方もストレスがたまります。これではお互いに苦しいだけなので、言葉を選ぶのが大切です。と言っても自分は一昨日理解したばかりです。なので専門用語はなるべく通常の言葉に落とし込む練習が必要ですね・・・。落とし込みの深追いは禁物ですが、自分の分野ではしっかりとやらないと専門用語のオンパレードなので、同じ道の人は一緒に頑張りましょう!?

 

 インプットしたらアウトプットを早くしようはまさに今ブログ書いてることですね。感じたことや経験したことを言葉としてどこかに落とすことが大事です。情報学生は常にこれをし続けるべきだと今更ながら気づかせてもらいました。「考える -> 作る -> 評価」をやるべきなんですが、大学生だと他のことなどで期間がじわじわと伸びてしまいがちです。なので長期休暇でやるのが一番良いです。ある人はまだ一週間あるはずなのでやってみてください!(でも無理はだめです)

 

〜最後に〜

 

 一気にまとめてしまったので文章量がとんでもないことになりました。これも良くないですね(一敗)。それと、書き忘れてましたが、失敗はたくさんアウトプットしてほしいです。失敗学という本すら出るほどなのでぜひぜひ。

 

大学では味わえない超短期開発が出来ました!評価もたくさん頂いてありがとうございます。作って、結果を見て、発狂してのサイクルでした!講義は大学の話よりリアルがありすぎて、聞いてるだけで楽しかったです。なのでやっぱり一言でまとめると

俺の初インターンがこんなに忙しい訳がない。

 

f:id:hama-matcha:20180916160916j:plain

言えたぜ!(終)

mecab-ipadic-NEologdのインストールでハマったこと

mecab-ipadic-NEologdが全然インストールできなかったので苦戦内容と解決策を載せておきます

使用しているのはmacOS High Sierraです

 

MeCabがバグる:ターミナルでMeCabを使うと ????|????とか表示される、一旦すべて消しましょう

brew uninstall mecab mecab-ipadic

再インストールです

brew reinstall mecab mecab-ipadic

ここで、ターミナルでmecabと入力して動作を確かめてください

./bin/install-mecab-ipadic-neologd -nを実行したあとにパスをmecab -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd/でチェックしても見つからない時、 原因は2つほど見つけました。

問題1 iconvがないと怒られている インストール中にiconvという単語が何度も出てきたら注意ですね

解決1 pyenv local system

理由

pyenvでオレオレ設定してるとハマりやすいですほしいのは辞書データなのでおとなしくsystemにしましょう

問題2 エラー分を読んでいない

解決2 意外とありがちですが最後の行から読んでみると~~~.sh先に叩いてねとか書いてます。すいません読んでませんでした許してください!

オレオレ設定してるとよくわかんないエラーに見舞われるため程よく管理しよう!