"機械学習","信号解析","ディープラーニング"の勉強

HELLO CYBERNETICS

深層学習、機械学習、強化学習、信号処理、制御工学などをテーマに扱っていきます

Chainer2.0がリリース【今後の安定版】とりあえず抑えておきたい変更点

 

 

f:id:s0sem0y:20170604181105p:plain

Chainer2.0がリリースされ、今後の安定版として使われることになりました。以後、これからChainerを本格的に使っていく場合はこちらを利用していくことになります。

 

 

Chainerを再インストールする

Chainerの再インストールはpipを使えば簡単に終わります。

まずは既存のChainerをアンインストールしましょう

 

pip unistall chainer

 

これだけですぐに終わります。その次に、以下のコマンド

 

pip install chainer --no-cache-dir

 

「--no-cache-dir」の部分は、キャッシュを利用せずパッケージを再DLしてインストールを行います。特に再DLに多大な時間がかかるわけではないので、上記のコマンドを利用することをお勧めします(公式でもこちらが推奨されています)。

 

cupyの導入

Chainerからcupyが完全に分離されました。cupyはGPUを用いる際に使われるので、仮にCPUだけで動かす人には無縁です。しかし深層学習を本格的にやる以上はGPUを用いることは確実ですので、

 

pip install cupy

 

でライブラリをしっかりインストールしておきましょう。cupyはCUDAのプログラミングをする必要なくpythonからGPUを利用できる便利なライブラリということになります。cupyはnumpyと同じような関数が実装されており、基本的にはCPUで計算をする際にnumpyで書いていたものをcupyに置き換えるだけで済みます。

 

chainerの流儀では

 

import numpy as np

import cupy as cp

 

#xp = np

xp = cp

 

x = xp.array()

 

などと書いておくことで、numpyを使うかcupyを使うかを切り替えるようにしておきます(これはVer1のときからの話ですが)。コメントアウトで切り替えてもいいですし、切り替える関数を作っても良いでしょう。(あまり変わらないと思いますが)

 

chainer2.0の変更点

トレーニングモードとテストモード

Chainer1

これまではネットワークを以下で構成し

# Chainer v1
import chainer.functions as F

class MyModel(chainer.Link):
    ...

    def __call__(self, x, train=True):
        return f(F.dropout(x, train=train))

m = MyModel(...)

 

テストの際の順伝搬は、

# Chainer v1
y = m(x, train=False)

と記述していました。

chainer2

2.0へのバージョンアップ後は

# Chainer v2
import chainer.functions as F

class MyModel(chainer.Link):
    ...

    def __call__(self, x):
        return f(F.dropout(x))

m = MyModel(...)

とモデルを構築した後は、以下によりテストの際の順伝搬を行うことになります。

with chainer.using_config('train', False):
    y = m(x)

「with」はもともとpythonで利用されている構文であり、「ファイルの読み込み→なんらかの処理→ファイルを閉じる」という処理を「ファイルを読み込む→何らかの処理」と簡潔に安全に行うことができる便利なものです。chainer2.0ではこの便利な機能を活用する方向で実装が行われたようです。

 

Variableオブジェクトについて

揮発性の操作

chainerは動的に計算グラフを構築します(Define by Run)。従って、計算を行う度に計算グラフを構築しているということになりますが、この計算グラフは学習の際にバックプロパゲーション(後方自動微分)を実行するために必要となります。

 

chainerではVariableというオブジェクトに値や計算グラフの情報がつめ込まれていましたが、単にテストをするだけで学習をする必要がないならば、わざわざ計算グラフの構築処理(あるいは情報を保持する)を行う必要がありません。これまでVariableには「volatile(揮発性)」という引数をTrueにすることで、計算グラフの情報を持たせない設定にすることができました。

 

揮発性を有する(計算グラフを持たない)Variableをを順伝搬する場合は、chainer1では

# Chainer v1
x_data = ...   # ndarray
x = chainer.Variable(x_data, volatile=True)
y = model(x)

となっていましたが、chainer2では

# Chainer v2
x_data = ...   # ndarray
x = chainer.Variable(x)
with chainer.no_backprop_mode():
    y = model(x)

 に変更されました。要するに「volatile」揮発性という引数をなくして、with構文で記述するように実装されたということです。

 

 

VariableとVariableNode

上記の変更はVariableに加えVariableNodeが実装されたことによります。

これまではVariableに計算グラフの情報も載せていたのですが、計算グラフの情報はVariableNodeとして別のクラスとして実装されました。つまりこれまでのVariableが、2.0ではVariableとVariableNodeに分離されたということです。

 

不要なメモリの消費を大幅に改善することができたようです。

 

Variableオブジェクトの中身

Variableオブジェクトの中身を表示する場合には、chainer1では

# Chainer v1
x_data = ...   # ndarray
x = chainer.Variable(x)
print(x.data)

でしたが、chainer2では

# Chainer v1
x_data = ...   # ndarray
x = chainer.Variable(x_data, volatile=True)
print(x)

で可能になっていました。従って、Variableの長さ(通常はデータ数)を確認する場合には「len(Variableオブジェクト)」とすれば確認できることになります。

 

同じように「x.data.shape」は「x.shape」で置き換える必要があることにも注意しましょう。

パラメータの初期値について

パラメータの初期値の設定が変わります。

パラメータの初期値の設定はchainer1では

# Chainer v1
class MyLink(chainer.Link):
    def __init__(self):
        super(MyLink, self).__init__(
            W=(10, 5),
            b=(5,),
        )
        chainer.initializers.init_weight(self.W, chainer.initializers.Normal(0.05))
        self.b.data.fill(0)

でしたが、chainer2では

# Chainer v2
class MyLink(chainer.Link):
    def __init__(self):
        super(MyLink, self).__init__()
        self.W = chainer.Parameter(chainer.initializers.Normal(0.05), (10, 5))
        self.b = chainer.Parameter(0, (5,))
    ...

と引数として与えることになりました。ちなみにTensorFlowではNormal分布ではなくTruncated Normal分布を使って初期化するのが標準的になっています(なんでだろう。まだよく調べてません)。

 

 

Chainer関連記事

私は日本初のディープラーニングフレームワークChainerを応援しています。

(とか言いながらTensorFlowもKerasも使ってます。)

 

s0sem0y.hatenablog.com

s0sem0y.hatenablog.com

s0sem0y.hatenablog.com

s0sem0y.hatenablog.com