개요
모델을 훈련할 때 흔히들 데이터셋을 shuffle하여 학습시키곤 한다. 데이터셋을 training data: test data로 나눌 때도 shuffle하고 매 에폭마다 training data를 shuffle한다.
이렇게 data를 shuffle하는 이유에 대해 막연하게 알고 있었는데 이번에 데이터를 shuffle해야 하는 이유에 대해 알아보고자 한다.
미니배치와 배치를 혼용하여 쓰는 경우도 있지만 이 글에선 편의를 위해 미니 배치 학습은 전체 data를 나눠서 학습하는 것, 배치학습은 전체를 한번에 학습하는 것을 의미하여 쓴다.
data를 shuffle하는 경우는 두가지가 있다. 첫째는 데이터셋을 training data: test data로 나눌 때이고 둘째는 모델 학습시 매 에폭마다 shuffle하는 경우이다.
데이터 Split Shuffle
먼저 데이터셋을 나눌 때 shuffle을 하는 이유에 대해 알아보겠다. 데이터셋을 섞지 않고 바로 split한다면 train data와 test data의 분포가 너무 다를수가 있다. 극단적인 예시로 이진분류 문제라면 train data에는 label이 1인경우만 있고 test data에는 label이 0인 경우만 있다면 label이 0인 경우에 대해서 제대로 학습하지 못하게 되고 이는 overfitting을 야기한다.
이를 방지하기 위해 크게 두가지 방법이 있다. 각각 데이터셋을 random shuffle 후 split하는 random sampling 그리고 동일한 분포를 가지게 섞는 stratified random sampling이다. 최근의 데이터를 test data로 쓰고 그 이전의 데이터들을 train data로 쓰는 방법은 shuffle을 하지 않기에 설명에서 제외한다.
Random sampling는 가장 직관적이고 편한 접근방식이다. 그러나 이 방법 역시 dataset간에 편향을 발생시킬 수 있다. 이를 방지하기 위해 stratified random sampling를 사용할 수 있는데 이는 특정값들에 대하여 train data와 test data간에 동일한 분포를 가지도록 shuffle후 split하는 방법이다.
간단한 sklearn 예제를 통해 그냥 split했을 때, random sampling그리고 stratified random sampling간의 차이를 보겠다.
import numpy as np
from sklearn.model_selection import train_test_split
x, y = np.arange(16).reshape((8, 2)), np.array([0,0,0,0,1,1,1,1])
>>> x
[0 1] [2 3] [4 5] [6 7] [8 9] [10 11] [12 13] [14 15]
>>> y
[0 0 0 0 1 1 1 1]
이해가 쉽게 이진값을 label로 하는 list를 만든 후 sklearn의 train_test_split함수를 사용하였다.
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.5, random_state=42, shuffle=False)
>>> x_train
[0 1] [2 3] [4 5] [6 7]
>>> y_train
[0 0 0 0]
>>> x_test
[8 9] [10 11] [12 13] [14 15]
>>> y_test
[1 1 1 1]
shuffle을 하지않고 바로 split한 경우이다. 출력에서 보이듯이 train data의 label값들은 모두 0이고 test data의 label값들은 모두 1이니 학습이 제대로 되지 않고 overfitting이 일어날 것임을 알 수 있다.
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.5, random_state=42, shuffle=True)
>>> x_train
[8 9] [10 11] [6 7] [15 16]
>>> y_train
[1 1 0 1]
>>> x_test
[12 13] [2 3] [0 1] [4 5]
>>> y_test
[1 0 0 0]
다음으로 random sampling을한 경우이다. 이전 보다는 편향이 덜함을 볼 수 있지만 한 라벨값이 한쪽에 쏠릴 수 있음을 볼 수 있다.
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.5, random_state=32, shuffle=True, stratify=y)
>>> x_train
[10 11] [0 1] [4 5] [14 15]
>>> y_train
[1 0 0 1]
>>> x_test
[2 3] [8 9] [6 7] [12 13]
>>> y_test
[0 1 0 1]
마지막으로 stratified random sampling이다. 함수의 stratify인자에 y값을 넣어줌으로써 test data와 train data간의 y값 분포가 같도록 나누어 주는 것을 볼 수 있다.
따라서 데이터를 split할 때 shuffle하는 이유는 overfitting을 방지하기 위해서임을 알 수 있었다.
학습 shuffle
다음으로 모델 학습시 에폭마다 data를 shuffle해야 하는 이유이다. 모델 학습시 매 에폭마다 data를 shuffle해야 하는 이유는 3가지가 있다.
먼저 미니배치 학습을 할 때 미니 배치가 전체 데이터에 대해 대표성을 띄게 해 일반화 성능을 높히고 overfitting을 방지할 수 있다. 왜냐하면 미니배치 학습 시 미니배치의 기울기들을 평균내 최적화를 하기 때문이다. 평균 낸 기울기가 하나씩 학습할 때의 기울기를 대표하지 못한다면 잘못된 방향으로 학습할 수 있다. 앞서 데이터를 split할 때 분포와 대표성을 위해 shuffle한것처럼 같은 이유로 shuffle하는 것이다.
두번째 이유로 모델이 데이터의 순서에 익숙해지는 것을 방지할 수 있다. 이에 대해 두가지 설명이 있다.
하나는 모델이 같은 순서의 데이터들을 입력받게 되면 그 순서들에 익숙해져 순서가 정답에 영향을 끼친다는 설명이다. 예를 들어 Binary classification문제에서 dog-cat-dog순으로 입력이 들어온다면 순서를 학습해 dog가 입력으로 들어왔다면 그 다음은 cat이 나올 것이라고 학습하는 식이다. 이는 설득력이 약한 것 같다. 왜냐하면 NTM처럼 메모리가 있는게 아닌 이상 모델의 예측은 다른 예측에 독립적이기 때문이다. 두번째는 기울기가 에폭을 주기로 비슷한 방향으로만 움직여 global minima에 다다르기 힘들다는 설명이다. 이는 설득력이 좀 있는데 내가 참고한 글에선 은닉층이 한개인 FNN을 사용하여 실험적으로 이를 증명하였다.
Figure1의 Shuffle을 하지 않고 학습한 왼쪽 그래프들은 에폭(iterations)이 반복됨에 따라 기울기가 완만하게 바뀌는 것을 볼 수 있다. 반면에 Shuffle을 한 후 학습한 오른쪽 그래프들은 에폭이 반복됨에 따라 기울기가 급격하게 바뀌는 것을 볼 수 있다. 이를 통해 Shuffle을 하지 않고 미니 배치 학습하면 비슷한 방향의 기울기들이 반복되어 기울기가 완만하게 바뀌는 것을 알 수 있고 따라서 손실함수 값이 global minima로 도달하기 어려울 것이다.
마지막으로 모델 학습 시 매 에폭마다 데이터를 shuffle해야 하는 이유는 Loss surface의 변화때문이다. 손실함수를 간단하게 표현하면 y-wx이다(y: label, w: weight, x: input). 만약 미니배치 학습을 하지 않고 배치학습을 한다면 x에 대하여 손실함수는 고정되어 있기 때문에 손실함수 값이 특정값에 수렴한다면 더 나은 minima가 있음에도 그 값에서 벗어나기 힘들 것이다.
미니 배치학습을 한다면 상황은 좀 나아진다. 왜냐하면 x가 변화하기 때문이다. 물론 미니 배치학습을 하더라도 shuffle을 하지 않는다면 loss surface의 경우의 수는 적다. 미니 배치 학습에 매 에폭마다 데이터를 shuffle을 한다면 가중치 Wi에서의 loss surface가 Wj에서의 loss surface와 같기는 매우 힘들다.(i != j) 따라서 loss가 특정 구간에 수렴하더라도 다음 미니 배치에서 loss surface가 달라짐에 따라 그 구간을 탈출하기 쉬워져서 모델의 정확도가 더 높아질 수 있다. 이때 loss surface는 모델의 출력이 확률분포를 따르기 때문에 어느정도 비슷하게 존재한다. 따라서 global minima가 충분히 깊다면 global minima는 많은 loss surface에 존재하기 때문에 모델이 수렴할 수 있는 것이다.
Reference
DeepwizAI, 2020년 1월 29일,https://www.deepwizai.com/simply-deep/why-random-shuffling-improves-generalizability-of-neural-nets
Josh, 2017년 12월 9일 ,https://datascience.stackexchange.com/questions/24511/why-should-the-data-be-shuffled-for-machine-learning-tasks
'AI' 카테고리의 다른 글
Decision Tree부터 Random Forest, LightGBM까지(Ensemble Learning) (0) | 2022.10.12 |
---|---|
LightGBM: A Highly Efficient Gradient BoostingDecision Tree (0) | 2022.10.11 |
캐글 타이타닉 생존자 예측 실습(Logistic Regression) (0) | 2022.09.28 |
Attention Is All You Need 리뷰 (0) | 2022.09.22 |
Deep Learning without Poor Local Minima 리뷰 (2) | 2022.09.21 |