Deep Learning & Machine Learning/강좌&예제 코드

캐글 딥러닝 강좌 정리 2 - 확률적 경사 하강법(Stochastic Gradient Descent), 손실함수, 옵티마이저

webnautes 2023. 10. 26. 22:05
반응형

캐글의 딥러닝 튜토리얼을 바탕으로 정리한 문서입니다.  개인적으로 추가한 내용이 있어서 원문 내용과 차이가 있습니다.

이번에 다루는 내용은 수식에 대한 이해가 되면 수정할 부분이 있을 듯합니다.

 

 

Intro to Deep Learning

https://www.kaggle.com/learn/intro-to-deep-learning 



2022. 3. 1  최초작성




레이어를 쌓아서 완전 연결 신경망( fully-connected neural network)을 만들 수 있습니다. 처음 신경망이 생성될 때에는 모든 신경망의 가중치가 보통 무작위로 설정되기 때문에 신경망은 주어진 입력으로부터  추론되어야 하는 예상 가능한 출력을 만들기 위한  정보를 아무것도 갖고 있지 않습니다.

 

이미지 출처 - https://www.researchgate.net/figure/Example-of-fully-connected-neural-network_fig2_331525817 




이제 신경망을 학습 시켜봅니다

 

신경망을 학습시에는 Train 데이터 세트를 사용하고 학습된 신경망의 성능을 평가하기 위해 학습에 사용한적이 없는 별도의 Test 데이터 세트를 사용합니다. 또 하나의 데이터 세트인 Validation 데이터 세트는 Train 데이터 세트를 사용하여 학습하는 중에 사용되는 학습에는 사용하지 않는 데이터 세트로 모델이 과적합(Overfitting)되지 않도록 하는데 사용됩니다.  



Train 데이터 세트와 Validation 데이터 세트를 구성하는 샘플은 모델의 입력으로 사용되는 몇가지 특징(feature)과 입력이 주어졌을때 모델의 예상 출력인 라벨(label)로 구성됩니다.  Test 데이터 세트도 다른 데이터 세트처럼 보통 입력과 출력이 다 제공되지만 출력 없이 입력만 주어지기도 합니다. 지금 데이터 세트에 대해 언급한 내용들은 사용하는 학습 방법(지도/비지도/강화학습..)이나 알고리즘(분류/회귀/…)에 따라 구성에 차이가 있을 수 있습니다. 



신경망을 학습시킨다는 것은 주어진 특징을 예상 출력으로 변환할 수 있는도록 가중치를 조정하는 것을 의미합니다. 예를 들어 80 Cereals 데이터 세트의 경우  시리얼에 포함된 설탕, 섬유질, 단백질 함량을 입력으로 가져와서 해당 시리얼의 칼로리 예측을 할 수 있도록 모델의 가중치를 조정해야 합니다. 

 

신경망을 학습하는 과정에서 신경망의 가중치는 주어진  훈련 데이터의 특징을 입력으로 받아서 훈련 데이터의 예상 출력을 내놓을 수 있도록 설정되어야 합니다. 



훈련 데이터 세트 외에도 두 가지가 더 필요합니다.

 

신경망의 예측이 얼마나 좋은지를 측정하는데 사용되는 손실 함수(loss function)와 신경망의 가중치를 변경하는 방법을 알려줄 수 있는 옵티마이저(optimizer)입니다.

 

손실 함수(loss function)

손실함수는 학습을 통해 해결해야 할 문제를 신경망에 알리는 역할을 합니다. 그러기 위해 손실 함수는 예상 출력인 실제 값과 모델이 예측하는 값 사이의 차이를 측정하여 신경망의 예측이 얼마나 좋은지 알려줍니다.  이때 해결하고자 하는 문제에 맞는 손실함수를 선택하여 사용해야 합니다. 잘못된 손실함수를 선택하면 학습이 예상한 대로 이루어지지 않습니다.

 

훈련하는 동안 모델은 적절한 가중치 값을 찾기 위한 지침으로 손실 함수를 사용합니다(손실이 낮을수록 좋음). 

이것이  손실 함수가 신경망에게 학습 목적을 알려주는 방법입니다.



회귀 문제의 경우를 살펴봅니다. 예를 들어 80 Cereals 데이터셋의 칼로리, Red Wine Quality 데이터셋의 와인 등급과 같은  수치 값을 예측하는 것입니다. 



회귀 문제에 대한 일반적인 손실 함수는 평균 절대 오차 MAE(mean absolute error)입니다. 각 예측 y_pred과 실제 목표 y_true와의 차이를  절대 차이 abs(y_true - y_pred)를 사용하여 측정합니다.

 

데이터셋의 총 MAE 손실은 데이터셋에 속하는 모든 데이터와 해당 데이터에 대응하는 예측 사이의 절대 차이의 평균입니다.



 

