クーの自由研究

素朴な疑問を実験します。ボクと一緒に螺旋階段を頂上まで登ってみませんか?貴方の影についていきます。

計算機音楽の自由研究(実験:その1)フーリエ変換かけずに波形のまま自己符号化器にかける

はじめに

考えてみれば、今年はじめての実験かもしれません。

昨年作った画像用の自己符号化器に対して、無理やり音の波形データを学習?させて、エンコード、デコードがどれくらいできるかやってみます。

我ながらとっても無理があるお題ですが、なにごとも「やってみてわかることもある」のでチャレンジします。

f:id:np2LKoo:20170723205454p:plain

(入力波形例)

波形的にはそこそこ復元できるものの、「音」としてはほとんどノイズもしくはかすかに原音がきこえる程度になると予想しています。音は思いのほか(グラフィックにくらべれば「はるかに」)、歪に対しての耐性が弱いイメージがあります。

実験プログラム

 無理やりのやっつけプログラムなので、今回プログラムの公開予定はありません。(波形処理以外の「自己符号化器」本体は昨年プログラムと全く同じものです。)もう少し実験が安定してくれば、そして公開価値のあるプログラムであれば公開します。

昨年の実験は、標準的なレポートフォーマットをまとめて、実験の結果をある程度わかるようにして報告できました。今年は

・音用の報告フォーマットがない。作ったとしても「音」のレポートは音を鳴らさないと伝わりにくい。

・昨年は「グラフィック」に関してかなり「微」調整して学習効率をあげていきました。今回は「元になるプログラムがそもそもない」(フーリエ変換はmfccの前処理しての学習はあるっぽいが今回は関連なし)のと、力技でつないだだけの状態です。

結果の公開方法については試行錯誤が必要な感じです。できれば音のでる「マルチメディアPDF」にまとめて公開できればと考えています。

調整した概要のみ記載します。

・16Bit 48KHzサンプリング波形(32768点サンプル)のままでは情報量が多すぎるので、学習直前に8bit 4KHz(2731点サンプル)へリサンプリングした波形を画像と同様の配列構造にして入力として学習させた。(ちなみに画像MNISTでは28×28=784点)

・サウンドデータベースは完成していないので、ピアノ音のみの6000音(MidiNote=21~108)を学習させた。

・昨年同様PCが非力なので、1Epochを間引いて学習した1/100で1024Epoch学習したので、実質6000音を10Epoch程度学習していることに相当している。

エンコード、デコードした結果を例として波形、音の両方でこの後貼ってみます。

・中間的には32Bit実数で計算し、最終的には原音と同じ8Bit整数にして出力しています。32Bit実数計算の結果は±128を超える場合があるので、8Bit(+128, -127)を超えないように割り返して収まるように計算している。

・計算結果が波形的に若干中央値からずれている場合があるので、波形でいうところのDCオフセット簡易処理(波形の平均がゼロとなるように補正)している。

実験結果

 実験条件

中間Hidden層:  1層:1000ノード
データ数: 各音2731 (音のサンプリング数)
データ総数 6000音(ピアノ音のみ)
学習のサブスケール(間引き): 1/100  (このサイト独自パラメータ、1/100の場合は100Epochで通常の1Epoch)
バッチサイズ: 10 (10個ずつまとめて処理)
ドロップアウト 0.3 (30%の確率ドロップアウト学習)
Epoch数: 1024 (1/100スケールなので実質 10Epoche相当)
活性化関数: Leaky Step ReLU (このサイト独自の活性化関数(昨年記事参照):本当はSigmoidでやろうとしていましたが、値域の関係でエラーになるので、こちらを使用)
オプティマイザ: AdaGrad (単層なので、オプティマイザかける必要はないが、昨年からの成り行きで選択中)
評価(コスト)関数: 最小二乗法:グラフィックのものをそのまま流用、波形が「図形的に近い」とコストが低いと判定。本当は多少位相がずれても周波数特性的に同じであれば低コストにすべきだが、このあたりは全く手つかず。

結果:代表的EPochの復元波形と音を貼り付け

f:id:np2LKoo:20170723213401p:plain

f:id:np2LKoo:20170723213434p:plain

EPoch0 は学習前の初期ノイズ(初期値)です。

Epoch64を超えるとだんだん波形がそれっぽくなってきます。

Epoch1024の最初の部分を拡大してみます。(上が元の音、下がEpoch1024のエンコード/デコード波形)

f:id:np2LKoo:20170723214834p:plain

音は、中間くらいの高さの音を、「元音, Epoch 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, ふたたび原音」の順に鳴らしたものを貼ります。テンポを取りながら聞いてみてください。

 ノイジーな音に耐性のない方は聞かない方がいいかもしれません。音量には十分ご注意ください。

(追記)さて、解析結果は別記事にしようとも思いましたが、音の下に貼った方がわかりやすいので、こちらにはります。上の音をLibrosaでmcff(メル尺度のパワースペクトログラム)のグラフをだしたものです。(これも昨年のプログラムをそのまま使用)

