학습 관련 기술들 목차
👀, 🤷♀️ , 📜
이 아이콘들을 누르시면 코드, 개념 부가 설명을 보실 수 있습니다:)
구현하기 전 읽어 볼 지식
➡ 위의 매개변수 갱신 방법들을 발전시킨 것 들이 옵티마이저이다!!!
옵티마이저 (Optimizers)
매개변수 갱신
[최적화 optimization]
매개변수의 최적값을 찾는 문제
- 신경망 학습의 목적: 손실 함수의 값을 가능한 한 낮추는 매개변수를 찾는 것
확률적 경사 하강법 SGD
최적화 중 배운 방법: 매개변수의 기울기(미분)이용
- \(W\): 갱신할 가중치 매개변수
- \(aL/aW\): \(W\) 에 대한 손실 함수의 기울기
- \(ƞ\): 학습률(실제론 0.01이나 0.001로 미리 정함)
기울어진 방향으로 일정 거리만 가겠다는 단순한 방법
👀코드 보기
class SGD:
def __init __(self, lr = 0.01):
self.lr = lr
def update(self, params, grads):
for key in params.keys():
params[key] -= self.lr * grads[key]
update (params, grads)
메서드: SGD 과정에서 반복해서 불림
params
와grads
: (지금까지의 신경망 구현과 마찬가지로) 딕셔너리 변수
👀 구현 예시 코드 보기
network = TwoLayerNet(...)
optimizer = SGD()
for i in range(10000):
...
x _batch, t _batch = get _mini _batch(...) # 미니배치
grads = network.gradient(x _batch, t _batch)
params = network.params
optimizer.update(params, grads)
...
optimizer
: ‘최적화를 행하는 자’라는 뜻의 단어
- 이 코드에서는 SGD가 그 역할 함
- 매개변수 갱신은 optimizer가 책임지고 수행하니,
- 우리는 optimizer에 매개변수와 기울기 정보만 넘겨주면 됨
이처럼 최적화를 담당하는 클래스를 분리해 구현하면 기능을 모듈화하기 좋음
[SGD 단점]
- 위 식의 최솟값은 (0,0) 인데 대부분의 화살표 방향이 그렇지X
- 최적화 갱신 경로 : 최솟값인 (0, 0)까지 지그재그로 이동하니 비효율적
- 비등방성 anisotropy 함수: (방향에 따라 성질, 즉 여기에서는 기울기가 달라지는 함수)에서는 탐색 경로가 비효율적이라는 것
원인: 기울어진 방향이 본래의 최솟값과 다른 방향을 가리켜서 - 모멘텀, AdaGrad, Adam로 단점 개선
- Y축 방향으로의
갱신 강도(위 아래)를 줄이자!!!!
SGD VS GD
공통점
- 경사하강법(GD)과 확률적 경사하강법(SGD) 모두에서 매개변수 세트를 반복적인 방식으로 업데이트하여 오류 함수를 최소화
차이점 - GD: 특정 반복의 매개변수에 대한 단일 업데이트를 수행하려면 훈련 세트의 모든 샘플을 실행해야 함
- 속도: 훈련 샘플의 수가 많고 실제로 매우 큰 경우의 매개변수 값을 업데이트하는데 너무 느림
- 오차율: SGD보다 훨씬 최소화
- SGD: 훈련 세트의 훈련 샘플 중 하나만 또는 하위 집합을 사용
- 속도: 훈련 샘플을 하나만 사용하고 첫 번째 샘플부터 즉시 개선되기 시작하므로 더 빠름
- 오차율: 오류 함수는 GD의 경우만큼 최소화되지 않음(매개변수 값이 최적 값에 도달하고 거기에서 계속 진동)
사용 용도
- GD: 정말 낮은 오차율을 원하는 경우
- SGD: 훈련 샘플의 수가 많고 실제로 매우 큰 경우의 매개변수 값을 업데이트하는데 너무 느림
📜 GD의 3가지 변형
Gradient Descent에는 Batch, Stochastic , Minibatch의 세 가지 변형이 있음
- Batch: 모든 훈련 샘플이 평가된 후 가중치를 업데이트
- Stochastic: 각 훈련 샘플 후에 가중치를 업데이트
- Minibatch: 두 세계의 장점을 결합
모멘텀 Momentum
‘운동량’을 뜻하는 단어
- \(W\): 갱신할 가중치 매개변수
- \(aL/aW\): W에 대한 손실 함수의 기울기
- \(ƞ\): 학습률
- \(v\):(velocity): 물리에서 말하는 속도
- \(αv\): 물체가 아무런 힘을 받지 않을 때 서서히 하강시키는 역할 (α는 0.9 등의 값으로 설정). 물리에서의 지면 마찰이나 공기 저항에 해당
기울기방향으로 힘을 받아 물체가 가속된다는 물리법칙을 따름
즉,
- SDG: 기울어진 방향만 뺌
- Momentum: 기울어진 방향에 마찰이나 공기저항을 제외하고 뺌(물리에서의 속도로 간주)
👀코드 보기
class Momentum:
# 인스턴스 변수 v가 물체의 속도: v는 초기화 때는 아무 값도 담지X
def __init__(self, lr = 0.01, momentum = 0.9):
self.lr = lr
self.momentum = momentum
self.v = None
# W 업데이트 식
def update(self, params, grads):
#update ( ) 가 처음 호출될 때 매개변수와 같은 구조의 데이터를 딕셔너리 변수로 저장
# 기울기와 형태를 같은 형태로 만듦
if self.v is None:
self.v = {}
for key, val in params.items():
self.v[key] = np.zeros_like(val)
#해당 속도와 기울기 조정
#위의 해당 식 구현
for key in params.keys():
# αv의 momentum= a
# v설정 식
self.v[key] = self.momentum*self.v[key] – self.lr*grads[key]
# W 설정 식
params[key] + = self.v[key]
모멘텀의 갱신 경로는 공이 그릇 바닥을 구르듯 움직임
-
SGD와 비교하면 ‘지그재그 정도’가 덜함
- x축
- 힘: 아주 작지만
- 방향: 일정
- 한 방향으로 일정하게 가속
- y축
- 힘: 크지만
- 방향: 위아래로 번갈아 받음 일정X, 상충
- y축 방향의 속도는 안정적X
- 전체적: SGD보다 x축 방향으로 빠르게 다가가 지그재그 움직임이 줄어듦
AdaGrad
학습률(ƞ): 신경망 학습에서 중요
- 이 값이 너무 작으면 학습 시간이 너무 길어지고,
- 반대로 너무 크면 발산하여 학습이 제대로 이뤄지지 않음
학습률 감소(learning rate decay): 이 학습률을 정하는 효과적 기술
- 학습을 진행하면서 학습률을 점차 줄여가는 방법
- 처음에는 크게 학습하다가 조금씩 작게 학습
- 실제 신경망 학습에 자주 쓰임
학습률을 서서히 낮추는 가장 간단한 방법: 매개변수 ‘전체’의 학습률 값을 일괄적으로 낮추는 것.
- 이를 더욱 발전시킨 것이 AdaGrad
[정의]
AdaGrad: ‘각각의’ 매개변수에 ‘맞춤형’ 값을 만들어 줌
- 개별 매개변수에 적응적으로 adaptive 학습률을 조정하면서 학습 진행.
[AdaGrad의 갱신 방법 수식]
- \(W\): 갱신할 가중치 매개변수
- \(aL/aW\): W에 대한 손실 함수의 기울기
- \(ƞ\): 학습률
- \(h\): (기존 기울기 값)^2하여 계속+
- ☉기호: 행렬의 원소별 곱셈
- \(1/h^(1/2)\):매개변수를 갱신할 때 이를 곱해 학습률을 조정
매개변수의 원소 중에서 많이 움직인(크게 갱신된) 원소는 학습률이 낮아진다는 뜻
- 학습률 감소가 매개변수의 원소마다 다르게 적용
기존 기울기에 계속 루트를 하여 점점 학습률을 낮춤
(작동방식)
AdaGrad는 과거의 기울기를 제곱하여 계속 더해감
- 학습을 진행할수록 갱신 강도가 약해짐.
- [Problem] 무한히 계속 학습한다면 갱신량이 0이 되어 더 이상 갱신 X
RMSProp
위의 [Problem]이 문제를 개선한 기법.
과거의 모든 기울기를 균일하게 더해가는 것X
지수이동평균(Exponential Moving Average, EMA)
먼 과거의 기울기는 서서히 잊고 새로운 기울기 정보를 크게- 과거 기울기의 반영 규모를 기하급수적으로 감소시킴
👀코드 보기
```python
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일 떄 대비)
- 대부분의 딥러닝 프레임 워크에서는 이 값도 인수로 설정 가능.
- y축 방향: 기울 기가 커서 처음에는 크게 움직이지만, 그 큰 움직임에 비례해 갱신 정도도 큰 폭으로 작아지도록 조정
- 그래서 y축 방향으로 갱신 강도가 빠르게 약해지고, 지그재그 움직임이 줄어듦
Adam
Adam: 두 기법(모멘텀,AdaGrad)을 융합한 것
- 모멘텀: 공이 그릇 바닥을 구르는 듯한 움직임을 보임
- AdaGrad: 매개변수의 원소마다 적응적으로 갱신 정도를 조정(y의 지그재그 변화를 줄임)
Adam: 하이퍼파라미터의 ‘편향 보정’진행
그릇 바닥을 구르듯 움직임(모멘텀)
- 모멘텀 때보다 공의 좌우 흔들림이 적음(이는 학습의 갱신 강도를 적응적으로 조정해서)
[Adam의 3개의 하이퍼파라미터]
- 학습률
- 일차 모멘텀용 계수 β 1
- 이차 모멘텀용 계수 β 2
논문에 따른 기본 설정값,
- β 1 은 0.9
- β 2 는 0.999
이 값이면 많은 경우에 좋은 결과를 얻을 수 있음.
어느 갱신 방법을 이용할 것인가?
[위 4개 결과 비교]
- 각자의 장단이 있어 잘 푸는 문제와 서툰 문제가 있음
- 지금도 많은 연구에서 SGD를 사용.
- 모멘텀과 AdaGrad도 시도해볼 만한 가치가 충분.
- 요즘에는 많은 분이 Adam에 만족해함.
- 일반적으로 SGD보다 다른 세 기법이 빠르게 학습하고, 때로는 최종 정확도도 높게 나타납니다.
정리
● 매개변수 갱신 방법에는 확률적 경사 하강법(SGD ) 외에도 모멘텀, AdaGrad, Adam 등이 있다.