Chainer v2 alpha
Chainer v2 alphaがリリースされたので、自作のソースコードを対応させてみました。
以下のサイトを参考にしました。
動作環境
- OS: Windows 10(64bit)
- Python: Python 2.7.11 :: Anaconda custom (64-bit)
- GPU: GTX 1080
使用したリポジトリ
以前作成したCIFAR-10の画像認識のリポジトリにChainer v2用のブランチを作成しました。
インストール
Chainer Meetupのスライドにあるように、以下のコマンドでインストールできました。
念のため--no-cache-dir
をつけました。
$ pip install chainer --pre --no-cache-dir
$ pip install cupy --no-cache-dir
とりあえず実行してみる
Chainer v2の修正により後方互換性が壊れるので、動作しないことは予想できているのですがとりあえず実行してみます。
$ python src/train.py -g 0 -m vgg -p model\temp9 -b 100 --iter 200 --lr 0.1 --optimizer sgd --weight_decay 0.0001 --lr_decay_iter 100,150
以下のエラーが発生しました。
Traceback (most recent call last):
File "src\train.py", line 143, in <module>
cifar_trainer.fit(train_x, train_y, valid_x, valid_y, test_x, test_y, on_epoch_done)
File "c:\project_2\chainer\chainer-cifar\src\trainer.py", line 26, in fit
return self.__fit(x, y, valid_x, valid_y, test_x, test_y, callback)
File "c:\project_2\chainer\chainer-cifar\src\trainer.py", line 40, in __fit
loss, acc = self.__forward(x_batch, y[batch_index])
File "c:\project_2\chainer\chainer-cifar\src\trainer.py", line 75, in __forward
y = self.net(x, train=train)
File "c:\project_2\chainer\chainer-cifar\src\net.py", line 360, in __call__
h = self.bconv1_1(x, train)
File "c:\project_2\chainer\chainer-cifar\src\net.py", line 28, in __call__
h = self.bn(self.conv(x), test=not train)
TypeError: __call__() got an unexpected keyword argument 'test'
chainer.links.BatchNormalization
の__call__
の引数にtest
がないにもかかわらず渡しているというエラーです。
Chainer v2で動作するように修正する
chainer.functions.dropoutの呼び出し引数からtrainを削除
Chainer v2からはdropout
の引数train
が不要になるので削除します。
修正例:
修正前:
h = F.dropout(F.max_pooling_2d(h, 2), 0.25, train=train)
修正後:
h = F.dropout(F.max_pooling_2d(h, 2), 0.25)
chainer.links.BatchNormalizationの呼び出し引数からtestを削除
BatchNormalization
の引数test
が不要になるのでdropout
の場合と同様に削除します。
修正前:
class BatchConv2D(chainer.Chain):
def __init__(self, ch_in, ch_out, ksize, stride=1, pad=0, activation=F.relu):
super(BatchConv2D, self).__init__(
conv=L.Convolution2D(ch_in, ch_out, ksize, stride, pad),
bn=L.BatchNormalization(ch_out),
)
self.activation=activation
def __call__(self, x, train):
h = self.bn(self.conv(x), test=not train)
if self.activation is None:
return h
return self.activation(h)
修正後:
class BatchConv2D(chainer.Chain):
def __init__(self, ch_in, ch_out, ksize, stride=1, pad=0, activation=F.relu):
super(BatchConv2D, self).__init__(
conv=L.Convolution2D(ch_in, ch_out, ksize, stride, pad),
bn=L.BatchNormalization(ch_out),
)
self.activation=activation
def __call__(self, x): # trainを削除
h = self.bn(self.conv(x)) # testを削除
if self.activation is None:
return h
return self.activation(h)
学習中でない場合の処理をchainer.using_config('train', False)で括る
dropout
やBatchNormalization
の呼び出しから引数train
, test
を削除しました。
このままだとこれらの関数が学習中のモードで動作してしまいます。
Chainer v2からはwith chainer.using_config('train', ):
を使って学習中かどうかを制御します。
with chainer.using_config('train', False):
# 学習中でない場合の処理(テストデータの精度計算など)
学習中かどうかをchainer.config.trainで区別する
Chainer v2からchainer.config
が追加され、学習中かどうか、back propagationが必要かどうかなどをconfig
で判断できるようになりました。
私は今まで学習中かどうかを、以下のように自作関数のtrain
引数で判定していたのですが、v2からはtrain
引数は必要なくconfiguration.config.train
で判定すればよいです。
修正前:
def my_func(x, train=True):
if train:
# 学習中の処理
else:
# 学習中でない場合の処理
修正後:
def my_func(x):
if chainer.config.train:
# 学習中の処理
else:
# 学習中でない場合の処理
back propagationが不要な場合にchainer.using_config('train', False)で括る
back propagationが不要な処理をchainer.using_config('train', False)
で括ります。
今までchainer.Variable
生成時にvolatile
フラグをONにしていたケースが該当します。
Chainer v2 alphaでは必要ないが今後(beta以降で)必要になること
chainer.Variableの引数volatileを削除
v2 alphaの段階では残っていますが今後chainer.Variable
のvolatile
は削除される予定です。
volatile
の代わりにchainer.using_config('enable_backprop', )
で制御することになります。
chainer.functions
、chainer.links
の呼び出しにVariable
ではなくNumpy配列、Cupy配列を渡せるようになっているので、Variable
の生成処理も削除する選択肢もあると思います。
修正前:
x = Variable(xp.asarray(batch_x), volatile=Train)
修正後:
with chainer.using_config('enable_backprop', False):
x = Variable(xp.asarray(batch_x))
修正後の実行
c:\project_2\chainer-cifar>python src\train.py -g 0 -m vgg -p model\temp -b 100 --iter 200 --lr 0.1 --optimizer sgd --weight_decay 0.0001 --lr_decay_iter 100,150
DEBUG: nvcc STDOUT mod.cu
ライブラリ C:/Users/user_name/AppData/Local/Theano/compiledir_Windows-10-10.0.14393-Intel64_Family_6_Model_58_Stepping_9_GenuineIntel-2.7.11-64/tmpiwxtcf/265abc51f7c376c224983485238ff1a5.lib とオブジェクト C:/Users/user_name/AppData/Local/Theano/compiledir_Windows-10-10.0.14393-Intel64_Family_6_Model_58_Stepping_9_GenuineIntel-2.7.11-64/tmpiwxtcf/265abc51f7c376c224983485238ff1a5.exp を作 成中
Using gpu device 0: GeForce GTX 1080 (CNMeM is disabled, cuDNN 5105)
C:\Users\user_name\Anaconda\lib\site-packages\theano-0.8.2-py2.7.egg\theano\sandbox\cuda\__init__.py:600: UserWarning: Your cuDNN version is more recent than the one Theano officially supports. If you see any problems, try updating Theano or downgrading cuDNN to version 5.
warnings.warn(warn)
loading dataset...
start training
epoch 0 done
train loss: 2.29680542204 error: 85.5222222221
valid loss: 1.95620539665 error: 81.3800000548
test loss: 1.95627536774 error: 80.6099999845
test time: 1.04036228008s
elapsed time: 23.5432411172
epoch 1 done
train loss: 1.91133875476 error: 76.8000000185
valid loss: 1.83026596069 error: 73.6399999559
test loss: 1.8381768012 error: 73.2900000066
test time: 0.993011643337s
Chainer v2にする前からTheano周りでWarningが出ているのですが、動作しているようです。
最後に
Chainer v2向けの修正は難しくはないのですが、dropout
とBatchNormalization
の使用箇所が多かったので、その分修正量としては多くなりました。
修正の結果として、いくつかの関数が持っていた引数train
が不要になったのでコードが少しすっきりしました。
v1向けに実装した多くのコードがv2では動かなくなると思うので、v2が正式リリースされた直後は拾ってきたv1向けのコードを動かそうとしても動かないという事象が多く見られる気がします。