위 그림에서 평균 절대 오차는 회귀를 통해 예측된 직선과 실제 데이터 점(위 그림의 빨간점) 사이의 평균 길이입니다.



옵티마이저(optimizer)

앞에서 살펴본 손실 함수는 신경망이 해결하고자 하는 문제를 설명합니다.  이 문제를 해결하는 것은 옵티마이저의 역할입니다. 옵티마이저는 손실을 최소화하기 위해 가중치를 조정하는 알고리즘입니다.



딥 러닝에 사용되는 대부분의 옵티마이저 알고리즘은 확률적 경사하강법(stochastic gradient descent) 계열에 속합니다. 옵티마이저는 신경망을 단계적으로 훈련시키는 반복 알고리즘입니다. 훈련 단계는 다음과 같습니다.

 

  1. Train 데이터 세트에서 지정한 배치 크기만큼씩 샘플을 가져와 학습을 진행한 후, 신경망이 어느 정도 학습되었는지 살펴보는데 사용하기 위해 학습된 신경망을 사용하여 예측을 해봅니다. 보통 Train 데이터 세트 전체를 학습에 다 사용할때마다, 학습된 모델로 예측을 해봅니다.
  2. 손실함수를 사용하여 예측값과 실제 값 사이의 손실을 측정합니다.
  3. 옵티마이저에서 지정된 방식에 따라 손실이 작아지는 방향으로 신경망의 가중치를 조정합니다.
  4. 손실이 원하는 만큼 작아질 때까지(또는 더 이상 손실이 감소하지 않을 때까지) 1~3을 반복합니다.



전체 Train 데이터 세트를 일정 개수의 샘플로 구성되는 배치(batch)로 나누어서 학습을 진행하며 훈련 데이터 전체를 1번 학습에 사용하는 것을 에포크(epoch)라고 합니다. 학습을 진행시 Epoch는 신경망에서 전체 훈련 데이터 세트를 다 볼때마다 1씩 증가합니다. 



학습률(Learning Rate)과 배치 크기(Batch Size)

손실이 작아지는 방향으로 가중치를 이동시 어느 정도 이동할지 결정하는 것이 학습률 learning rate입니다.

배치 크기는 전체 Train 데이터셋을 얼마큼의 크기로 나누어 학습에 사용할지를  결정합니다.

 

학습률과 배치 크기에 따라 학습하는데 걸리는 시간과 학습의 성능이 달라집니다.

 

학습률이 작을 수록  신경망의 가중치가 최적의 값으로 수렴되기 전에 더 많은 데이터를 볼 필요가 있음을 의미합니다.

아래 그림의 첫번째 경우처럼 학습률이 작으면 최적값으로 이동하는 보폭이 짧아서 많은 횟수를 이동해야하며, 세번째 경우처럼 학습률이 너무 크면 최적값으로 이동하는 보폭이 너무 커서 최적값에 도달하지 못할수도 있습니다. 두번째 경우처럼 적당한 학습률을 정하는게 중요합니다.  

 

 

이미지 출처 : https://www.jeremyjordan.me/nn-learning-rate/



손실 함수(Loss function)와 옵티마이저(Optimizer)

모델을 정의한 후 모델의 compile 메서드를 사용하여 손실 함수와 옵티마이저를 지정합니다. 

 

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

 

여기에서는 문자열로 손실함수와 옵티마이저를 지정하고 있지만 Keras API를 사용하면 손실함수와 옵티마이저의 여러 파라미터를 조정할 수 있습니다. 



그레디언트(기울기)는 가중치가 가야 할 방향을 알려주는 벡터입니다. 즉,  손실을 최소화하는 것을  빠르게 하기 위해 가중치를 변경하는 방법을 알려줍니다.  기울기를 사용하여 손실 곡선의 최소값으로 이동하도록 하기 때문에 경사 하강(gradient descent)이라고 부릅니다.  학습에 사용되는 배치는 데이터 세트의 무작위 샘플이기 때문에  확률적입니다. 이 두가지 경우를 고려하기 때문에 확률적 경사 하강법이라고 합니다. 



Red Wine Quality 데이터 세트 학습

Red Wine Quality 데이터 세트를 사용하여 학습을 해봅니다.

https://www.kaggle.com/uciml/red-wine-quality-cortez-et-al-2009



Red Wine Quality 데이터 세트는 약 1600개의 포르투갈 레드 와인에서 얻은 물리/화학적 측정값과 블라인드 맛 테스트를 통한 각 와인에 대한 품질 평가가 포함되어 있습니다.  데이터 세트의 샘플은 11개의 특징과 1개의 라벨(quality)로 구성됩니다. 



Keras로 작성된 Red Wine Quality 데이터셋을 학습하는 분류(Classification) 코드입니다. 

