はじめに
昨年作った自己符号化器:AutoEncoderを改めてコーディングしなおすことにしました。
昨年はMNIST(画像:図形)をやりましたが、今年は自己符号化器で「サウンド:波形」を扱おうとしています。下の画像部分をサウンドに置き換えて学習させようとしています。
・Pythonも知らないときに、いろんなサンプルをもとにして作成しているので、読みにくい部分があります。
・コーディング規約って何?のときのプログラムで、寄せ集めなので一貫性がありません。自分でとっても見にくいです。
・MNISTがうまく学習できるように実験していったので、意図せず汎用性が損なわれているかもしれません。
・今回も汎用性を損なわないようにしたいですが、波形を処理することは意識する。当初の意図とは異なり、波形を「あえて」フーリエ変換やウェーブレット変換せずにやっていますが、場合によっては波形を直接学習することに特化するかもしれません。
・いろいろなパターンでやると意図しないエラーが発生してその都度手間がかかっているので、可変部分について汎用性を持たせます。(MNIST数字学習はデータ量が一定だったが、サウンド学習ではベース、ピアノだけとかシンセ系は除くなど、数を変えています。このような可変部分への対応などを行います)
再作成にあたって
Pythonらしいコーディングにします。
Pythonのコーディング規約に「PEP8」というのがあるようです。
このコーディング規約にならってコーディングしてみます。
バッチ学習部分を可変にします。
バッチ学習にすると不協和音をそのまま学習していることになる感じがしています。
バッチ数はもともと可変にしていましたが、10以下にできないコーディングにしていました。バッチなし(1つづつ全部学習する)にもできるようにします。
あいかわらず「日記形式無視」でだらだら書いていきます。
新着記事の機能でこの記事を見ていただいている方には大変申し訳なく思っております。最近は1つの記事を1週間程度かけてだらだら書いていくこともあるくらいです。暖かい目で見て頂くとうれしいです。
コーディング状況
コーディングの経過状況や、途中で感じたことなどを書いていきます。
8/18 いきなり挫折ぎみです。期待していただいている方がいらっしゃったら申訳ございません。
昨年作成した自己符号化器はスクラッチとはいえ、大半が他のソースからのコピペや訳のわからない勢いで作成したのでした。いざ1行1行コーディングを始めると、その1行の「重さ」に改めて気づいている次第です。
何故、昨年のソースはそのようにコーディングしているのか、どのようなコンセプトからそうした、のか。本当に必要な行なのか。もっといいコーディングはないのか。
定数や変数定義ですら、どのような用途で作成しているのか、削減できないか、独立性はあるのか、クラス変数とインスタンス変数を取り違えていないか(最近までよく分かっていなかったので)などなど。
いわゆる写経的なコーディングを考えていたので、すらすらいくと思っていたのですが、「色即是空」とは何なのか?で止まってしまい、写経にならないイメージです。
の〇太「ど〇えもん、なんとかしてよ」
(ぱっぱら~♪) |
ど〇えもん「りふぁくたりんご。。。ひとくちかじれば、あ〇ぷる社の技術者のごとくソースを「おしゃれ」に、げしげし最適化できるようになるよ。横の部分を丸くかじるのがコツだよ。最適化したソースはアップルソース(Apple sauce)*1として食べることもできるんだ。」
の〇太「ありがとう!なんとかやってみるよ。」
もとのフルスクラッチではなく、リファクタリング路線に変更します。
リファクタリングの説明はこちらを見ました。わかりやすい説明に感謝です。
もしくは
ポリシー
・まずはPyCharmのPEP8チェック機能をいったんエラーレベルまであげ、PEP8準拠にします。
◆ほぼ完了したのでワーニングレベルにもどしました。かなり修正点がありました。どうしても準拠させたほうがわかりにくい、みにくいところだけあえて準拠から外しました。
・紆余曲折で使用していない importや変数、無意味なコメントアウトをばっさり削除します。
◆かなり試行錯誤の跡が残っていたので、必要ないものをばっさり削除しました。
・変更前の適度なポイントにトレース表示を入れ、時間測定をコーディングします。
◆これは既にコーディングしてあり、コメントアウトしてありました。必要に応じて追加します。
・構造変更前の実行で、現状の時間測定を何パターンかしておきます。
◆現状の何パターンかを計測しました。速度チューニング自体は昨年かなりやったので、(リファクタリングにより)現状から遅くならないかの確認用です。
・クラス変数、インスタンス変数の命名をすっきりわかりやすく変更します。
◆どうしようもなく分かりにくいものだけに留めることにしました。
・def メソッドの名称をより適した適度な長さの統一感ある名称に変更します。
◆迷って進まない。外部から使用する(ダメな割に)使い慣れているものが多いので、一旦保留することにしました。あとで改めて考えます。
・全体のメソッド構成を再検討し、細分化しすぎている箇所や大きすぎる箇所の粒度を統一していきます。
◆思いのほか粒度はそろっています。もともとエディタで1画面で表示できる範囲くらいしか考えられないので、それ以上になると意味もなく機能分割したり、して無理やり50行程度以下にしていました。(コアな部分だけ、分割するとわかりにくいので90行程度あるものもありますがあえてそのまま)
・構造を変更したら、正しく動作するかこまめにチェックします。
▲実験1~2はたまたま「発散」しなかった模様。昨年のMNIST(数字画像学習)用途にハイパーパラメータをチューニングしたままにしてあるので、とっても応答がピーキーで、改めて調整が必要と感じました。学習パラメータをかなり低くして発散しなさそうなレベルから始めます。もともと動いていたものは同じように動作するのでここまでのリファクタリングとしては問題なし。ロジックの見直し以前にハイパーパラメータのリセットをしてみます。
→発散はハイパーパラメータが原因ではなく、正規化(0~1)前提の処理に対して正規化していないデータを渡していたロジックがあったためでした(今回の波形についての問題)。
→また、値がマイナスであることを考慮していない部分があることがわかりました。(そのまま二乗しているなど :MNISTのデータにはマイナスはありません)
・def メソッド単位にロジックやコーディングを見直し、より分かりやすく(あとで変更しやすく)、シンプルにしていきます。無駄は省きます。速度改善は意識します。
速度がそんなにかわらなければわかりやすい方を選びますが、ループの中心部分は速度最優先にします。
◆しくみ上無理がある部分があるのがわかりました。見切ってはいないのですが、こんな感じです。マイナス方向の波形学習とプラス方向の波形学習を対象的に行わないとどうしても(学習がうまく進んだとしても)歪んだ波形になります。リファクタリングをこれ以上詰める前にしくみを再考したほうがいい感じになってきました。
これはよろしくありません。
リファクタリングは、基本的なレベルはクリアできたと思いますでので、次のステップをどうするか思案中です。(もう少し波形直接学習にこだわるか、ウェーブレット変換などへいくか)
以降のリファクタリングステップは今回は pass します。
・def メソッド単位に変更したら、改悪していないか実行して確認します。結果と速度を確認します。(ユニットテストのコーディングは面倒なのでパスします)
・もう現在のボクのスキルではこれ以上のソースにしようがなくなれば、次のメソッドに移ります。
・全体を通して、「波形」を題材にする場合、よく変更する点について、固定値ではなく、パラメータ化して変更可能にします。(必要最小限にとどめます)
・全体構成として公開しても「はずかしくない」程度にバランスがいいか確認します。
以上を行った上で、実験2などで問題になっている箇所の原因を探します。(原因を探しやすくコーディングを改変することも念頭にいれてリファクタリングします)
こう書くとこっちの方が面倒な気がしますが、「動く状態」を維持できる点がとてもいいと感じますし、細切れの時間を使うにはリファクタリングのほうが向いている気がします。
感想
やっている途中ですが、「こまめなバックアップ」は必須で、手間がかかります。参考サイトでは 「1人でやるとき(開発であれ、リファクタリングであれ)も、cvsなどのバーション管理ソフトは入れたほうがいい」とありました。たしかに普通の作成でも実験用にブランチしたり、実験でつくった汎用的なメソッドを元にマージしたりしているし。。。
gitでもいいかもですが、公開はきれいにしたいので、ローカルでcvs(subversionなど?)をそのうち入れてみます。
いろいろな情報を読むと「リファクタリングするなら、テストコーディングすべし!」なのですが、このテストコーディングがよくわかりません。現状は「短いテストケースが同じ「感じ」になればOK」という、ゆるゆるで進んでいます。
◆マイナス側の学習がプラス側と「結果として同等ではない」ことがわかりました。学習の「しくみ」自体に根本的な「プラスマイナスを取り違えているなどの」問題があるわけではないので、どうするか思案中です。
◆MNIST(手書き数字学習)の場合はノイズや不確かな情報は学習の谷側に集めれば問題ないのですが、波形をそのまま扱う場合はプラス、マイナスの値を扱い、ノイズや不確かな情報はゼロ付近に集め、これを小さくしていく必要があります。もう少し考えようと思います。つきつめれば、「空即是色自己符号化器」とは何か?の壁にぶちあたるような予感がしています。実験は進みませんが、避けて通れない道のような気がするので悪あがきします。
色即是空=「自己符号化器」のエンコード、空即是色=「〃」デコードにあてはめてみる
もしかしたら「空」とは虚数空間、もしくは複素数空間のことをいっているのかもしれないな、と想像力を働かせてみます。実験には「オカルト」を持ち込みませんが、オカルト大好きなんです。(くどいか。)