Deconvolution 2Dの学習経過をjupyter上で描画(Bokeh)

#はじめに
ディープラーニングの学習経過の画像をjupyter上でリアルタイムに表示できるものがないかと探していたところ、[Bokeh](http://bokeh.pydata.org/en/latest/)というライブラリがあったので試してみました。

#学習内容
Chainer を使って1層のDeconvolution 2D(簡単なフィルタみたいなもの）を学習させてみました。Deconvolutionについては以前に[こちらで紹介したこと](http://www.slideshare.net/samacoba1983/chainer-63698486)など参考にしてください。
下のgifでは点 ⇒ 球状の模様に変化させるように学習させています。

![test2.gif](https://qiita-image-store.s3.amazonaws.com/0/109458/9a7a4426-a9ed-0273-9edd-274482b80ccc.gif)

Bokehでは画像をマウスホイールで拡大縮小などできるので学習の確認には便利です。

#ソース
以前のChainerではnumpyを一度Variableに変換する必要がありましたが、Ver 1.17の現在では自動でVariableに変換してくれるようです。
Bokehのjupyter上での表示については[こちら](
http://bokeh.pydata.org/en/latest/docs/user_guide/notebook.html)など参考にしています。

```
import chainer.links as L
import chainer.functions as F
from chainer import Variable, optimizers
import numpy as np
import math
import time

#１つの球状の模様を作成（ガウスですが）
def make_one_core():            
    max_xy=15    
    sig=5.0
    sig2=sig*sig
    c_xy=7
    core=np.zeros((max_xy, max_xy), dtype= np.float32)
    for px in range(0, max_xy):
        for py in range(0, max_xy):
            r2=(px-c_xy)*(px-c_xy)+(py-c_xy)*(py-c_xy)
            core[py][px]=math.exp(-r2/sig2)*1
    return core.reshape((1, 1, core.shape[0], core.shape[1]))

#点と球状のimageを作成
def get_image(N=1, img_w=128, img_h=128):
    
    #ランダムに0.1％の点を作る
    img_p = np.random.randint(0, 10000, size = N*img_w*img_h)
    img_p[img_p < 9990]=0
    img_p[img_p >= 9990]=255

    img_p = img_p.reshape((N,1,img_h, img_w)).astype(np.float32)
    
    decon_core = L.Deconvolution2D(1, 1, 15, stride=1, pad=7)
    #Wに球状の模様をあてる
    decon_core.W.data = make_one_core()
    
    #点⇒球に変換
    img_core = decon_core(img_p)#Variableに変換なしでもOK
    
    return img_p, img_core.data    


#初期描画
from bokeh.plotting import figure
from bokeh.io import push_notebook, show, output_notebook
from bokeh.layouts import gridplot

output_notebook()

palette_256 = ['#%02x%02x%02x' %(i,i,i) for i in range(256)] #256段階で白黒表示用

img_p, img_core = get_image()#点と球状のimageを取得

img_h = img_p.shape[2]
img_w = img_p.shape[3]

plt1 = figure(title = 'epoch = --', x_range=[0, img_w], y_range=[0, img_h])
rend1 = plt1.image(image=[img_p[0][0]],x=[0], y=[0], dw=[img_w], dh=[img_h], palette=palette_256)

plt2 = figure(title = 'loss  = 0', x_range=plt1.x_range, y_range=plt1.y_range)
rend2 = plt2.image(image=[img_core[0][0]],x=[0], y=[0], dw=[img_w], dh=[img_h], palette=palette_256)

plts = gridplot([[plt1,plt2]], plot_width=300, plot_height=300)
handle = show(plts, notebook_handle=True)

#モデル・オプティマイザ設定
model =  L.Deconvolution2D(1, 1, 15, stride=1, pad=7)#1層のDeconvolution
optimizer = optimizers.SGD(lr=0.001)#大きいと発散する
optimizer.setup(model)
 
#計算
for epoch in range(0,31):    
    
    #1層のDeconvolutionを通してロスを計算しアップデート
    model.cleargrads()
    img_y = model(img_p)
    loss = F.mean_squared_error(img_y, img_core)
    loss.backward()
    optimizer.update()
    
    #画像・ロスデータをセット
    rend1.data_source.data['image'] = [img_p[0][0]]
    rend2.data_source.data['image'] = [img_y.data[0][0]]
    plt1.title.text='epoch = '+str(epoch)
    plt2.title.text='loss  = '+str(loss.data)
    push_notebook(handle = handle)#表示をアップデート
    time.sleep(0.5)

```