일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- Transformer
- RNN
- SVD
- 밑바닥부터 시작하는 딥러닝2 2장
- 데이터프레임
- 판다스
- 벡터간 유사도
- ReLU
- 자연어처리
- pandas
- 밑바닥부터 시작하는 딥러닝
- word embedding
- sigmoid
- Linear Algebra
- 신경망 학습
- one-hot vector
- word2vec
- 딥러닝
- machine translation
- 역행렬
- 동시발생 행렬
- NLP
- 정칙행렬
- 연립일차방정식
- 선형대수학
- 프로그래머를 위한 선형대수
- DataFrame
- PPMI
- NMT
- Python
- Today
- Total
생각하는감자
6장-학습 관련 기술들 본문
최적화
매개변수의 최적값을 찾는 문제를 푸는 것을 최적화라고 하고, 매개변수의 최적값을 찾는다는 것은 손실 함수의 값을 가능한 한 낮추는 매개변수를 찾는 것이다. 앞서 확인한 최적의 매개변수 값을 찾는 방법은 매개변수의 기울기를 이용하는 것이었다. 이를 확률적 경사 하강법이라고 했다.
확률적 경사 하강법(SGD)
SGD는 단순하고 구현이 쉽다는 장점이 있지만, 문제에 따라 비효율적일 수도 있다. 비등방성함수, 즉, 방향에 따라 다른 성질을 가지는 함수에서는 탐색 경로가 비효율적이라는 단점이 있는데, SGD의 최적화 갱신경로를 알아보면 아래와 같다. 예를 들어 아래와 같은 함수의 최솟값을 구하는 문제를 생각해 보면, 최솟값을 가지는 장소는 (0,0)이지만 기울기 대부분은 (0,0) 방향을 가리키지 않는다.
최솟값을 찾아가는 이동 경로가 지그재그 형식으로 이동하기 때문에 비효율적이다.
이러한 SGD의 단점을 개선해주는 모멘텀, AdaGrad, Adam이라는 최적화 방법들이 있다.
모멘텀
모멘텀(momentum)이라는 단어는 "운동량"을 뜻하는 단어로, 쉽게 생각해 기울기 방향으로 힘을 받아 물체가 가속된다는 물리법칙을 나타내므로 공이 그릇의 바닥을 구르는 듯한 움직임을 보여준다.
모멘텀의 최적화 갱신 경로는 아래 그래프와 같다. SGD에 비해서는 x축 방향으로 빠르게 다가가는 것을 알 수 있다. 이것은 x축의 힘은 아주 작지만, 방향은 변하지 않아서 한 방향으로 일정하게 가속하기 때문이다.
AdaGrad
학습률을 학습을 진행하면서 점차 줄여가는 방법을 발전시킨 것이 AdaGrad이다. 이 방법은 각각의 매개변수에 맞춤형 값을 만들어주는 것인데, 개별 매개변수에 적응적으로 학습률을 조정하면서 학습을 진행한다. 갱신 강도가 점차 약해져 실제로 무한히 계속해서 학습을 진행하게 되다면, 어느 순간엔 갱신량이 0이 되어 갱신하지 않게 된다. 이러한 문제를 개선시킨 것은 RMSProp이라는 방법 있는데, 이것은 먼 과거의 기울기는 서서히 잊어가고 새로운 기울기 정보를 크게 반영하는 것이다.
앞서 보았던 최적화 방법에 비해 최솟값을 향해 움직이는 것이 훨씬 효율적인 것을 알 수 있다. y축 방향은 기울기가 커서 처음에는 크게 움직이지만, y축 방향으로 갱신 강도가 빠르게 약해지고 지그재그 모양의 움직임이 줄어들게 된다. AdaGrad를 구현해보면 다음과 같다.
import numpy as np
class AdaGrad:
def __init__(self, lr=0.01):
self.lr = lr
self.h = None
def update(self, params, grads):
if self.h is None:
self.h = {}
for key, val in params.items():
self.h[key] = np.zeros_like(val)
for key in params.keys():
self.h[key] += grads[key] * grads[key]
params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)
마지막에 1e-7이라는 아주 작은 값을 더한것은 self.h[key]에 0이 담겨있어도 0으로 나눗셈을 하는 사태를 막아주는 역할을 한다.
Adam
Adam이라는 기법은 직관적으로 생각한다면, 모멘텀과 AdaGrad 기법을 융합한 최적화 방법이다. 모멘텀의 "공이 그릇 바닥을 구르는듯한 움직임"과 AdaGrad의 "매개변수마다 적응적 갱신"이라는 이점을 조합한 것이므로 매개변수 공간을 효율적으로 탐색하게 된다. Adam의 최적화 갱신경로를 그래프로 그려보면 다음과 같다.
매개변수 최적화 방법에는 이외에도 여러가지가 있는데, 어떤 방법이 항상 뛰어나다고 결정지을 순 없다. 각자의 장단점이 있고, 같은 최적화 기법이라도 잘 해결되는 문제가 있는가 하면 그렇지 않은 문제가 있기도 하다. 따라서, 상황을 고려하여 문제에 적합한 최적화 방법을 사용하면 된다.
가중치의 초깃값
가중치 감소 기법은 오버피팅을 억제하여 범용 성능을 높이는 기술이다. 간단히 말해, 가중치의 값이 작아지도록 학습하여 오버피팅이 일어나지 않게끔 하는 기법이다. 가중치를 작게 하고 싶다면 초깃값 자체를 최대한 작은 값에서 시작해야 하는데 그렇다고 초깃값을 모두 0으로 설정하는 것은 학습이 올바로 이루어지지 않기 때문에 좋지 않은 방법이다. 오차역전파법에서 모든 가중치의 값이 똑같이 경신되기 때문인데, 즉, 갱신을 거쳐도 여전히 같은 값을 유지한다는 것이다. 다른 말로 하면 가중치를 여러 개 갖는 의미가 사라진다는 것과 같다. 가중치가 고르게 되어버리는 상황(대칭적인 구조)을 막기 위해서는 초깃값을 랜덤 하게 설정해야 한다.
배치 정규화
배치정규화의 장점은 여러개가 있다. 먼저, 학습 속도를 개선시켜 주어 학습을 빨리 진행할 수 있게 될 뿐만 아니라, 초깃값에 크게 의존하지 않으며, 오버피팅을 억제한다는 장점이 있다. 해당 장점들은 딥러닝 학습의 골칫거리들을 해소시켜 준다. 배치 정규화가 하는 것은 학습할 때 미니배치를 단위로 정규화해주는 것이며, 이것은 데이터의 분포가 평균이 0, 분산이 1이 되도록 정규화하는 것이다. 배치정규화의 계산그래프로는 아래와 같이 그릴 수 있다.
오버피팅
오버피팅이라는 것은 신경망이 훈련데이터에만 지나치게 적응되어버려서 그 외의 데이터에는 제대로 대응하지 못하는 상태를 의미한다. 기계학습은 훈련데이터에는 포함되지 않는, 아직 보지 못한 데이터가 주어졌을 때 올바르게 식별해 내는 범용 성능을 지향한다. 복잡하고 높은 표현력을 가지는 모델을 만들어내는 것도 중요하지만, 그만큼 오버피팅을 억제할 수 있어야 한다.
오버피팅은 주로,
- 매개변수가 많고, 표현력이 높은 모델인 경우
- 훈련 데이터가 적은 경우
에 발생한다.
가중치 감소
오버피팅은 가중치 매개변수의 값이 커서 발생하는 경우가 많기 때문에, 학습 과정에서 큰 가중치에 대해 그에 상응하는 큰 패널티를 부과하여 오버피팅을 억제하는 방법이다. 손실함수에 가중치의 L2 노름을 더하는 것으로 간단하게 구현할 수 있지만, 신경망 모델이 복잡해지면 가중치 감소만으로는 대응하기 어려워진다.
드롭아웃
Dropout은 은닉층의 뉴런을 무작위로 삭제하면서 학습하는 방법으로, 삭제된 뉴런은 신호를 전달하지 않게 된다. 훈련때는 데이터를 흘릴 때마다 삭제할 뉴런을 무작위로 선택하고, 시험 때는 모든 뉴런에 신호를 전달한다. 드롭아웃을 구현할 때에는 순전파를 담당하는 메서드에서는 훈련 때만 잘 계산해 두면 시험 때는 단순히 데이터를 흘리기만 하면 되는 것이다.
import numpy as np
class Dropout:
def __init__(self, dropout_ratio = 0.5):
self.dropout_ratio = dropout_ratio
self.mask = None
def forward(self, x, train_flg = True):
if train_fig:
self.mask = np.random.rand(*x.shape) > self.dropout_ratio
return x*self.mask
else:
return x*(1.0 - self.dropout_ratio)
def backward(self, dout):
return dout * self.mask
순전파 때마다 삭제할 뉴런을 self.mask에 False로 표시하는 것이 핵심이다. 순전파때 신호를 통과시키는 뉴런은 역전파 때도 신호를 그대로 통과시키고, 순전파 때 차단했던 뉴런은 역전파 때도 차단한다.
드롭아웃을 적용하니, 훈련 데이터에 대한 정확도가 100%에 도달하지도 않게 되었으며, 시험데이터와의 정확도 차이도 줄어들게 되었다. 즉, 표현력을 높이면서도 오버피팅을 억제했다고 볼 수 있다.
*드롭아웃은 앙상블 학습과 밀접하다. 앙상블은 개별적으로 학습시킨 여러 모델의 출력을 평균내어 추론하는 방식이다. 이를 사용하면 신경망의 정확도가 몇% 정도 개선된다. 드롭아웃이 학습 때 뉴런을 랜덤 하게 삭제하는 행위를 앙상블 학습 때 매번 다른 모델을 학습시키는 것과 연관 지을 수 있다.
적절한 하이퍼파라미터 값
검증데이터
모델의 성능을 개선시키고 실험하기 위해 하이퍼파라미터를 다양한 값으로 설정하게 되는데, 이때 시험데이터를 사용하면 안된다. 시험 데이터를 하이퍼파라미터를 조정하기 위해 사용한다면 해당 하이퍼 파라미터 값이 시험 데이터에 오버피팅 된다. 즉, 하이퍼파라미터 값이 시험데이터에만 적합하도록 조정되는 것이기 때문에 범용 성능이 떨어지게 된다. 따라서, 훈련데이터와 시험데이터를 제외하고도 하이퍼파라미터값을 조정하기 위한 데이터인 검증데이터를 마련해야 한다.
정리하면, 데이터의 용도는 아래와 같다.
- 훈련 데이터 : 매개변수 학습
- 검증 데이터 : 하이퍼파라미터 성능 평가
- 시험 데이터 : 신경망의 범용 성능 평가
프로젝트를 시작할 때에 데이터셋 구축을 제일 먼저 하게 될 텐데, 코드상에서 분리를 시켜도 되고, 이미 분리되어 있는 데이터셋을 가져다가 활용해도 된다.
하이퍼파라미터 최적화
하이퍼 파라미터의 대략적인 범위를 먼저 설정한 뒤에 랜덤하게 값을 골라내고 그 값으로 정확도를 평가해야 한다. 해당 작업을 여러 번 반복하여 최적 값의 범위를 좁혀나가는 것이 핵심이다. 딥러닝 학습에는 매우 오랜 시간이 걸리므로(며칠 ~ 몇 주까지도 걸릴 수 있음) 성능이 좋지 않을 것 같은 것은 빠르게 포기하는 것이 좋고, 1회 평가에 걸리는 시간을 단축하기 위해 에폭을 작게 하는 것이 효과적이다.
- 하이퍼파라미터 값의 범위를 설정
- 설정된 범위 내에서 하이퍼파라미터 값을 무작위로 추출
- 1단계에서 샘플링한 값을 사용하여 학습하고, 검증 데이터로 정확도를 평가
- 1,2단계를 특정횟수 반복하여 그 정확도의 결과를 보고 하이퍼파라미터의 범위를 좁힘