Ch5

2024. 4. 7. 13:06딥러닝

5.1 일반화: 머신 러닝의 목표

5.1.1 과소적합과 과대적합

머신러닝은 일반화와 최적화 사이에서 줄다리기를 하는 과정이다. 그러므로 제대로 된 학습을 위해서는 노이즈, 이상치, 결측치 등등을 고려하며 feature selection을 해야 한다,
최적화 : 가능한 훈련 데이터에서 최고의 성능을 얻으려고 모델을 조정하는 과정
일반화 : 훈련된 모델이 이전에 본 적 없는 데이터에서 얼마나 잘 수행되는지 의미

잡음 섞인 데이터
불확실한 특성 : 덜 익은 바나나와 익은 바나나의 구분을 가능하게 하는 특성은 무엇인가?
드문 특성과 가짜 상관관계 : 드문 특성 값에 대해 무시하지 않고 그것을 반영하는 것은 옳은 일인가? 이렇게 반영했을 때 만들어지는 상관관계는 가짜 상관관계일 확률이 높다.

5.1.2 딥러닝에서 일반화의 본질

딥러닝의 일반화의 본질은 딥러닝 모델 자체와는 거의 관련이 없고, 실제 세상의 정보 구조와 관련이 깊다.

매니폴드 가설 -> 대충은 알겠는데 매니폴드를 공간과 연관 지어서 확실히 설명할 수가 없음.

Mnist 손글씨 데이터를 생각해보자. 각 손글씨 이미지는 2828 크기의 배열이며 각 원소는 0~255 사이의 정수이다. 이때 실제 손글씨 숫자는 2828만큼의 배열로 이루어진 공간에서 아주아주 작은 부분만 차지하며, 랜덤한 정보가 아니라 매우 구조화된 정보이다.

그렇기에 각 손글씨 숫자의 부분 공간은 연속적이라고 할 수 있으며, 이를 조금만 지워도 여전히 손글씨 숫자로 인식할 수 있을 뿐만 아니라 적절히 수정하면 다른 손글씨로도 만들 수 있다. ‘3’이라고 치면 윗부분을 수정해서 ‘5’로 만드는 식.

이런 관계를 매니폴드라고 한다. 매니폴드 가설은 ‘실제 세상의 모든 데이터가 그 데이터가 인코딩 된 고차원 공간 안의 저차원 매니폴드에 놓여 있다’는 가정이다. 머신러닝으로 치면 다음과 같다. 모델은 가능한 입력 공간 안에서 비교적 간단하고, 저차원이며, 구조적인 부분공간만 학습하면 된다. 이 부분 공간을 잠재 매니폴드라고 한다. 이러한 매니폴드 중 하나의 속에서 두 입력 사이를 보간(interpolation)하는 것이 항상 가능하다. 즉 일반화의 핵심은 샘플 사이를 보간하는 것이다.

보간 – 일반화의 원천

보간은 간단히 말해 공간의 빈 곳을 채우는 것이다. 데이터 포인트를 보간할 수만 있다면 전에 본 적 없는 포인트를 해당 매니폴드에서 가까이 놓인 다른 포인트와 연결하여 이해할 수 있다. 연속적인 경로를 따라 한 입력에서 다른 입력으로 변형 할 때 모든 포인트가 이 매니폴드에 속한다.

하지만 잠재 매니폴드에서의 보간과 부모 공간에서의 선형 보간은 다르다.

-> 잠재 매니폴드에서 모든 포인트는 유효한 숫자가 되지만 일반적으로 두 숫자 데이터를 평균하면 유효한 숫자가 되지 않는다. 2 ~ 6 ~ 0으로 변화하는 잠재 매니폴드에서의 평균 포인트는 6이라고 할 수 있지만 실제 인코딩 공간에서 손글씨 숫자 데이터를 평균하면 알아볼 수 없는 이상한 데이터가 나옴.

