活性化関数の性質調査:傾き0が学習を進めるのか?

目的

今回は、reluの正答率が高いのは、0以下の時値が0で傾きも0であることに起因していると仮説を立てその検証を行う。

条件

なお検証用のプログラムこれまでと同じ

import tensorflow as tf
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from tensorflow.keras.utils import to_categorical
import time
# CIFAR-10 データの読み込み
(x_train, y_train), (x_test, y_test) = cifar10.load_data()

# 正規化
x_train = x_train.astype('float32') / 255
x_test = x_test.astype('float32') / 255

# ラベルを one-hot エンコーディング
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)

# モデルの構築
model = Sequential([
    Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=(32, 32, 3)),
    Conv2D(32, (3, 3), activation='relu'),
    MaxPooling2D(2, 2),
    Dropout(0.25),
    Conv2D(64, (3, 3), activation='relu', padding='same'),
    Conv2D(64, (3, 3), activation='relu'),
    MaxPooling2D(2, 2),
    Dropout(0.25),
    Flatten(),
    Dense(512, activation='relu'),
    Dropout(0.5),
    Dense(10, activation='softmax')
])

# モデルのコンパイル
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

# モデルの訓練
history = model.fit(x_train, y_train, batch_size=64, epochs=50, validation_data=(x_test, y_test), verbose=2)

# モデルの評価
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
print("time", time.time() - start_t)

loss = history.history['loss']
accuracy = history.history['accuracy']
val_loss = history.history['val_loss']
val_accuracy = history.history['val_accuracy']

import pandas as pd
df = pd.DataFrame({'loss': loss, 'accuracy': accuracy, 'val_loss': val_loss, 'val_accuracy': val_accuracy})
df.to_csv('fime_name.csv', index=False)

を使用する。

今回は、以前使用した平方根を180対称にした関数とtanhで0以下は0にするという関数を作成し、元の関数と比較する。それぞれ、rectified_sqrt, rectified_tanhとする。それぞれの関数は、以下のようになる。

tanh

def rectified_tanh(x):
    return tf.where(x <= 0,
                    tf.cast(0, x.dtype),
                    tf.nn.tanh(x))

平方根

def rectified_sqrt(x):
    return tf.where(x <= 0,
                    tf.cast(0, x.dtype),
                    tf.sqrt(x + g_aa) - tf.sign(x)*g_a)

結果

reluとも比較するため3つの関数の結果を並べて示す。

accuracy, lossは学習用データの結果、val_accuracy, lossはテストデータの結果

relutanhrectified_tanh
function
accuracy
loss
csvreluダウンロードtanhダウンロードrectified_tanhダウンロード

relusqrt_180_degree_symmetry g_a=0.1rectified_sqrt
g_a = 0.1
function
accuracy
loss
csvreluダウンロードsqrt_01ダウンロードrectified_sqrtダウンロード

rectified_tanh:tanhと比べてaccuracy, loss 共にreluに近い形になっている。val_accuracyもtanhの7.5付近より大きくなり、reluとほぼ同じ0.8まで上がっている。tanhよりもval_…と無印の差が広がっており過学習の傾向が出ている。ただし、reluと比べると若干であるが過学習の傾向は少ないように見える。reluはval_lossが学習を重ねると増加傾向にあるが、rectified_tanhの方はその様子は見られない、

rectified_sqrt : reluとsqrt_180_degree_symmetryの中間的な性質といえる。sqrt_180_degree_symmetryよりも正答率が向上している。しかし、reluにはわずかに届いていない。学習の最後の方は若干過学習の傾向がみられるが、reluと比べるとその傾向は小さい。ただし、学習の進みが悪いだけのようにも見える。

結論:

tanh, sqrt 共に xが0以下の時 0 とする reluのような関数にした結果、どちらも正答率が向上した。このことから、0以下を常に0にすると正答率を上げることができるといえる。ただし、同時に過学習の傾向が現れる。