*Kaggle에서 제공하는 Deep Learning Tutorial을 학습하며 번역한 내용입니다.
Introduction
여태까지는 regression문제를 해결하는 것만을 공부했지만 이번에는 classification이라는 도다른 machine learning problem을 해결해 보자. loss funcion과 final layer가 만들어내는 outputs의 차이를 제외하고는 이제까지 배운 걸 적용하면 된다.
Binary Classification
두 집단의 분류문제는 machine learning에서 아주 흔한 문제이다. 두 집단으로 나누는 문제를 binary classification problem이라고 한다.
raw data에서 class들은 Yes/No, Dog/Cat처럼 표현 가능할 것이다. 이에 0,1처럼 class label을 붙여줘야 한다. numeric label을 붙여서 neural network가 data를 사용할 수 있도록 해야한다.
Accuracy and Cross-Entropy
Accuracy는 classification problem에서 성공을 측정하는 metrics중 하나이다. accuracy = 옳은 예측 / 전체 예측이다.
항상 옳은 예측만 하는 경우 accuracy는 1이된다.
하지만 accuracy는 loss function으로 사용할 수 없다. SGD는 부드럽게 변하는 loss function이 필요한데 accuracy는 급격하게 뛰기 때문에 그렇다. 그래서 loss function으로 사용하기 위해 선택한 것이 substitute이다. 이것은 cross-entropy function이다.
loss function이 training중에 network가 가야할 목표를 정의한다고 했다. regression에서 우리의 목표는 예측값과 실제값의 차이를 줄이는 것이고 MAE를 사용해서 이 거리를 계산하도록 했다.
classification에서 우리가 대신 사용하는 것은 확률들 사이의 거리이다. 이것을 cross-entropy가 제공한다. cross-entropy는 확률사이의 거리를 측정해준다.
Cross-entropy는 잘못된 확률 예측에 패널티를 준다.
network의 예측률이 1이 되길 원한다. 예측율이 1에 다다를 수록 cross-entropy loss는 작아진다.
왜 cross-entropy를 사용하냐?는 잠시 제쳐두고 classification loss에서는 cross-entropy를 사용하고 다른 metrics는 성능향상을 위해 사용하자는 것만 기억하자.
Making Probabilities with the Sigmoid Function
cross-entropy와 accuracy function은 input으로 probabilities를 필요로 한다. dense layer에서 만들어지는 실제 valued output을 확률로 만들기 위해서는 새로운 activation function이 필요하다. 우리는 sigmoid activation을 사용한다.
최종 class 예측을 얻기 위해서 threshold probability를 정의한다. 보통 이 값은 0.5이다. 0.5보다 작으면 0 label을 주고 0.5보다 크면 1 label을 준다.
Example - Binary Classification
lonosphere dataset은 지구 대기권의 ionosphere layer에 집중된 rada signals로부터 얻은 정보들을 담고 있다. signal이 물체를 찾았는지 혹은 그냥 빈 공간을 보고 있는지 결정해보자.
import pandas as pd
from IPython.display import display
ion = pd.read_csv('../input/dl-course-data/ion.csv', index_col=0)
display(ion.head())
df = ion.copy()
df['Class'] = df['Class'].map({'good': 0, 'bad': 1})
df_train = df.sample(frac=0.7, random_state=0)
df_valid = df.drop(df_train.index)
max_ = df_train.max(axis=0)
min_ = df_train.min(axis=0)
df_train = (df_train - min_) / (max_ - min_)
df_valid = (df_valid - min_) / (max_ - min_)
df_train.dropna(axis=1, inplace=True) # drop the empty feature in column 2
df_valid.dropna(axis=1, inplace=True)
X_train = df_train.drop('Class', axis=1)
X_valid = df_valid.drop('Class', axis=1)
y_train = df_train['Class']
y_valid = df_valid['Class']
regression에서 했던 것 처럼 모델을 정의하면 된다. 한가지 다른 점은 마지막 layer는 sigmoid activation이 들어가서 model이 class probabilities를 만들도록 해야하는 것이다.
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
layers.Dense(4, activation='relu', input_shape=[33]),
layers.Dense(4, activation='relu'),
layers.Dense(1, activation='sigmoid'),
])
cross-entropy loss와 accuracy metric를 모델에 추가해주자(compile method사용). two-class problems에서는 'binary' versions을 사용하는 것을 잊지말자(더 많은 분류를 위한 문제에서는 살짝 다르다). Adam optimizer는 classification에서도 잘 동작하기 때문에 그대로 사용한다.
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['binary_accuracy'],
)
편의상 early stopping callback을 추가해주자.
early_stopping = keras.callbacks.EarlyStopping(
patience=10,
min_delta=0.001,
restore_best_weights=True,
)
history = model.fit(
X_train, y_train,
validation_data=(X_valid, y_valid),
batch_size=512,
epochs=1000,
callbacks=[early_stopping],
verbose=0, # hide the output because we have so many epochs
)
늘 그래왔던 것 처럼 learning curves를 살펴보자. validation set에서 얻은 최적의 value와 loss를 확인해보자.
history_df = pd.DataFrame(history.history)
# Start the plot at epoch 5
history_df.loc[5:, ['loss', 'val_loss']].plot()
history_df.loc[5:, ['binary_accuracy', 'val_binary_accuracy']].plot()
print(("Best Validation Loss: {:0.4f}" +\
"\nBest Validation Accuracy: {:0.4f}")\
.format(history_df['val_loss'].min(),
history_df['val_binary_accuracy'].max()))
Exercise
hotel을 cancel할지 안할지 예측하는 모델을 만들어보자.
# 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)
plt.rc('animation', html='html5')
# Setup feedback system
from learntools.core import binder
binder.bind(globals())
from learntools.deep_learning_intro.ex6 import *
Hotel Cancellations dataset을 먼저 로드하고
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.pipeline import make_pipeline
from sklearn.compose import make_column_transformer
hotel = pd.read_csv('../input/dl-course-data/hotel.csv')
X = hotel.copy()
y = X.pop('is_canceled')
X['arrival_date_month'] = \
X['arrival_date_month'].map(
{'January':1, 'February': 2, 'March':3,
'April':4, 'May':5, 'June':6, 'July':7,
'August':8, 'September':9, 'October':10,
'November':11, 'December':12}
)
features_num = [
"lead_time", "arrival_date_week_number",
"arrival_date_day_of_month", "stays_in_weekend_nights",
"stays_in_week_nights", "adults", "children", "babies",
"is_repeated_guest", "previous_cancellations",
"previous_bookings_not_canceled", "required_car_parking_spaces",
"total_of_special_requests", "adr",
]
features_cat = [
"hotel", "arrival_date_month", "meal",
"market_segment", "distribution_channel",
"reserved_room_type", "deposit_type", "customer_type",
]
transformer_num = make_pipeline(
SimpleImputer(strategy="constant"), # there are a few missing values
StandardScaler(),
)
transformer_cat = make_pipeline(
SimpleImputer(strategy="constant", fill_value="NA"),
OneHotEncoder(handle_unknown='ignore'),
)
preprocessor = make_column_transformer(
(transformer_num, features_num),
(transformer_cat, features_cat),
)
# stratify - make sure classes are evenlly represented across splits
X_train, X_valid, y_train, y_valid = \
train_test_split(X, y, stratify=y, train_size=0.75)
X_train = preprocessor.fit_transform(X_train)
X_valid = preprocessor.transform(X_valid)
input_shape = [X_train.shape[1]]
이번에 사용할 model은 batch normalizaion과 dropout layers를 가지고 있다.
아래 그림대로 model을 정의 해보자.
from tensorflow import keras
from tensorflow.keras import layers
# YOUR CODE HERE: define the model given in the diagram
model = keras.Sequential([
layers.BatchNormalization(input_shape=input_shape),
layers.Dense(256, activation='relu'),
layers.BatchNormalization(),
layers.Dropout(0.3),
layers.Dense(256, activation='relu'),
layers.BatchNormalization(),
layers.Dropout(0.3),
layers.Dense(1, activation='sigmoid'),
])
Adam optimizer와 cross-entropy의 binary versions 그리고 accuracy metric를 compile하자.
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['binary_accuracy'],
)
learning curve를 보이면서 model을 학습시켜보자.
early_stopping = keras.callbacks.EarlyStopping(
patience=5,
min_delta=0.001,
restore_best_weights=True,
)
history = model.fit(
X_train, y_train,
validation_data=(X_valid, y_valid),
batch_size=512,
epochs=200,
callbacks=[early_stopping],
)
history_df = pd.DataFrame(history.history)
history_df.loc[:, ['loss', 'val_loss']].plot(title="Cross-entropy")
history_df.loc[:, ['binary_accuracy', 'val_binary_accuracy']].plot(title="Accuracy")
training loss가 계속 떨어지지만 early stopping callback이 overfitting을 막아주었다. 게다가 accuracy는 cross-entropy가 떨어짐에 따라 계속 증가한다. 따라서 성공적인 학습임을 알 수 있다.
Moreover, the accuracy rose at the same rate as the cross-entropy fell, so it appears that minimizing cross-entropy was a good stand-in. All in all, it looks like this training was a success!
'ComputerScience > Machine Learning' 카테고리의 다른 글
Hands-On-Machine Learning : 67p ~ 98p (0) | 2021.08.14 |
---|---|
Hands-On-Machine Learning : 29p ~ 66p (0) | 2021.08.11 |
DeepLearning - 5. Dropout and Batch Normalization (0) | 2021.08.10 |
DeepLearning - 4. Overfitting and Underfitting (0) | 2021.08.10 |
DeepLearning - 3. Stochastic Gradient Descent (0) | 2021.08.06 |