f:id:np2LKoo:20170726001415p:plain

スケールの取り方と色の替え方を忘れてしまったので、デフォルト状態のグラフを貼ります。4KHzサンプリングなので、2KHz以上の音はありません。(末尾のはたぶんノイズです)白っぽい輝線が基音や倍音です。学習が進むにつれてコントラストがあがり、原音の基音・倍音が再生できているのがわかります。(追記ここまで)

違った音のエンコード/デコード音も貼ってみます。

いずれもEpochが進むと元の音に近い音が聞こえてくると思います。

(追記)こちらもmfccグラフを貼ってみます。

f:id:np2LKoo:20170726001806p:plain

上よりも高い音なので、基音・倍音ともに上側にシフトしている感じです。(追記ここまで)

(追記)ほぼまる1日計算した結果(の重みとバイアス)を使ったAutoEncode/Decode結果です。ピックアップで低い音から「16768EpochのEncdoe/Decode音」「元の音」...の順に貼ってみました。ノイズや他の不協和音がまだかなりありますが、主となる音がかなりはっきり聞こえてきています。(とはいえ、こちらも心の準備が必要な音です)

(追記ここまで)

(上にさらに追記)音はそれなりなのですが、mfccグラフが変な感じです。

f:id:np2LKoo:20170726002642p:plainあれ?と思って波形をみてみるとこんなことになってました。

f:id:np2LKoo:20170726002101p:plain

マイナス部分のデシベルが低く、帯のようにみえています。

それなりに聞こえていたので、波形まではみていなかったですが、波形がかなり歪な形になっています。波形の振幅値倍率補正をするときに、中央値をうまく考慮せずに演算しているためと思われます。(8ビット補正のときに128が中央ゼロとなるように補正演算していますが、学習の問題というより、(8ビットでの)波形出力時の振幅調整&DC補正の演算ミスとおもわれます。実際にそうなのかは宿題ということで。。。:演算ミスではなく、(活性化関数はゼロ点で対称なものを使っているので)ほんとうにデコードが上記のとおりの波形になってたら興味深いです。)mcffは波形の中央値がおかしいので、帯のようなくずれたような図形になっていますが、輝線の部分ははかなり良い近似をみせています。(輝線のコントラストが原音にくらべて悪いので、他の周波数がはいり、ノイズや不協和音になっている感じなのは、音を聞いた印象に合致しています。)(上にさらに追記ここまで)

考察

 予想ではよくてノイズの中にかすかに音が聞こえる。または、学習せずに原音にそこそこ近い音が出力される:(これは学習しているといえず、単なるエフェクトで、自己符号化器としての実験は失敗を意味する。)だと考えていましたが、ノイズは酷いものの、元の音の周波数特性をある程度とらえた音になっていました。「自己符号化器」恐るべし

音に関する調整は直流(DC)成分除去と、振幅範囲の調整くらいしかしておらず、音を無理やり昨年作成したプログラムにつないで、パラメータをサンプル数に合わせただけなのに、自分としては大成功といえるくらい「それなり」の結果がでて正直予想外でした。(予想に反してなので、成功といえるか微妙かもですが)

音を聞いただけでは元の音をひどくノイジーにしただけで、面白くもないですが、音的な特性に関して調整すれば、もうすこし効率よく「学習」できるのではないかと思いました。

まとめ

 データ量的にはかなり抑えて実験しましたが、それでも1実験(1024Epoch:実10Epoch相当)に1時間30分程度かかるのはキツイ感じがしました。MNISTだと1実験10分程度だったので、結果をみていろいろ調整してリトライするのはあまり苦ではありませんでした。効率よく実験していける方法を考えたいと思います。

元の音に近い音が再現できるようになるということは、重み情報に各周波数(もしくはそれをまとめたもの)の「フィルター」もしくは「生成元」が形成されていることになります。これがどんな情報であるのかも調べていきたいと思います。

実験失敗(ほとんどノイズだけ)を予想していたので、次はすぐ「フーリエ変換」コースかなと思っていましたが、もうすこし「フーリエ変換なし」での実験をしたくなってきました。

なお、昨年同様、実験は延々こんなのが続きます。

なんとか「面白み」をだせるよう頑張りたいと思います。

ベースがあることは素晴らしいと実感

 昨年行った実験のプログラムを大々的に流用(というか本体はそのまま使用)しています。ちょっとしたことでも昨年やったこと(もしくは調べたこと)が参考になっています。その上で、何かがジョジョに分かってくる、できることが広がっていく感覚、はとても心地よいです。(実験の成否ではなく、pythonプログラムなどをうまくつくれるようになってきたことについて:自己満足ではありますが、モチベーションの維持は大切だと思っています。)

機械学習フレームワークを使えばいいのは分かっているのですが、しばらくはどうしてもフレームワークの中身(そしてブラックボックスの中身)を触りたいような実験ばかりになると思われるので、もうしばらくは独自路線でいきます。