Transfer Learning 을 할때에 BatchNormalization layer를 학습시키는지 아닌지에 따라서 결과차이가 차이남
from tensorflow.keras import layers
f1 = tfa.metrics.F1Score(num_classes = CLASSES, average='macro')
x = tf.keras.layers.Input(shape=(400,400,3), name = "image")
base_model = tf.keras.applications.EfficientNetB3(
include_top=False, weights='imagenet',input_tensor = x)
base_model.summary()
for layer in base_model.layers:
layer.trainable = False
for layer in base_model.layers:
print(layer)
print(layer.trainable)
model = Sequential()
model.add(base_model)
model.add(GlobalAveragePooling2D())
model.add(layers.BatchNormalization())
model.add(Dropout(0.2))
model.add(Dense(CLASSES))
model.add(tf.keras.layers.Activation('softmax', dtype='float32'))
model.compile(optimizer = Adam(lr = 0.001), loss = tf.keras.losses.BinaryCrossentropy(), metrics=['accuracy', f1])
model.summary()
이렇게 베이스 모델에 모든 레이어에 대해서 False를 주고, trainable한지 출력했을때 각 모든 레이어에 대해서 False가 나오는 것을 알 수 있다. 빨강색으로 표시한 것처럼 BatchNormalization에도 False가 되어있다.
참고로, trainable 설정을 해주지 않으면 모든 레이어에 대해서 학습 가능하도록 True로 되는 것이 default 값인 걸 확인헀다. Trainable에 관한 설정을 하지 않고 마찬가지로 trainable 한지 모든 레이어에 대해서 출력하면 모든 레이어에 대해서 다 학습가능하도록 되어있는 것을 확인했다.
케라스 efficientnet finetuning관련 글을 살펴보면 basemodel의 모든 레이어에 대해서 Freeze 시키고 학습을 시켰을 경우에 정확도가 0.6~0.7정도가 나오는 반면에 , 커스텀한 나의 데이터셋을 이용했을때
epoch을 200으로해도 accuracy가 0.2~0.3에 머문다.. 뭐가 문제일까 하고 더 구글링을 해봤는데 BatchNormalization layer가 학습을 하는지 안하는지에 따라 결과값이 차이가 난다는 글을 보았다. (맨 아래 링크 )
for layer in base_model.layers:
if isinstance(layer, layers.BatchNormalization):
layer.trainable = True
else:
layer.trainable = False
for layer in base_model.layers:
print(layer)
print(layer.trainable)
model.compile(optimizer = Adam(lr = 0.001), loss = tf.keras.losses.BinaryCrossentropy(), metrics=['accuracy', f1])
BatchNormalization 에 대해서만 True로 하고 나머지 layer를 False로 주고 다시 컴파일을 한 후에, 학습을 진행해보았다. 마찬가지로 trainable 한지 아닌지에 대해서 각 레이어에 대해서 출력을 해보니
이제 BatchNormalization layer만 Freeze 시키지 않고 나머지 레이어는 다 False로 둔 상태로 다시 학습을 진행헀다.
아직 에포크 11임에도 불구하고 정확도가 0.77정도로 올라갔다. BatchNormalization이 어떻게 학습에 관여하는지에 따라서 이렇게 결과가 차이가났다 ! 오늘도 하나 새롭게 배웠다 : )
This weird behavior comes from the BatchNormalization layer. It seems like there is a bug, when keras (2.2.4) is running the validation in inference mode. However we could ignore this, because besides the weird validation accuracy scores, our layer still learns, as we can see in the training accuracy (Read more about different normalization layers here). But to fix it, we can make the BatchNormalization layer trainable:
<출처 : http://digital-thinking.de/keras-transfer-learning-for-image-classification-with-effificientnet/>
To understand why this happens we need to understand how the BN works. When the network is in training mode, the mini-batch statistics of BN are used for training the network; when the network is in inference mode, we use the moving mean/var learned during the training. (training mode 시에 mean, variance를 계산한 후에 버리는 것이 아니라 inference모드에서의 사용을 위해서 지수이동평균으로 축적한다)That's all good. The problem is how the layer behaves when it is frozen. Its side-effects are more profound when we use fine-tuning and Transfer Learning.
You see, when frozen and while in training mode the BN continues to use the mini-batch statistics for scaling the training data. This causes the unfrozen/trainable layers to adapt to the scale of the data. Unfortunately during inference mode (predictions) the network will switch to the moving mean/var. If the moving mean/var is different that the mini-batch statistics the data are scaled differently causing massive discrepancies on the accuracy. If you want more info, have a look at the PR.
<출처 :https://github.com/keras-team/keras/issues/9214>
파라미터가 총 4개 (Mean, Variance, Gamma, Beta) 가 사용되는데 레이어의 인풋을 mean, variance로 정규화한후 Gamma를 곱하고 Beta를 더해주는게 간단한 설명이다.
여기서 Gamma , Beta는 딥러닝 모델의 학습시에 Backpropagation을 통해서 적절한 값으로 학습된다. Gamma는 1, Beta는 0으로 초기화된다.
그러나 Mean, Variance는 Backpropagation으로 학습되는 것이 아니고 training mode / inference mode 시에 사용하는 값에 차이가 있다.
batchnormalization 레이어에서 layers.trainable = False 는 그대로 레이어를 고정하여 훈련중 내부상태가 변화하지 않으며 반드시 추론모드에서 실행됨을 의미한다(batch normalization layer에서만 국한됨 , 즉 이동평균과 이동 분산을 사용하여 현재 배치를 정규화하지 않고 사용한다는 의미 )
* 주의 : compile() 호출한 뒤에 trainable 속성값이 변경되면 compile 다시 호출 할 때까지 모델에 새로운 값이 적용되지 않기 때문에 trainable 속성 변경 뒤에는 compile을 다시 시켜줘야함
http://digital-thinking.de/keras-transfer-learning-for-image-classification-with-effificientnet/
'Deep learning' 카테고리의 다른 글
Imbalance data training (0) | 2021.09.14 |
---|---|
Trainable 정리 (0) | 2021.09.13 |
Tensorflow Batchnormalization (전이학습) 중요한 사항 (0) | 2021.09.13 |
EfficientNetV2 (0) | 2021.08.30 |
Keras Tuner Custom objective 설정 방법 (0) | 2021.08.25 |