728x90
반응형
매개변수 갱신
- 신경망 학습의 목적은 손실 함수의 값을 가능한 한 낮추는 매개변수를 찾는 것이었다.
- 매개변수의 최적값을 찾는 문제이며, 이런 문제를 푸는 것을 최적화(optimization)라 한다.
- 매개변수 공간은 매우 넓고 복잡해서 최적의 솔루션을 찾기 어렵다. 또한 심층 신경망에서는 매개변수의 수가 엄청나게 많아져서 사태는 더욱 심각해진다.
- 최적의 매개변수 값을 찾는 단서로 기울기(미분,오차역전파)를 이용했다. 매개변수의 기울기를 구해, 기울어진 방향으로 매개변수 값을 갱신하는 일을 반복해 점점 최적의 값에 다가갔다.
- 이것이 확률적 경사 하강법(SGD)이란 단순한 방법, 매개변수 공간을 무작정 찾는 것보다는 '똑똑한'방법이다.
- 지금 서 있는 장소에서 가장 크게 기울어진 방향으로 가자는 것이 SGD전략 - 반복시 언젠가 '깊은 곳' 찾아갈 수 있을지도 모른다.
확률적 경사 하강법(SGD)
수식
SGD 구현
- 인수 lr은 learning rate(학습률)를 뜻한다.
class SGD:
def __init__(self, lr=0.01):
self.lr = lr # lr learning rate(학습률)
def update(self, params, grads):
for key in params.keys():
params[key] -= self.lr * grads[key]
SGD단점
- 비등방성(anisotropy) 함수(방향에 따라 성질, 즉 기울기가 달라지는 함수)에서는 탐색 경로가 비효율적이다.
- 비등방성 함수에서는 SGD같이 무작정 기울어진 방향으로 진행하는 단순한 방식보다 더 영리한 묘안이 간절해진다.
- SGD가 지그재그로 탐색하는 근본 원인은 기울어진 방향이 본래의 최솟값과 다른 방향을 가리켜서라는 점도 있다.
- SGD단점을 개선해주는 모멘텀, AdaGrad, Adam 세 방법이 있다.
SGD에 의한 최적화 갱신 경로
- 최솟값인 (0,0)까지 지그재그로 이동하니 비효율적이다.
모멘텀(Momentum)
- 운동량을 뜻한다. - 물리와 관련이 있다.
수식
- W는 갱신할 가중치 매개변수, n은 학습률이다. v라는 변수가 새로 나오지만 물리에서 말하는 속도 velocity에 해당한다.
모멘텀의 이미지
모멘텀 구현
# 모멘텀 구현
class Momentum:
def __init__(self, lr=0.01, momentum=0.9):
self.lr = lr
self.momentum = momentum
self.v = None
def update(self, params, grads):
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():
self.v[key] = self.momentum*self.v[key] - self.lr*grads[key]
params[key] += self.v[key]
- 인스턴스 변수 v = 물체의 속도
- update()가 처음 호출될 때 매개변수와 같은 구조의 데이터를 딕셔너리 변수로 저장한다.
모멘텀에 의한 최적화 갱신 경로
- 공이 그릇 바닥을 구르듯 움직인다.
- SGD와 비교하면 지그재그가 덜한다.
- x축의 힘은 아주 작지만 방향은 변하지 않아서 한 방향으로 일정하게 가속하기 때문이다.
- y축의 힘은 크지만 위아래로 번갈아 받아서 상충하여 y축의 방향은 안정적이지 않다.
- 전체적으로 SGD보다 x축 방향으로 빠르게 다가가 지그재그 움직임이 줄어든다.
AdaGrad
- 신경망 학습에서는 학습률 값이 중요하다. 이 값이 너무 작으면 학습 시간이 너무 길어지고, 반대로 너무 크면 발산해 학습이 제대로 이뤄지지 않는다.
- 학습률을 정하는 효과적 기술로 학습률 감소(learning rate decay)가 있다. - 학습을 진행하면서 학습률을 점차 줄여가는 방식
- 처음에는 크게 학습하다가 조금씩 작게 학습한다는 얘기, 실제 신경망 학습에 자주 쓰인다.
- 학습률을 서서히 낮추는 가장 간단한 방법은 매개변수 '전체'의 학습률 값을 일괄적으로 낮추는 방법이다.
- - 이것을 더욱 발전시킨 것이 AdaGrad - '각각의' 매개변수에 '맞춤형'값을 만들어준다.
- AdaGrad는 개별 매개변수에 적응적으로(adaptive) 학습률을 조저앟며 학습을 진행한다.
AdaGrad 갱신 방법 수식
- W는 갱신할 가중치 매개변수, 알파L/알W은 W에 대한 손실 함수의 기울기, h는 기존 기존 기울기 값을 제곱해 계속 더해준다.
AdaGrad
- AdaGrad는 과거의 기울기를 제곱해 계속 더해간다. 그래서 학습을 진행할수록 갱신 강도가 약해진다.
- 실제로 무한히 계속 학습한다면 어느 순간 갱신량이 0이 되어 전혀 갱신되지 않게 된다.
- 이 문제를 개선한 방법이 RMSProp이라는 방법이다.
RMSProp
- 과거의 모든 기울기를 균일하게 더해가는 것이 아니라, 먼 과거의 기울기는 서서히 잊고 새로운 기울기 정보를 크게 게 반영한다.
- 이것을 지수이동평균(Exponential Moving Average, EMA)라고 하며 과거 기울기의 반영 규모를 기하급수적으로 감소시킨다.
AdaGrad 구현
# AdaGrad 구현
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이라는 작은 값이 0으로 나누는 사태를 막아준다.
- 1e-7이라는 작은 값을 더하는 이유는 이 작은 값은 self.h[key]에 0이 담겨 있다 해도 0으로 나누는 사태를 막아주기 때문이다.
AdaGrad에 의한 최적화 갱신 경로
- 최솟값을 향해 효율적으로 움직인다.
- y축 방향은 기울기가 커서 처음에는 크게 움직이지만, 그 큰 움직임에 비례해 갱신 정도도 큰 폭으로 작아지도록 조정된다.
- y축 방향으로 갱신 강도가 빠르게 약해지고, 지그재그 움직임이 줄어든다.
Adam
- 모멘텀은 공이 그릇 바닥을 구르는 듯한 움직임을 보였다.
- AdaGrad는 매개변수의 원소마다 적응적으로 갱신 정도를 조정했다.
- 이 두 기법을 융합한것이 Adam
- 2015년 제안된 새로운 방법
- 이론은 복잡하지만 직관적으로는 모멘텀과 AdaGrad를 융합한 듯한 방법
- 하이퍼파라미터의 '편향 보정'이 진행된다는 점도 Adam의 특징
Adam에 의한 최적화 갱신 경로
네 가지 방법 MNIST 데이터셋으로 본 갱신 방법 비교
import os
import sys
sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import matplotlib.pyplot as plt
from mnist import load_mnist
from util import smooth_curve
from multi_layer_net import MultiLayerNet
from optimizer import *
# 0. MNIST 데이터 읽기==========
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)
train_size = x_train.shape[0]
batch_size = 128
max_iterations = 2000
# 1. 실험용 설정==========
optimizers = {}
optimizers['SGD'] = SGD()
optimizers['Momentum'] = Momentum()
optimizers['AdaGrad'] = AdaGrad()
optimizers['Adam'] = Adam()
#optimizers['RMSprop'] = RMSprop()
networks = {}
train_loss = {}
for key in optimizers.keys():
networks[key] = MultiLayerNet(
input_size=784, hidden_size_list=[100, 100, 100, 100],
output_size=10)
train_loss[key] = []
# 2. 훈련 시작==========
for i in range(max_iterations):
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
for key in optimizers.keys():
grads = networks[key].gradient(x_batch, t_batch)
optimizers[key].update(networks[key].params, grads)
loss = networks[key].loss(x_batch, t_batch)
train_loss[key].append(loss)
if i % 100 == 0:
print( "===========" + "iteration:" + str(i) + "===========")
for key in optimizers.keys():
loss = networks[key].loss(x_batch, t_batch)
print(key + ":" + str(loss))
# 3. 그래프 그리기==========
markers = {"SGD": "o", "Momentum": "x", "AdaGrad": "s", "Adam": "D"}
x = np.arange(max_iterations)
for key in optimizers.keys():
plt.plot(x, smooth_curve(train_loss[key]), marker=markers[key], markevery=100, label=key)
plt.xlabel("iterations")
plt.ylabel("loss")
plt.ylim(0, 1)
plt.legend()
plt.show()
SGD학습 진도가 가장 느리고 나머지 세 기법의 진도는 비슷하지만 AdaGrad가 조금 더 빠른 것 같다.
하이퍼파라미터인 학습률과 신경망의 구조(층 깊이 등)에 따라 결과가 달라진다는 것이 중요하다.
출처 : 밑바닥부터 시작하는 딥러닝
https://www.hanbit.co.kr/store/books/look.php?p_code=B8475831198
728x90
반응형
최근댓글