週末はプログラミング AIとCGと
Weekend programmer, AI and CG
2015.11.30
Updated by Ryo Shimizu on November 30, 2015, 04:14 am JST
Weekend programmer, AI and CG
2015.11.30
Updated by Ryo Shimizu on November 30, 2015, 04:14 am JST
久しぶりに週末まとまった時間ができたので、なんとなくプログラミングして過ごすことにしました。
プログラミングには集中力と時間が必要で、というのも、一度始めてしまうと夢中になってしまうので、日々の仕事の合間にやるにはあまりにも負荷が大きい趣味なのです。
今週末取り組んだプログラミングは主に3つ。
ひとつは、ディープラーニング用フレームワークChainerの最新バージョンへの対応とその視覚化。
視覚化そのものはそれほど目新しいテーマではないのですが、最新バージョンへバージョンアップするとChainerは下位互換性を盛大に捨ててるのでそれをキャッチアップしないとならないのと、私自身がまだPythonのフレームワークに慣れてないので練習を兼ねて視覚化ライブラリのmatplotlibの使い方を覚えました。
面白いのは、上の写真のように、全く同じ構造の2つのニューラルネットワークを同時に学習させ、同じ時間だけ学習させた結果を視覚的に見れることです。
当然ですが全く違いますがどことなく似ています。
これはいわば、一卵性双生児のようなものです。
そして同時に、全く同じDNAを持って産まれた一卵性双生児がどうして性格や考え方が異なるのか、ということを暗示させる結果にもなっています。
たとえ構造が全く同じでも、初期値が乱数なので全く同じニューラルネットワークにはなりようがないのです。
ところがさらにおもしろいのは、このニューラルネットワークの兄弟は、どちらも同程度の性能を発揮するということです。
アプローチは違うものの、性能は同じ程度。
これもまたAIの奥の深さと言えるのではないでしょうか。
そして、さらにおもしろいのは、この兄弟のどちらかが一人で決断を下すよりも、二人で多数決を取ったほうが正解率が上がることです。これはアンサンブル学習と言われています。
この兄弟は多ければ多いほど良く、だいたい20人くらいの兄弟がアンサンブル学習して多数決をすると際立った成果が出るそうです。
もうひとつは、Chainerが流行った時にすぐに誰かがやるのではないかと期待していたのに実際には誰もやってくれなかったChainerのimagenetのマルチGPU化です。
今、ディープラーニングといえば大半の用途はimagenetです。imagenet、つまり画像向けニューラルネットワークです。ディープラーニングの際立った成果が出たのがimagenetなのである意味当然と言えるでしょう。
カリフォルニア大学バークレー校で開発され、世界中で使われているディープラーニング用システムCaffeのサンプルは基本的にimagenetです。もちろんCaffeはimagenet以外にも使えます。
NVIDIAが配布しているディープラーニングのフロントエンド環境であるDigitsは、Caffeをベースとしながらもむしろimagenetに特化したGUIです。
つまり、AIの専門家から非専門家に降りてくるところがちょうどimagenetというわけです。
筆者らが開発しているChainerのGUI環境DEEPstationもとりあえずimagenet用です。本当はLSTMやWord2Vecとかも扱えるようにしたかったのですが、imagenetとそれ以外のユーザーインターフェースが異なりすぎてひとつのパッケージに入れるのが大変そうなのでまずは人気の高いimagenetから始めることにしました。
さて、ところがimagenetをマルチGPUでやろうとすると、問題にぶちあたります。
簡単にやる方法が提供されていないのです。
せっかく高価なマシンを買っても、宝の持ち腐れとなっては勿体無いことです。
今はまだAIの専門家であっても、GPUが4つ以上あるマシンを自由に使えるケースは稀です。機材だけで数百万円してしまうからです。
大昔なら、大学の計算機というのは数千万円から数億円して当然だったのですが、最近はダウンサイジングとローコスト化が進み、かなり凝ったマシンでも50万円以下で買えるようになってしまいました。
そういう時代に百万円を超えるマシンを購入するのはいろいろな意味で勇気が必要です。
しかし2枚のGPUで学習時間が半分になるのであれば、時は金なりですから、あるに越したことはないのです。
いつまでたってもChainerのマルチGPU対応のサンプルがリリースされないので自分で作ってみることにしました。
今回はモデル並列化という手法を用いてとりあえずGPU2枚刺しのマシン用に作ります。
モデル並列化は効率は良さそうなんですが、GPUの数が増えるとプログラムを修正しなければならないというのが玉に瑕です。
最初はなかなか上手く行かなかったのですが、試行錯誤の末、なんとか2つのGPUがフル稼働するようになりました。
マシンは職場にあるのでリモートですが、きっと誰もいないオフィスでファンがけたたましい音を立てて回っていることでしょう。GPUは二基とも70度を超える高温に加熱しています。
学習も、二倍というほど高速ではありませんがそれなりに回っているようでまずは一安心です。
AIが学習をしているのを待つ間、私は再び視覚化について考えていました。
AIの学習結果は無数の小さな層によって表現されます。
これはカリフォルニア大学バークレー校が教育したニューラルネットワーク、caffenetの第一層です。
11x11の小さな層が96個並んでいます。
この並び方そのものにあまり意味はなく、単に96種類の層がひとまとまりになっているだけです。
AIはこの層をフィルターとして、これを組み合わせて一般物体認識を行います。
斜めの線や縦の線、円形のもの、などなど、いろいろなフィルターが学習に寄って自動生成されているのがわかります。
こうして並べるのも解りやすいのですが、実際にはこれは二次元的なイメージよりも三次元的なイメージの方が実態に近いような気がします。
そこで三次元的なグラフを手軽に描くライブラリを探したのですがどうも私が求めるようなものはないようでした。matplotlibにも三次元を描画する機能はあるのですが、私が欲しいものと今ひとつ違ったので、これも作ることにします。
まずは直方体を並べてそれぞれの要素の強さを視覚的に表現してみます。
これはgl.enchant.jsを使うと非常に簡単なプログラムで表現できます。
興味のある方はソースを見てみてください。わずか80行足らずのプログラムで立体グラフを書けるのは非常に嬉しいことです。
javascriptが実現するイベント駆動型のプログラミングは非常に強力で、たとえばこのプログラムの場合、グラフの高さを変える部分(三角関数の合成によって生成)と、グラフのそれぞれの棒の高さに応じて色を変える部分は分けて書かれています。
こうすることでプログラミングの煩雑さを減らしているのです。
棒の塊が蠢くのも見ていて楽しいのですが、DEEPstationに組み込むことを考えると、あれはエヴァンゲリオンに強い影響を受けたデザインですからもう少し色気が必要です。
そこで小さな六角形の板の高さを変えることで表現してみることにします。
こちらのプログラムのソースコードはこれです。実行にはWebGLに対応した世代のブラウザが必要です。ちなみにiPhoneでも動きます。
プログラミングが楽しいのは、苦労せずして目的の結果を得ることが出来た時です。
先ほどの箱型棒グラフでは得られなかった別種の立体感がこちらの板を組み合わせたものにはあります。
ここまでできてしまえば、あとは単にデータを流し込むだけですから、さらに簡単です。
調子に乗って試しに100x100で合計1万のオブジェクトを表示させようとしたら、信じられないくらい重くなってしまいました。
ポリゴン数的には1万ポリゴンなど屁でもないのですが、1万オブジェクトというのは処理系にとって少なくない負担です。
これを高速化するには、個別のオブジェクトにするのではなくひとつのオブジェクトにするとかディスプレースメントマップにするとか色々方法が考えられますが、とりあえずのビジュアル化ならこれで十分ということで今日はこのへんで満足することにします。
ああでもきっと次の休日は、これを高速化することに費やしてしまいそうな気がします。
プログラミングは一生付き合える趣味です。
しかも、場合によってはその成果は仕事にもフィードバックされます。
やっぱりプログラミングは素晴らしいですね。
おすすめ記事と編集部のお知らせをお送りします。(毎週月曜日配信)
登録はこちら新潟県長岡市生まれ。1990年代よりプログラマーとしてゲーム業界、モバイル業界などで数社の立ち上げに関わる。現在も現役のプログラマーとして日夜AI開発に情熱を捧げている。