Machine Learning/[Kaggle Course] ML (+ 딥러닝, 컴퓨터비전)

[Kaggle Course] Dropout, Batch Normalization

WakaraNai 2020. 12. 26. 23:29
728x90
반응형

딥러닝의 세계에는 dense layers 외에도 더 있습니다.

12종류가 넘는 layer를 한 모델에 추가할 수도 있죠

전처리 또는 변형을 다른 방식으로 한다거나, 뉴런 간 연결 관계를 새롭게 정의할 수도 있고요

 

이번 시간에는 특별한 두 종류의 layers에 대해 알아봅니다.

이들은 neurons을 가지고 있지 않지만, model을 개선시켜주는 기능을 추가해주죠.

 

 

Dropout Layer 

overfitting을 수정할 때 사용

 

traindata 속 가짜 패턴을 학습한 neuron으로 인해 생긴 overfitting을 처리해보려 합니다.

'가짜 패턴'을 알아채기 위해선 network는 종종 특정한 가중치들의 조합들,

즉 가중치의 'conspiracy'에 의존합니다.

너무 구체적이면, 망가지기 쉬우므로 하나를 제거하면 conspiracy는 흩어집니다.

 

이러한 conspiracies를 부수기 위해,매 훈련마다 layer's 입력 unit의 일부분을 무작위로 제거합니다(dropout)

이러면 train data 속 가짜 패턴을 network가 학습하기 어려워지죠.

대신 더 크고 일반적인 패턴을 찾아야하며, 그 패턴의 가중치는 new data에서도 잘 돌아갈만큼 강력해야 합니다.

50% dropout을 2개의 hidden layers에 추가한 이미지

dropout이 여러 networks의 ensemble(앙상블)을 생성하는 것처럼 보입니다.

하나의 큰 network에서 산출된 예측은 오래 가지 못하며, 그 대신 작은 networks 모여 하나가 되면 예측은 오래가죠.

그 하나가 된 networks(=committee)의 각각의 구성요소는 서로 다른 실수를 일으킵니다.

그러나 동시에 옳은 답을 내놓죠. 그러므로 전체를 committe로 만드는 것이 각각의 구성요소보다 낫습니다.

(Random forest가 decision trees의 ensemble이란 점과 같은 아이디어 입니다.)

 

Add Dropout

Keras의 'rate' argument로 input unit 중 몇 퍼센트를 제거할지 정합니다.

'Dropout' layer으로 적용하고 싶었던 layer 바로 전에 써주면 됩니다.

30% 비율로 dropout을 적용한 코드입니다.

keras.Sequential([
    # ...
    layers.Dropout(rate=0.3), # apply 30% dropout to the next layer
    layers.Dense(16),
    # ...
])

 

 

 

Batch Normalization (bachnorm)

훈련 속도가 느리거나 불안정할 때 사용

 

일반적으로 모든 데이터에 같은 크기의 neural networks를 적용합니다. 사이킷런의 StandardScaler 또는 MinMaxScaler로요. 그 이유는 SGD는 data가 생성한 활성화된 크기에 비례하여( in proportion to how large an anctivation the data produces) network의 가중치를 조정하기 때문입니다. 저마다 크게 차이나는 크기들의 activations(활성화)가 일어날 경향이 있는 features는 훈련을 불안정하게 합니다.

 

그러니, network에 data를 넣기 전 normalize를 하거나 network 속에서 normalization을 해야 합니다.

이 기능은 "batch normalization layer'에서 가능합니다. 이 layer는 각 bach가 들어오는 순서대로 살펴봅니다.

먼저 그 batch의 평균과 표준편차(standard deviation)으로 정규화를 한 다음, 훈련 가능한 크기로 data를 바꿔주는 두 개의 parameter를 적용합니다. 실제로, bachnorm은 입력값의 크기를 조정하는 기능을 수행합니다.

 

대부분, batchnorm은 최적화된 process의 보조도구로 이용됩니다. (가끔은 성능 예측에도 도움됩니다.)

bactchnorm이 있는 모델은 훈련을 완료하기 위해 더 적은 epochs를 넣어야 합니다. 

