※この記事では, 一般的なニューラルネットワークの特徴, CNN のしくみなどは取り上げません. それらは各自で学習済みと想定しています.
前回
Google Colaboratory で Chainer を触ってみるvol.3 ~nodeを理解する~
進捗
隠れ層の数, 活性化関数, optimizer, 学習時のパラメータなどが学習時間と学習精度にどのような影響を及ぼすか, 「00 Colaboratory で Chainer を動かしてみよう」で実験中です. 今回は, 「活性化関数の影響」を確認しました.
理解したこと表
どの影響? | 学習時間 | 学習精度 | 備考 |
---|---|---|---|
隠れ層の数 | + 0.3秒/1layer | 8層でほぼ頭打ち | - |
隠れ層の node 数 | ほぼ変わらず | 500 node で +1.5% | GPU 使えば何でもよさそう |
活性化関数 | +2.04s(selu) | +2.7%(selu) | パラメータをいじるともう少し精度上がる |
epoch 数 | - | - | - |
batchsize | - | - | - |
optimizer | - | - | - |
活性化関数とは
node(ニューロン)への重みづけ入力とバイアスの総和が活性化(発火)するかどうかを決める関数です. 活性化した値が次の node への入力となります.
Chainer で用意されている活性化関数は, こちらにまとめられています. 今回は, Qiita - Chainerの活性化関数を可視化で取り上げられている9つの関数を試しました.
試行錯誤するコード
いつものやつです. そのほかのコードは, Vo.1で投稿したものと同じです.
# class_model.py
import chainer.functions as F
import chainer.links as L
from chainer import Chain
class MLPNew(Chain):
def __init__(self):
super(MLPNew, self).__init__()
with self.init_scope():
# Add more layers?
self.l1 = L.Linear(784, 200) # Increase output node as (784, 300)?
self.l2 = L.Linear(200, 200) # Increase nodes as (300, 300)?
self.l3 = L.Linear(200, 10) # Increase nodes as (300, 10)?
def forward(self, x):
h1 = F.tanh(self.l1(x)) # Replace F.tanh with F.sigmoid or F.relu?
h2 = F.tanh(self.l2(h1)) # Replace F.tanh with F.sigmoid or F.relu?
y = self.l3(h2)
return y
# do_train_and_validate.py
device = 0
n_epoch = 5 # Add more epochs?
batchsize = 256 # Increase/Decrease mini-batch size?
model = MLPNew()
classifier_model = L.Classifier(model)
optimizer = optimizers.SGD() # Default SGD(). Use other optimizer, Adam()?(Are there Momentum and AdaGrad?)
train_and_validate(
classifier_model, optimizer, train, validation, n_epoch, batchsize, device)
今回は, 下記部分の tanh を各活性化関数に変更すれば試せます.
h1 = F.tanh(self.l1(x)) # Replace F.tanh with F.sigmoid or F.relu?
h2 = F.tanh(self.l2(h1)) # Replace F.tanh with F.sigmoid or F.relu?
結果詳細
デフォルト(HandsOn 通りの設定)
- 隠れ層 : 3
- 隠れ層の node 数 : 200
- 活性化関数 : tanh ←今回はこれを変更する
- epoch 数 : 5
- batchsize : 256
- optimizer : SGD
活性化関数 | 合計学習時間 | 学習精度 |
---|---|---|
tanh(デフォルト) | 16.0598(基準) | 0.78984374(基準) |
clipped_relu | 16.2518(+0.2s) | 0.7798828(+1%) |
hard_sigmoid | 15.7152(-0.34s) | 0.46464843(-32.5%) |
sigmoid | 15.8886(-0.17s) | 0.47636718(-31.3) |
leaky_relu | 15.4042(-0.65s) | 0.78164065(-0.8%) |
relu | 16.0199(-0.04s) | 0.7799805(-1%) |
elu | 16.5385(+0.48s) | 0.7970703(+0.8%) |
selu | 18.0986(+2.04s) | 0.8165039(+2.7%) |
softplus | 15.8983(-0.16s) | 0.74472654(-4.5%) |
selu 関数が一番良好な結果と思われます. sigmoid 関数はダメそうですね. | ||
あと, 表に書き忘れていますが, 学習結果とテスト結果に大きな差はないので, 過学習は発生してません. |
selu のパラメータをいじってみる
selu に関する公式の説明には, α や scale について設定があるので, こちらをいじって結果を比較しました.
def forward(self, x):
h1 = F.selu(self.l1(x),alpha=1.6732632423543772, scale=1.0507009873554805)
h2 = F.selu(self.l2(h1),alpha=1.6732632423543772, scale=1.0507009873554805)
y = self.l3(h2)
return y
α | scale | 合計学習時間 | 学習精度 |
---|---|---|---|
未設定 | 未設定 | 18.0986 | 0.8165039 |
1.6732632423543772 | 1.0507009873554805 | 17.8415 | 0.8162109 |
2.4 | 1.0507009873554805 | 17.9607 | 0.83095706 |
1.6732632423543772 | 1.5 | 17.8783 | 0.8292969 |
2.4 | 1.5 | 17.695 | 0.8381836 |
α, scale どちらも大きい方が精度は良くなりそうです. これらパラメータは学習時間に影響はほぼなさそうです. ほんとは関数の定義をきちんと理解すべきですが, 現時点はここまでにとどめます. selu 以外の関数にもパラメータはありますので, チューニングすれば精度が逆転するかもしれませんね. |
まとめ
活性化関数を変更すると, 学習時間と精度に差が出ることがわかりました. ただ, sigmoid 関数以外であれば顕著な差はなさそうです. 各関数にはそれぞれパラメータがありますので, その値をチューニングすればもっと精度が上がるかもしれません.
次回
DeepLearning のエポック数とバッチサイズを理解する.