즉 보간이 일반화의 전부는 아니다. 보간은 이전에 본 것과 매우 가까운 것만 이해할 수 있게 하므로 지역 일반화만 가능하다. 사람은 궁극 일반화(직관이나 패턴 인식과는 다른 무언가. 이성?)를 할 수 있다고 한다.
-> 이렇게만 보면 아직 사람의 지능을 완전히 흉내내는 것은 멀고 먼 길인 것 같다.

딥러닝이 작동하는 이유

2장에서 딥러닝이란 구겨서 공 모양으로 만든 종이를 펴는 과정과 같다는 내용이 있었다.

종이 한 장은 우리가 살고 있는 3d 공간 안의 2d 매니폴드라고 할 수 있으므로, 딥러닝은 잠재 매니폴드를 풀기 위한 도구이다.
딥러닝 모델은 매우 고차원의, 연속적인(미분 가능한) 곡선이다. 이 곡선을 점진적으로 훈련 데이터에 맞을 때까지 파라미터를 조정해야 한다(경사하강법). 학습 데이터는 입력 공간 안에서 고도로 구조적인 저차원의 매니폴드를 형성하고, 경사하강법은 이러한 잠재 매니폴드를 따라 이동하는 것으로 볼 수 있다.

특히 이미지/시퀀스 처리에서 딥러닝 모델은 훈련 데이터에 잇는 정보의 형태를 반영하는 식으로 구조화된다고 한다.

가장 중요한 훈련 데이터

딥러닝의 일반화 능력은 모델의 특정 속성에 의한 것이 아니고, 매니폴드 가설에서 볼 수 있듯이 데이터의 자연적인 구조로 인한 결과이다. 딥러닝은 곡선을 맞추는 것이기 때문에 이를 위해서는 입력 공간을 조밀하게 샘플링하여 훈련해야 한다(특히 decision boundary 근처에서). 그렇지 않으면 모델이 훈련 데이터의 인풋 사이를 보간하여 새로운 입력을 이해할 수 없고, 결국 일반화도 하지 못하게 된다.

결국 쓰레기가 들어가면 쓰레기가 나오듯이, 딥러닝 모델을 향상시키는 핵심은 좋은 품질의, 더 많은 양의 데이터이다.
현실적인 문제로 데이터를 더 수집할 수 없다면 regularization을 적용해야 한다. 모델이 저장할 수 있는 정보량을 조정 -> 층의 개수나 층 자체의 크기를 변화시키는 등. 모델 곡선의 매끄러운 정도에 제약을 추가한다 이렇게 모델이 적은 개수의 패턴만 기억하거나 매우 규칙적인 패턴만 기억할 수 있으면 모델이 일반화 가능성이 가장 높은 패턴에만 집중할 수 있도록 한다.

5.2 머신 러닝 모델 평가

5.2.1 train/test/validation 세트

Information leak

Layer, later의 유닛 개수 등의 하이퍼 파라미터 튜닝 또한 본질적으로 학습이라고 할 수 있다. 그러므로 검증 데이터를 바탕으로 계속 튜닝하게 되면 검증 데이터에 과적합이 될 수 있다. 검증 데이터를 사용하면 할수록, 이 데이터가 유출되는 것마냥 모델이 검증 데이터에만 성능이 좋아지는 것이다.

그러므로 일반화를 위해서라도, 모델 성능을 평가할 때 사용하는 테스트 세트는 절대로 모델에 유출되어서는 안 된다.

데이터를 train/test/validation 셋으로 나누는 대표적인 방식으로는

1. holdout validation
2. k-fold cross validation
3. iterated k-fold cross validation