학습 모델의 목표는 11개의 측정으로부터 와인의 품질을 예측하는 것입니다.

 

from tensorflow.keras import layers, optimizers, Sequential
from tensorflow.keras.utils import to_categorical
from sklearn.metrics import accuracy_score
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import os



# csv 파일로부터 데이터 세트를 로드합니다.
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
red_wine = pd.read_csv(BASE_DIR + '/' + 'winequality-red.csv')

red_wine = red_wine.dropna()


# 7:3 비율로 train dataset과 Test dataset으로 분리합니다.
df_train = red_wine.sample(frac=0.7, random_state=1234)
df_test = red_wine.drop(df_train.index)



# 특징과 라벨을 분리합니다.
X_train = df_train.drop('quality', axis=1).values
X_test = df_test.drop('quality', axis=1).values
y_train = df_train['quality'].values
y_test = df_test['quality'].values


# min-max normalization를 적용하여 특징 값의 범위를 0 ~ 1 사이로 변경합니다.
# 신경망은 입력이 공통 크기일 때 가장 잘 수행되는 경향이 있기 때문입니다.
# 이때 특징별로 min,max를 구하여 min-max normalization를 적용합니다.
X_train_max = X_train.max(axis=0)
X_train_min = X_train.min(axis=0)
X_train = (X_train - X_train_min) / (X_train_max - X_train_min)
X_test = (X_test - X_train_min) / (X_train_max - X_train_min)



# 라벨을 ont-hot 인코딩을 합니다.
y_train, y_test = to_categorical(y_train), to_categorical(y_test)



# 모델을 생성합니다. 마지막에 one-hot 인코딩된 9개의 값을 출력합니다.
model = Sequential()
model.add(layers.Dense(144, activation='relu', input_shape=[X_train.shape[1]]))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(0.3))
model.add(layers.Dense(144, activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(0.3))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.Dense(9, activation='softmax'))



# 손실함수와 옵티마이저를 지정합니다.
model.compile(optimizer=optimizers.Adam(learning_rate=0.000056194), loss='categorical_crossentropy', metrics=['accuracy'])



# 학습을 진행합니다.
# validation_split 아규먼트로 Training 데이터셋의 10%를 Validation 데이터셋으로 사용하도록합니다.
# 배치 크기가 128이라는 것은 전체 데이터셋을 샘플 128개씩으로 나누어서 학습에 사용한다는 의미입니다.
# 에포크(epochs)가 1000이라는 것은 전체 train 데이터셋을 1000번 본다는 의미입니다.
history = model.fit(
  X_train, y_train,
  validation_split = 0.1,
  batch_size=128,
  epochs=1000
  )


# 학습중 손실 변화를 그래프로 그립니다.
history_df = pd.DataFrame(history.history)
history_df['loss'].plot()
history_df['val_loss'].plot()
plt.legend()
plt.show()


history_df = pd.DataFrame(history.history)
history_df['accuracy'].plot()
history_df['val_accuracy'].plot()
plt.legend()
plt.show()


# Test 데이터 세트로 추론을 해봅니다.
y_pred = model.predict(X_test)


# one-hot 인코딩된 값을 정수 라벨로 변경합니다.
y_pred = np.argmax(y_pred, axis=1)
y_test = np.argmax(y_test, axis=1)


# 모델의 정확도를 계산합니다.
print(accuracy_score(y_test, y_pred))



학습 그래프입니다. 학습이 진행됨에 따라 손실 곡선이 수평선에 가까워집니다. 이것은 모델이 더 이상 학습이 되지 않으므로 추가 학습을 할 필요가 없음을 의미합니다.

 



정확도 곡선도 학습이 진행됨에 따라 수평선에 가까워집니다. 



학습 로그는 양이 많아서 마지막 결과만 남겨놓았습니다. 

Train 데이터 세트에 대한 정확도는 69%, Validation 데이터 세트에 대한 정확도는 62%이며 Test 데이터 세트에 대해 정확도 60%가 나왔습니다.



poch 1000/1000

8/8 [==============================] - 0s 13ms/step - loss: 0.7324 - accuracy: 0.6991 - val_loss: 0.9836 - val_accuracy: 0.6250

2022-02-27 23:11:55.016871: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.

 

0.6020833333333333





캐글 딥러닝 강좌 정리 1 - 뉴런(Neuron)과 깊은 신경망(DNN)

https://webnautes.tistory.com/2184



캐글 딥러닝 강좌 정리 2 - 확률적 경사 하강법(Stochastic Gradient Descent), 손실함수, 옵티마이저

https://webnautes.tistory.com/2185



캐글 딥러닝 강좌 정리 3 - 과적합(Overfitting)과 해결 방법(dropout, batch normalization)

https://webnautes.tistory.com/2186



반응형