게다가 batchnorm은 훈련 도중 멈춰버리는 등의 여러 문제를 해결할 수 있습니다.

특히, 훈련 도중에 문제가 생긴다면, model에 batchnorm을 적용해보세요.

 

>>> data 크기들이 들쭉날쭉하면 훈련 성능이 떨어지니 깔끔하게 다듬어 보려 하는 것

 

 

 

Add Batch Normalization

+) 만약 network의 첫번째 layer에 추가하고 싶다면 adaptive preprocessor를 해야합니다. (ex  StandardScaler)

# way1 - layer 이후에 적용하기
layers.Dense(16, activation='relu'),
layers.BatchNormalization(),

# way2 - layer와 activation function 사이에
layers.Dense(16),
layers.BatchNormalization(),
layers.Activation('relu'),

 

 

 

Ex. Using Dropout and Batch Normalization

Red Wine dataset의 모델을 개선해봅시다.

capacity를 증가시키되 dropout을 추가시켜 overfitting을 조절합니다.

batch normalization도 적용해서 최적화에 다가가는 속도도 빠르게 해봅시다.

 

Setup

# Setup plotting
import matplotlib.pyplot as plt

plt.style.use('seaborn-whitegrid')
# Set Matplotlib defaults
plt.rc('figure', autolayout=True)
plt.rc('axes', labelweight='bold', labelsize='large',
       titleweight='bold', titlesize=18, titlepad=10)


import pandas as pd
red_wine = pd.read_csv('../input/dl-course-data/red-wine.csv')

# Create training and validation splits
df_train = red_wine.sample(frac=0.7, random_state=0)
df_valid = red_wine.drop(df_train.index)

# Split features and target
X_train = df_train.drop('quality', axis=1)
X_valid = df_valid.drop('quality', axis=1)
y_train = df_train['quality']
y_valid = df_valid['quality']

 

Add dropout -> layer의 unit 개수를 필수적으로 늘려야 함

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Dense(1024, activation='relu', input_shape=[11]),
    layers.Dropout(0.3),
    layers.BatchNormalization(),
    layers.Dense(1024, activation='relu'),
    layers.Dropout(0.3),
    layers.BatchNormalization(),
    layers.Dense(1024, activation='relu'),
    layers.Dropout(0.3),
    layers.BatchNormalization(),
    layers.Dense(1),
])

 

model.compile(
    optimizer='adam',
    loss='mae',
)

history = model.fit(
    X_train, y_train,
    validation_data=(X_valid, y_valid),
    batch_size=256,
    epochs=100,
    verbose=0,
)


# Show the learning curves
history_df = pd.DataFrame(history.history)
history_df.loc[:, ['loss', 'val_loss']].plot();

 

 

 

이전 튜토리얼의 결과와 비교해보세요. 

훈련 전에 data를 일반화해주니 훨씬 더 나은 성능을 보입니다.

실세계의 data에서도 batch normalization이 된다는 것은 더 어려운 dataset에서도 적용 가능하다는 것을 의미합니다.  

 


 

Exercise

dataset은 이전 튜토리얼의 Exercise와 동일하게 Spotify dataset입니다.

이전 튜토리얼의 Exercise의 결과와 dropout 적용 결과, batch normalization 적용 결과 각각을 비교해보려 합니다.

(y축의 숫자들을 자세히 보시면 점점 더 세밀한 그래프가 되고 있으며, 최소 validation loss도 작아지고 있다는 점!)

 

1-1. Previous Result

먼저 이전 튜토리얼의 결과를 보겠습니다.

Minimum Validation Loss: 0.1943

 

1-2. Add two 30% dropout layers, one after 128 and one after 64

model = keras.Sequential([
    layers.Dense(128, activation='relu', input_shape=input_shape),
    layers.Dropout(rate=0.3),
    layers.Dense(64, activation='relu'),
    layers.Dropout(rate=0.3),
    layers.Dense(1)
])
model.compile(
    optimizer='adam',
    loss='mae',
)
history = model.fit(
    X_train, y_train,
    validation_data=(X_valid, y_valid),
    batch_size=512,
    epochs=50,
    verbose=0,
)
history_df = pd.DataFrame(history.history)
history_df.loc[:, ['loss', 'val_loss']].plot()
print("Minimum Validation Loss: {:0.4f}".format(history_df['val_loss'].min()))

