なんでまたそういう無関係なネタを一つの記事にするっ,ておしかりをうけそーですが (^^; 前者は小ネタなので…
国道422号線大石東バイパスの話
- 国道422号バイパスをてくてく etc. - まんぼう日記
- 国道422号バイパス工事の様子を見に行ってきました - まんぼう日記 (埋め込んでる Google Map の衛星写真が新しくなってて,工事現場の様子とか南郷ほたる橋とか写ってます)
の続きのようなそうでもないような話.瀬田川にかける橋の方は完成までまだ何年もかかるということやったけど,あっちのトンネルの方は7月末までってことになってたよなー,とか思い出して,ウェブで検索してみたら,こんなん見つけました.
http://www.pref.shiga.lg.jp/h/d-kanri/kikaku/files/2_uehara.pdf
ルート計画の話とか,橋種選定の話(図4第3案の鋼斜張橋がヘンテコですてき)とか,橋梁工事の工程(図6)とか,面白いことがいっぱいです.図7の今後の事業工程によると,橋の上部工は今年度第4四半期から,トンネル(関津トンネルというらしい)は来年度第4四半期から工事が始まる予定となってました.7月末までってのはトンネルまでの道路部分の工事のことなんでしょうね.計画ではトンネルも橋も平成30年度末開通ってことになってます.今からそこをてくてくする日が待ち遠しい (^^)
TheanoでGPGPUの話
昨日無事に GPGPU 用マシンの設定ができた( 続 GPGPU用マシンにCUDAをインストール - まんぼう日記 )ので,早速ニューラルネットの学習の実験をやってみました.ハード/ソフトの環境についてはリンクを辿ってください.
プログラムの作成というか修正
以前,Theanoで多層パーセプトロン(MLP)の学習をするプログラムを作って,MNIST の手書き数字認識の実験をやったことがあります( cf. Theano で MLP & CNN (2) - まんぼう日記 ).今回は,その時のプログラムをちょこっと修正して GPU 上で動かしてみることにしました.
GPUは倍精度(64bit)浮動小数点数の計算が苦手で,単精度(32bit)の方がよいみたいなので,まずは theano.tensor の float64 な型を使ってる箇所を修正して,float32 / float64 の切り替えが簡単にできるようにしました.上記の記事のリンク先にある nnet0211.py で T.dmatrix / T.dvector / T.dscalar にしてたところを,T.matrix / T.vector / T.scalar に.これで,theano.config.floatX の値を指定( 'float32' または 'float64',デフォルトは 'float64' )するだけで切り替えられます.直にプログラム中に theano.config.floatX = 'float32' のように書いてもよいし,環境変数 THEANO_FLAGS で指定することも可能(詳細はこちら: config – Theano Configuration — Theano 0.7 documentation.この記事の下の方にも環境変数で指定してる例があります).
それだけ修正したらokかと思いましたが,実行してみたら
TypeError: ('Bad input argument to theano function with name "/home/takataka/ .../nnet150612.py:95" at index 0(0-based)', 'TensorType(float32, matrix) cannot store a value of dtype float64 without risking loss of precision. If you do not mind this loss, you can: 1) explicitly cast your data to float32, or 2) set "allow_input_downcast=True" when calling "function".', array([[ 0.10094242, 0.09894396, 0.10255994, ..., 0.09911078,
というようなエラーが出てきました.デフォルトでは float32 な theano.tensor に float64 な値を代入させてくれへんのですね.ということは,numpy.array にデータを格納してる所も修正して,単精度浮動小数点数の配列にしとけばよいんでしょう.というわけでちょこちょこ修正.
今度こそokかと思ったら,まだエラーが.そっか,shared variable のデータ型もあわせなあきませんな.Numpy で作ったゼロ行列やら乱数を theano.shared に渡してたとこも修正.
三度目の正直,これでどや…動きました \(^^)/
プログラムはこちら:
- nnet150612.py ニューラルネットとその学習
- mnist_mlp150612.py それを使った MNIST での実験用
- mnist0118.py MNISTのデータの読み込み
実験結果
さあ実験.詳しい実験条件等については…省略.以下の出力とかプログラムとか,Theano で MLP & CNN (2) - まんぼう日記 やそのリンク先の記事を参照してください.
まずは,「入力 - 隠れ層 - 出力層」という2層のMLP.
2層MLP,CPUで実行
$ time THEANO_FLAGS='device=cpu,floatX=float32' python mnist_mlp150612.py ### 2-layer MLP: D = 784 H (ReLu) = 500 K (softmax) = 10 ### training: NL = 50000 NV = 10000 batchsize = 100 # eta = 0.01 mu = 0.9 lam = 1e-05 0 | 2.3045 93.27 | 2.3044 93.48 10 | 0.0794 2.11 | 0.0976 2.69 20 | 0.0366 0.79 | 0.0733 2.11 30 | 0.0205 0.28 | 0.0678 1.99 40 | 0.0127 0.13 | 0.0661 1.91 50 | 0.0085 0.04 | 0.0663 1.86 # NT = 10000 50 | 0.0085 0.04 | 0.0663 1.86 | 0.0645 1.94 real 2m30.410s user 10m41.883s sys 18m25.275s
実際の経過時間(real)よりユーザCPU時間(user)の方が長くなってるのは,マルチコアで並列計算してるから.実コア数6,Hyper Threadingで仮想コア数12のCPUなので,理想的には12倍までいきます.
2層MLP,GPUで実行
$ time THEANO_FLAGS='device=gpu1,floatX=float32,nvcc.fastmath=True' python mnist_mlp150612.py Using gpu device 1: Quadro K620 (中略) 50 | 0.0085 0.04 | 0.0661 1.88 | 0.0645 1.95 real 3m10.979s user 2m41.005s sys 0m30.319s
$ time THEANO_FLAGS='device=gpu0,floatX=float32,nvcc.fastmath=True' python mnist_mlp150612.py Using gpu device 0: Tesla K20c 50 | 0.0085 0.04 | 0.0661 1.87 | 0.0644 1.92 (中略) real 1m18.779s user 0m58.470s sys 0m20.841s
上が Quadro の場合,下が Tesla の場合.Quadro ではCPUに負けてますが,さすがに Tesla は速いです.今回のプログラムでは,SGDのミニバッチ毎にメインメモリとGPUの間でデータ転送が発生するのですが,これくらいの規模のネットワークでは,GPU内でのネットワーク出力の計算&誤差逆伝播学習の計算よりもそっちのオーバーヘッドの影響の方が大きいのかもしれません.
ちなみに,nvcc.fastmath = True というオプションも渡してますが,今回の実験ではなしでも計算時間は変わらず,その効果のほどはわかりませんでした.
次は,隠れ層をもう一つ入れて,「入力 - 隠れ層 - 隠れ層 - 出力層」という3層のMLPで.
3層MLP,CPUで実行
$ time THEANO_FLAGS='device=cpu,floatX=float32' python mnist_mlp150612.py ### 3-layer MLP: D = 784 H1 (ReLu) = 1000 H2 (ReLu) = 500 K (softmax) = 10 ### training: NL = 50000 NV = 10000 batchsize = 100 # eta = 0.01 mu = 0.9 lam = 1e-05 0 | 2.3030 92.28 | 2.3028 92.61 10 | 0.0303 0.68 | 0.0747 2.18 20 | 0.0058 0.03 | 0.0716 1.88 30 | 0.0024 0.00 | 0.0761 1.87 40 | 0.0013 0.00 | 0.0787 1.81 50 | 0.0010 0.00 | 0.0809 1.82 # NT = 10000 50 | 0.0010 0.00 | 0.0809 1.82 | 0.0778 1.82 real 6m21.194s user 34m25.742s sys 40m42.999s
3層にしたことで,userは11分→34.5分,realは2.5分→6分となりました.
ついでに,float32 と float64 の比較も.
$ time THEANO_FLAGS='device=cpu,floatX=float64' python mnist_mlp150612.py (中略) 50 | 0.0010 0.00 | 0.0811 1.80 | 0.0778 1.86 real 9m21.587s user 62m26.379s sys 47m39.997s
1.5倍ってとこですね.
3層MLP,GPUで実行
$ time THEANO_FLAGS='device=gpu1,floatX=float32,nvcc.fastmath=True' python mnist_mlp150612.py Using gpu device 1: Quadro K620 (中略) 50 | 0.0010 0.00 | 0.0810 1.79 | 0.0778 1.87 real 3m38.336s user 2m53.285s sys 0m45.223s
$ time THEANO_FLAGS='device=gpu0,floatX=float32,nvcc.fastmath=True' python mnist_mlp150612.py Using gpu device 0: Tesla K20c (中略) 50 | 0.0010 0.00 | 0.0808 1.82 | 0.0777 1.84 real 1m54.144s user 1m21.258s sys 0m33.203s
3層MLPの方は,Quadro でも CPU に勝ちました.しかも,2層の時とあまり所要時間が変わってません.メモリ転送のオーバーヘッドが全体に占める割合は2層の時より減ってはいるものの,まだそれが大きくて,GPUが性能を出し切れてないってことかもしれませんね.
ちなみに,Tesla で実行中に nvidia-smi コマンドでGPUのメモリ使用量を表示させてみたら,上記プログラムのプロセスが使ってるメモリは 90MiB でした.
それから,Tesla の方で float64 でも実験.
$ time THEANO_FLAGS='device=gpu0,floatX=float64' python mnist_mlp150612.py Using gpu device 0: Tesla K20c 50 | 0.0010 0.00 | 0.0811 1.80 | 0.0778 1.86 real 9m17.319s user 62m35.160s sys 47m33.556s
なんてこった.えらい遅くなりよう…さらにユーザCPU時間の変化がおかしなことに.CPU使った時とほとんど同じになってます.なんか変….
とりあえず今日はこんなところで.