이 있다.

  1. holdout validation: 데이터의 일정 부분을 분리하는 방식. 데이터가 적다면 validation/test set이 너무 적어서 전체 데이터를 통계적으로 대표하지 못한다.
    -> k-fold cross validation으로 해결
  2. k-fold cross validation: 데이터를 동일한 크기의 K개의 분할로 나눈 뒤, 각 분할 중 하나는 validation set으로, 나머지는 훈련에 사용하는 방식. 최종적으로 K개의 점수를 평균내어 결과를 낸다. 모델의 성능이 데이터 분할에 따라 편차가 클 경우에 유용하다.
  3. iterated k-fold cross validation
    이는 셔플링을 사용하여 k-fold cross validation을 반복하는 방식이다. K개로 데이터를 쪼개기 전에 데이터를 매번 셔플한 뒤 학습하기 때문에 반복횟수가 P라면 P * K만큼의 계산 비용이 든다.

5.2.3 모델 평가시 유념해야 할 점

  1. 대표성 있는 데이터: 숫자 데이터 분류를 학습할 때 생각없이 뒤의 20%의 데이터를 떼어서 검증 셋으로 사용해버리면 학습에는 07, 검증에는 89의 숫자만 들어가게 되므로 주의해야 한다. 이때는 무작위로 데이터를 섞는 것이 필요하다
  2. 시간의 방향: 과거 데이터로 미래 데이터를 예측하려고 한다면(내일 날씨, 주식 등) 1의 사례처럼 데이터를 무작위로 섞으면 안 된다. 섞어버리면 미래 데이터로 학습을 해버리므로 information leak가 발생한다.
  3. 데이터 중복: 데이터셋에 중복되는 데이터가 있다면 훈련, 검증 과정에서 데이터가 중복되어 들어가게 되므로 information leak가 발생한다.

5.3 훈련 성능 향상하기

최적으로 훈련된 지점을 알고 싶다면 먼저 모델을 과적합하는 단계까지 가봐야 한다. 이때 모델을 훈련시킬 때 생길 수 있는 문제는 세 가지가 있다.

1. 시간이 지나도 loss가 줄지 않는 경우

2. 훈련을 아무리 해도 threshold를 넘어설 만큼 일반화가 되지 않을 경우

3. 훈련/검증 loss는 줄어들지만 과적합이 되지 않고 과소적합만 되는 경우(최적 모델을 찾지 못함)

5.3.1 경사 하강법의 핵심 파라미터 튜닝하기

경사 하강법에서의 하이퍼 파라미터는 옵티마이저, 모델 가중치의 초깃값 분포, 학습률, batch size이다. 이 모든 파라미터들은 상호 의존적이다. 일반적으로 학습률과 batch size만 변화시키는 것으로 충분하다.

-학습률이 너무 높아버리면 global minima를 찾지 못하고 최적점 주위에서 왔다 갔다(oscillating)만 하지 수렴하지는 못한다.
-batch size가 너무 작다면 데이터에 노이즈가 섞일 수 있으므로 size를 증가시키는 것도 좋다.

5.3.2 구조에 대해 더 나은 가정하기

만약 훈련을 시켜도 검증 지표가 하나도 나아지지 않고 일반화 되지 않는 경우가 생긴다면 접근방식에 근본적인 문제가 있는 것이다.

이때는

  1. input 데이터에 target을 예측하기 위한 정보가 부족한 경우: 이전에 썼던 방식으로는 문제를 해결할 수가 없다.
  2. 사용한 모델의 종류가 문제에 적합하지 않은 경우: 예를 들어 시계열 데이터의 경우 dense층을 사용하면 전혀 진전이 없다. Rnn을 사용하는 것이 더 적합하다.

5.3.3 모델 용량 늘리기

모델이 검증 지표를 향상시키는 방향으로 학습하고, 일반화도 어느 정도 되었지만 validation loss를 확인했을 때 시간이 지나도 여전히 과적합이 되지 않을 경우(과적합이라면 훈련 데이터에만 잘 작동해야 하므로 validation loss가 필연적으로 증가해야만 한다), 이는 모델의 표현 능력이 부족하기 때문이다.