Minimum Validation Loss: 0.1936

learning curves를 보면 validation loss는 거의 최소값 근처에 머물러 있고, training loss는 계속 감소하고 있습니다. 

그러므로 이럴 때 dropout을 추가한 것은 overfitting을 막기에 좋은 시도입니다. 

게다가 network가 가짜 패턴을 찾아가게 하지 못하도록 하였기에, dropout은 network가 실제 패턴을 찾아가게 해주었으며 덕분에 validation loss를 어느 정도 개선할 수 있습니다.

 

 

 

 

이번에는 Concrete dataset에 대해서 batch normalization 적용 여부에 따른 결과의 차이를 보려 합니다

 

Setup

import pandas as pd

concrete = pd.read_csv('../input/dl-course-data/concrete.csv')
df = concrete.copy()

df_train = df.sample(frac=0.7, random_state=0)
df_valid = df.drop(df_train.index)

X_train = df_train.drop('CompressiveStrength', axis=1)
X_valid = df_valid.drop('CompressiveStrength', axis=1)
y_train = df_train['CompressiveStrength']
y_valid = df_valid['CompressiveStrength']

input_shape = [X_train.shape[1]]

 

2-1. WithOut batch normalization (unstandardized data)

model = keras.Sequential([
    layers.Dense(512, activation='relu', input_shape=input_shape),
    layers.Dense(512, activation='relu'),    
    layers.Dense(512, activation='relu'),
    layers.Dense(1),
])
model.compile(
    optimizer='sgd', # SGD is more sensitive to differences of scale
    loss='mae',
    metrics=['mae'],
)
history = model.fit(
    X_train, y_train,
    validation_data=(X_valid, y_valid),
    batch_size=64,
    epochs=100,
    verbose=0,
)

history_df = pd.DataFrame(history.history)
history_df.loc[0:, ['loss', 'val_loss']].plot()
print(("Minimum Validation Loss: {:0.4f}").format(history_df['val_loss'].min()))

Minimum Validation Loss: 24.9053

가중치 초기화 덕분에 수렴은 하지만, 꽤나 큰 숫자로 수렴하네요;; ㅎㅎ

이런 dataset이라면 학습은 어렵습니다.

 

2-2. Add Batch Normalization Layers

모든 Dense layer 전에 Batch Normalization Layer를 추가해줍니다

(맨 첫 번째 dense layer에 꼭 input_shape 넣기 잊지마세요!)

# YOUR CODE HERE: Add a BatchNormalization layer before each Dense layer
model = keras.Sequential([
    layers.BatchNormalization(),
    layers.Dense(512, activation='relu', input_shape=input_shape),
    layers.BatchNormalization(),
    layers.Dense(512, activation='relu'),
    layers.BatchNormalization(),
    layers.Dense(512, activation='relu'),
    layers.BatchNormalization(),
    layers.Dense(1),
])
model.compile(
    optimizer='sgd',
    loss='mae',
    metrics=['mae'],
)
EPOCHS = 100
history = model.fit(
    X_train, y_train,
    validation_data=(X_valid, y_valid),
    batch_size=64,
    epochs=EPOCHS,
    verbose=0,
)

history_df = pd.DataFrame(history.history)
history_df.loc[0:, ['loss', 'val_loss']].plot()
print(("Minimum Validation Loss: {:0.4f}").format(history_df['val_loss'].min()))

Minimum Validation Loss: 3.8686

24에서 3까지 줄어들었습니다!

 

batch normalization을 추가하니 첫 시도(첫번째 epoch)부터 극적으로 개선된 모습을 보입니다.

data의 크기를 해당 network를 통과하기 용이한 크기로 변형했기에 가능했습니다.

 

이젠 어려운 dataset에 대한 model 훈련도 잘 할 수 있을 겁니다.

batch normalization을 사용한다면요

 

728x90
반응형