最近話題になっている。ニューラルネットワークの二値化については前から興味があったので読んでみた。ニューラルネットワークの二値化についてはこれまでも色々と研究があるようである。大きな方向性としては、まずはじめに実数値で重みを学習してそれを二値化するというやり方と、最初から二値の重みを学習するやり方がある。BinaryNetはそのどちらとも明確に分類しづらい、ちょっと変わった手法である。BinaryConnectBinaryNetの前にBinaryConnectに触れておくことにする。どちらもBengioグループの研究である。BinaryConnectは大雑把に説明すると、以下の様な手法である。matrix自体は実数で値を持っていて、forward/backwardの計算時に二値化する。matrixを更新する。二値化はdeterministicに行う場合とstochasticに行う場合の2つを考えているが、後者のほうが性能が良い。入出力の値自体は二値化していない。入出力の値の範囲も二値化できれば、行列積の計算がかなり高速になるのになぁ、というのはこの論文を読めば誰もが思うところであろう。それを実現したのがBinaryNetであると考えてよい。BinaryNet先述の通り、BinaryNetでは入出力の値自体も二値化する。matrixの二値化自体は、deterministic方式を採用している。速度を重要視したらしい。各層への入力は二値で入ってくるものとする。出力は二値化する前にBatchNormalizationをかける。精度の点では、残念ながらBinaryConnectにちょっと負けている。7倍速いと言っているが、これは単純な行列積用のCudaカーネルを自分で実装した場合と比べてであって、かしこい行列積ルーチンと比べると、速度向上は2倍もいってない。意外と速くならないんだなぁという感想を持った。実装を頑張ればもっと速くなるのかもしれないが。Networkは、BinaryNetとほぼ同じ手法である。実はこちらの方が1日だけ早くarxivにアップロードされていた。CIFAR-10と、BinaryNetと全く同じであるし、BinaryConnectにちょっと精度が劣る点も一致している。Normalizationを近似している。これは、厳密に平均と分散を計算してscaleとshiftをすると重たいので、標準偏差の逆数を一番近い2^nの数字で近似して、乗算の代わりにビットシフトで計算を済ませようという話である。この近似以外は、BinaryNetとほぼ同じである。GPUでは乗算はそんなに遅くないと思うので、ビットシフトにしたところでメリットがありそうには思えないのだが、専用ハードウェアを設計したい、みたいな目線で書いてあるように見える。いう目で見ると、たしかにまぁ、乗算は少ないほうがよい......というか、無くしたい気持ちになるのはよく分かる。BinaryNetとくらべて、論文自体はこちらの方が幾分読みやすいように思う。1}$のあたり、ちょっと端折り過ぎではないか。いう訳で、BinaryNetに興味がある人は、こちらの方も併読したほうがよい。(後日追記)activationの微分についてこのブログ記事ではちょっとはしょりすぎてしまっていたが、activationの値の二値化をどうやって実装するかは重要な問題であるという指摘を受けた。二値化自体は普通に実装すればいいのだが、そうすると、勾配をどうやって計算すればいいのかがわからない。普通に実装すると、いたるところで勾配が0になり、勾配法による最適化が効かなくなる。勾配計算については、BinaryNetもBDNNも同じアイデアを用いている。二値化に使う関数を$f(x)$と表記することにすると、通常、勾配を計算する際には$f(x)$を微分するが、勾配を計算するときだけ、$f(x)$は次のような関数だったということにするのである。Networkとの相性はどうなるだろうか?単純に考えると、和を計算する部分で0がたくさん出てくるはずで、0の扱いをどうするか、悩ましそうに思える。(randomizeすると重そう)以前にFPGAでニューラルネットを実装するとどうなるのか、回路規模などから簡単に計算してみたことがあったのだが、その時には、FPGAを使うと電力効率は1,2桁よくなるが、速度的にはGPUを使うのと大差ないという計算結果になった。これらのシンプルなネットワークであれば、FPGAで組む難易度も大幅に易化するし、速度的にもGPUよりも1,2桁は速くなりそうに見える。学習には依然として実数での計算が必要であり、FPGAで全て解決、もうGPUは要らない、という話ではない。matrixをなくすのは、かなり難しそうであるなので、GPUはこれからしばらくは重要であり続けるだろう。