즉 더 많은 정보를 저장할 수 있도록 모델에 층을 추가하거나, 층 크기를 늘리거나(더 많은 가중치), 현재 문제에 더 적합한 종류의 층을 사용해야 한다.

5.4 일반화 성능 향상하기

모델이 정상적으로 과적합까지 된다면 이제 일반화 성능을 극대화하는 것이 필요하다.

5.4.1 데이터셋 큐레이션

딥러닝은 마법이 아니기 때문에 항상 넣어주는 데이터에 신경을 써야 한다. 괜히 전체 파이프라인에 들어가는 시간의 80%정도를 EDA에 쓰는게 아니다.

  1. 데이터가 충분한지 확인해야 한다: 일반화를 위해서라면 입력에서 출력을 매핑하는 공간을 조밀하게 샘플링해야 한다는 것을 꼭 기억해야 함. 가끔 불가능해 보이는 문제도 데이터를 대용량으로 들이부으면 해결되기도 한다.
  2. 레이블 할당 에러를 최소화: 입력을 시각화하여 이상치를 확인하고 레이블을 교정해야 한다.
  3. 데이터를 정제하고 누락된 값을 처리해야 한다
  4. 어떤 feature가 도움이 되는지 확실하게 판단이 안 서면 feature selection은 필수!!

5.4.2 특성 공학

모델에 데이터를 주입하기 전에 학습이 아닌 하드코딩된 변환을 적용하여 알고리즘이 더 잘 수행되도록 만들어준다.
특성 공학은 뭐 거창한게 아니고 feature를 더 간단한 방식으로 표현하여 문제를 쉽게 만드는 것이다. 만약 시계바늘을 보고 시간을 추정하는 모델을 만들어야 할 때를 생각해보자. 인풋 데이터로 2차원 시계 모양 데이터를 넣어도 되겠지만 시침과 분침의 x, y좌표를 담고 있는 튜플을 넣어도 되고, 아예 시침과 분침의 각도 값을 넣어버린다면 머신러닝 자체도 필요가 없어진다.

이렇게 feature를 간단하게 표현하게 되면 잠재 매니폴드를 더 매끄럽고, 간단하고, 구조적으로 바꾸는 효과가 있다. 이러한 방식이 좋긴 하지만 해당 문제에 대해 정확하게 이해하고 있어야 문제가 없을 수 있다.

하지만 딥러닝을 사용하는 현재는 신경망이 자동으로 원본 데이터에서 유용한 feature를 추출할 수 있기에 특성 공학은 별로 필요가 없다.

5.4.3 early stopping 사용하기

잠재 매니폴드를 학습하기 위해 필요한 최소한의 것보다 훨씬 많은 자유도를 가진다. 이전 장에서 보듯 항상 최상의 검증 점수를 내는 에포크 횟수를 찾기 위해 필요보다 오래 모델을 훈련하였다. EarlyStopping 콜백을 사용할 경우 에포크가 끝날 때 마다 모델을 저장하고 최상의 에포크를 찾은 후 저장된 모델을 재사용할 수 있다.
케라스에서는 주로 EarlyStopping 콜백을 사용하여 early stopping을 수행할 수 있다(7장)

5.4.4 모델에 regularization 적용하기

regularization이란 과적합 방지를 위해(모델이 훈련 데이터에 완벽하게 맞추는 것을 막기 위해) 인위적으로 방해하는 기법이다. 모델의 검증 능력을 높여 일반화 능력을 높이기 위해서 라고도 볼 수 있다.

모델의 과적합을 완화시키려면 가장 기본적으로 모델 크기(층의 수와 층에 있는 유닛 개수로 결정되는 학습 가능한 파라미터 개수)를 줄이면 된다.

딥러닝에선 loss를 최소화하기 위해 타겟에 대한 예측 성능을 가진, 압축된 표현을 모델이 학습하도록 해야 하는데, 너무 모델 크기가 커도, 작아도 안되므로 먼저 비교적 작은 크기의 모델(더 적은 층과 파라미터 개수)에서 검증 loss가 감소할 때까지 점점 크기를 늘려야 한다.

