分類タスクでやることは特徴抽出及び次元削減なので,これを達成するために,入力側から順次ユニット数を少なくするのがセオリーとされています.
input_shapeを使わない書き方
model = keras.Sequential([
keras.layers.Input(shape=<-- a -->),
keras.layers.Dense(<-- b -->, activation='<-- c -->'),
keras.layers.Dense(<-- d -->, activation='<-- e -->')
])
極端な話,精度さえ良ければなんでもいいです.
サイズ300*300の15枚のカラー画像を3つに分類する場合
カラー画像ということはRGBの3チャンネルあるので,input_shape=(300, 300, 3)
になります.
model = keras.Sequential([
keras.layers.Input(shape=(300, 300, 3)),
keras.layers.Flatten(), # Denseで扱うためにFlattenする必要がある
keras.layers.Dense(2048, activation='relu'),
keras.layers.Dense(256, activation='relu'),
keras.layers.Dense(3, activation='softmax')
])
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
flatten (Flatten) (None, 270000) 0
dense (Dense) (None, 2048) 552962048
dense_1 (Dense) (None, 256) 524544
dense_2 (Dense) (None, 3) 771
=================================================================
Total params: 553,487,363
Trainable params: 553,487,363
Non-trainable params: 0
_________________________________________________________________
順次ユニット数を少なくする考えのもとで書くとこのようになりますが,画像が(300, 300, 3)
とデカいのでFlattenしたあとは$300\times 300\times 3=270,000$となり,Dense
のみで推論しようとすると大抵の場合,メモリ不足で計算不可能です.
そこで,CNNを使って次のようにします.
model = keras.Sequential([
keras.layers.Input(shape=(300, 300, 3)),
keras.layers.Conv2D(32, (7, 7), activation='relu'),
keras.layers.MaxPooling2D(),
keras.layers.Conv2D(64, (3, 3), activation='relu'),
keras.layers.MaxPooling2D(),
keras.layers.Conv2D(128, (3, 3), activation='relu'),
keras.layers.MaxPooling2D(),
keras.layers.Conv2D(256, (3, 3), activation='relu'),
keras.layers.GlobalAveragePooling2D(),
keras.layers.Dense(128, activation='relu'),
keras.layers.Dense(32, activation='relu'),
keras.layers.Dense(3, activation='softmax')
])
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 294, 294, 32) 4736
max_pooling2d (MaxPooling2D (None, 147, 147, 32) 0
)
conv2d_1 (Conv2D) (None, 145, 145, 64) 18496
max_pooling2d_1 (MaxPooling (None, 72, 72, 64) 0
2D)
conv2d_2 (Conv2D) (None, 70, 70, 128) 73856
max_pooling2d_2 (MaxPooling (None, 35, 35, 128) 0
2D)
conv2d_3 (Conv2D) (None, 33, 33, 256) 295168
global_average_pooling2d (G (None, 256) 0
lobalAveragePooling2D)
dense (Dense) (None, 128) 32896
dense_1 (Dense) (None, 32) 4128
dense_2 (Dense) (None, 3) 99
=================================================================
Total params: 429,379
Trainable params: 429,379
Non-trainable params: 0
_________________________________________________________________
GlobalAveragePooing2Dより前が特徴抽出器,それより後が分類器として役割を果たし,Dense
のみで構成されるモデルよりメモリ消費量が少なく推論できます.
それぞれでmodel.summary()
を実行してみてもらうと,trainable params
の数が大きく違うと思います.これはメモリ使用量に直結します.
したがって,メモリ制約からConv2D
を使う必要があります.同様に,精度面からもConv2D
を使う方が良いのですが,詳しくは帰納バイアスについて調べてください.
ちなみに,これらレイヤに入れることのできるパラメータはドキュメントを参照するとわかりますが,質問で聞いているパラメータだけではありません.
Denseにもあるパラメータで考える必要があるのは,特にレイヤの初期値が挙げられます.ドキュメントで言われるところのkernel_initializer
です.
デフォルト値でkernel_initializer='glorot_uniform'
が割り当てられいることがわかると思います.これは原点付近で線形である関数の条件のもとで最適化されたランダム初期化法を行いますが,ReLUファミリーの活性化関数ではこれに当てはまらないためkernel_initializer='he_uniform'
を使うなどの活性化関数に合わせた工夫が必要です.
つまり,上のCNNは次のように修正することになります.
model = keras.Sequential([
keras.layers.Input(shape=(300, 300, 3)),
keras.layers.Conv2D(32, (7, 7), activation='relu', kernel_initializer='he_uniform'),
keras.layers.MaxPooling2D(),
keras.layers.Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform'),
keras.layers.MaxPooling2D(),
keras.layers.Conv2D(128, (3, 3), activation='relu', kernel_initializer="he_uniform"),
keras.layers.MaxPooling2D(),
keras.layers.Conv2D(256, (3, 3), activation='relu', kernel_initializer='he_uniform'),
keras.layers.GlobalAveragePooling2D(),
keras.layers.Dense(128, activation='relu', kernel_initializer='he_uniform'),
keras.layers.Dense(32, activation='relu', kernel_initializer='he_uniform'),
keras.layers.Dense(3, activation='softmax')
])
詳しくは次の記事を参照してください.
これら以外にもL1,L2正則化を行うパラメータや,他にもよく使われるDropoutやBatchNormalization1レイヤなどがありますので,体系的に勉強されることをお勧めします.