6.4 正則化

「ゼロから作るDeep Learning」 6章4節の内容を学習しながら、Ivoryライブラリで正則化の評価を行います。

6.4.1 過学習

過学習を起こしてみます。

from ivory.core.trainer import sequential
from ivory.datasets.mnist import load_dataset

data_train, data_test = load_dataset()
data_train.length = 300  # データセットの大きさを制限する。
data_test.length = 300
data_train.batch_size = 100
data_train.epochs = 200
data_train.random = True
epoch_data = {"train": data_train[:], "test": data_test[:]}

net = [
    ("input", 784),
    (6, "affine", 100, "relu"),  # 深いネットワークを作成する。
    ("affine", 10, "softmax_cross_entropy"),
]

trainer = sequential(net, metrics=["accuracy"])
trainer = trainer.fit(data_train, epoch_data=epoch_data)
df = trainer.to_frame()
df.tail()

[1] 2019-06-12 17:37:23 (5.42s) python3 (5.42s)

epoch data accuracy
397 198 test 0.716667
398 199 train 1.000000
399 199 test 0.723333
400 200 train 1.000000
401 200 test 0.716667
import altair as alt

def plot(df):
    y = alt.Y("accuracy", scale=alt.Scale(domain=[0, 1]))
    return (
        alt.Chart(df)
        .mark_line()
        .encode(x="epoch", y=y, color="data")
        .properties(width=200, height=160)
    )

plot(df)

[2] 2019-06-12 17:37:29 (62.5ms) python3 (5.48s)

6.4.2 Weight decay

重みを\mathbf{W}としたときに、損失関数に正則化項\frac12\lambda\mathbf{W}^2を加えて、大きな重みに対してペナルティを課します。また、逆伝搬においては、正則化項の微分\lambda\mathbf{W}を加算します。Affineレイヤは、weight_decay状態を持っています。TrainerインスタンスからAffineレイヤをひとつ取得します。

affine = trainer.model.layers[0]
affine.states

[8] 2019-06-12 17:37:29 (15.5ms) python3 (5.62s)

[<State('Affine.1.weight_decay', ()) at 0x193efa9abe0>]

weight_decay属性で直接アクセスできます。

affine.weight_decay

[9] 2019-06-12 17:37:29 (15.6ms) python3 (5.64s)

<State('Affine.1.weight_decay', ()) at 0x193efa9abe0>

値を確認します。

affine.weight_decay.d

[10] 2019-06-12 17:37:29 (31.3ms) python3 (5.67s)

0

初期値はゼロです。つまり、これまでWeight Decayを使ってきませんでした。有効化するためにゼロ以上の値に設定したいと思います。ただし、現在のネットワークには複数のAffineレイヤがあります。一括で設定するために、Trainerインスタンスのinitメソッドをここでも用います。Trainerインスタンスはそのinitメソッドで、ネットワークの初期化を行います。このとき、個々の変数がどのように初期化されるかまでは把握しません。レイヤがinitメソッドに与えられたキーワード引数のキーを属性に持っていた場合には、その値で初期化します。

df = trainer.init(weight_decay=0.1).to_frame()
df.tail()

[11] 2019-06-12 17:37:29 (3.67s) python3 (9.34s)

epoch data accuracy
397 198 test 0.696667
398 199 train 0.873333
399 199 test 0.680000
400 200 train 0.870000
401 200 test 0.673333
plot(df)

[12] 2019-06-12 17:37:33 (46.9ms) python3 (9.39s)

6.4.3 Dropout

活性化レイヤの後にDropout層を追加します。

net = [
    ("input", 784),
    (6, "affine", 100, "relu", "dropout"),
    ("affine", 10, "softmax_cross_entropy"),
]

[13] 2019-06-12 17:37:33 (15.6ms) python3 (9.41s)

Trainerインスタンスは、同じ設定でネットワークだけ別のものに入れ替えることができます。

trainer.set_net(net)
layers = trainer.model.layers
layers[:4]

[14] 2019-06-12 17:37:33 (31.2ms) python3 (9.44s)

[<Affine('Affine.8', (784, 100)) at 0x193f1b6e9e8>,
 <Relu('Relu.7', (100,)) at 0x193f1b6eac8>,
 <Dropout('Dropout.1', (100,)) at 0x193f1b6e588>,
 <Affine('Affine.9', (100, 100)) at 0x193f1b6ea58>]

Dropoutレイヤはdropout_ratio状態を持っています。

layers[2].dropout_ratio

[15] 2019-06-12 17:37:33 (15.6ms) python3 (9.45s)

<State('Dropout.1.dropout_ratio', ()) at 0x193f1b6e668>

初期値を確認します。

layers[2].dropout_ratio.d

[16] 2019-06-12 17:37:33 (15.6ms) python3 (9.47s)

0.5

訓練を実施します。値を0.15に設定して訓練します。

data_train.epochs = 300
df = trainer.init(dropout_ratio=0.15).to_frame()
plot(df)

[17] 2019-06-12 17:37:33 (7.26s) python3 (16.7s)