가중치 규제: 작은 크기의 모델에 사용

오캄의 면도날 이론 -> 더 간단한 모델이 복잡한 모델보다 덜 과적합된다.

간단한 모델이란 파라미터 값 분포의 엔트로피가 작은, 또는 적은 수의 파라미터를 가진 모델이라고 할 수 있다. 그러므로 과적합 완화를 위한 일반적인 방법은 모델의 복잡도에 제한을 두어서 가중치가 작은 값을 가지도록 강제하는 것이다.

이렇게 가중치 값의 분포를 균일하게 만드는 작업이 가중치 규제이고, 여기엔 L1, L2 규제가 있다.

L1 규제: 가중치의 절댓값에 비례하는 비용 추가(L1 노름)
L2 규제: 가중치의 제곱에 비례하는 비용 추가(L2 노름). 이를 신경망에서는 weight decay라고도 한다. 이는 수학적으로 L2 규제와 동일하다.

케라스에서는 다음과 같이 규제를 적용한다.

from tensorflow.keras import regularizers

model = keras.Sequential([
    keras.Dense(16, kernel_regularizer = regularizers.l2(0.002), activation = 'relu'),
    keras.Dense(16, kernel_regularizer = regularizers.l2(0.002), activation = 'relu'),
    keras.Dense(1, activation = 'sigmoid')
])
model.compile(optimizer = 'rmsprop', loss = 'binary_crossentropy', metrics = ['accuracy'])

regularizers.l1(0.001) #l1 규제
regularizers.l1_l2(l1 = 0.001, l2 = 0.001) #l1, l2규제 병행

이 코드의 kernel_regularizer = regularizers.l2(0.002) 부분은 가중치 행렬의 모든 원소를 제곱하고 0.002를 곱하여 모델의 전체 손실에 더한다는 의미다. 이러한 패널티 항은 훈련 시에만 추가된다!!
즉 이 모델의 loss는 테스트보다 훈련 시에 더 높다.

파라미터가 너무 많은 딥러닝 모델에는 이러한 규제로 가중치 값을 제약해도 일반화에 큰 영향을 끼치지 않기 때문에 드롭아웃을 사용해야 한다

드롭아웃

드롭아웃은 dropout이란 말 그대로 뭔가를 떨어뜨려서 제외하는 것이다. 즉 ‘훈련 동안만’ 무작위로 층의 출력 feature의 일부를 0으로 만들어서 제외시킨다.

드롭아웃의 비율을 0.1(10%)로 설정하면 벡터의 원소의 10%가 0이된다. 주로 비율은 0.2~0.5로 지정한다.

만약 크기가 (batch size, features)인 어떤 층의 출력을 담고 있는 넘파이 행렬이 있다고 할 때, 훈련 시에는 이 행렬 값의 일부를 랜덤하게 0으로 만들고

layer_output *= np.random.randint(0, high = 2, size = layer_output.shape)

테스트 시에는 드롭아웃의 비율로 출력을 낮추어야 한다: 앞에서 드롭아웃의 비율이 0.5였으므로 0.5를 곱해서 스케일링한다.

layer_output *= 0.5

종종 테스트 단계에서 출력을 그대로 두도록 구현하기도 한다.

layer_output *= np.random.randint(0, high = 2, size = layer_output.shape) #훈련 단계
layer_output /= 0.5 #스케일을 높인다

결국 훈련 시에는 드롭아웃의 비율만큼 스케일링 해주고, 테스트 단계에서는 활성화 함수의 출력을 그대로 사용하는 것이다.

'딥러닝' 카테고리의 다른 글

Ch7  (0) 2024.05.12
Ch6  (0) 2024.05.05
Ch4  (0) 2024.03.31
Ch3  (0) 2024.03.24
Ch2  (0) 2024.03.13