본문 바로가기

2022.01./코딩 수업

02.07

[6] 옵티마이저

6. Adam

 

class Adam: # 전개를 하고 묶는 작업을 거쳐야 Adam의 점화식과 일치한다는 것을 알 수 있다.

 

"""Adam (http://arxiv.org/abs/1412.6980v8)"""

 

def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):

self.lr = lr

self.beta1 = beta1 # B1 가중치, 관성과 미분치 미분할 때 필요 mn = B1mn-1 + (1 - B1) * df(xn)

self.beta2 = beta2 # B2 가중치, 미분치 좌표별 제곱할 때 필요 vn = B2vn-1 + (1-B2)*df(xn)*(df(xn)

self.iter = 0 # 보정작업에서 베타의 n 승해준 값 빼줘서 0에 편향되는 것을 막아줬었다. n

self.m = None # 관성 역할

self.v = None # 속도

 

def update(self, params, grads):

if self.m is None:

self.m, self.v = {}, {}

for key, val in params.items():

self.m[key] = np.zeros_like(val)

self.v[key] = np.zeros_like(val)

 

self.iter += 1

lr_t = self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter)

# 학습률 * 1/루트 (new)vn * (new)mn

for key in params.keys():

#self.m[key] = self.beta1*self.m[key] + (1-self.beta1)*grads[key]

#self.v[key] = self.beta2*self.v[key] + (1-self.beta2)*(grads[key]**2)

self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])

# m의 점화식 B1mn-1 + (1 - B1) * df(xn)

self.v[key] += (1 - self.beta2) * (grads[key]**2 - self.v[key])

# v의 점화식 vn = B2vn-1 + (1-B2)*df(xn)*(df(xn)

 

params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)

# Xn - 학습률 * 1/ 루트 (new)vn * (new)mn 로 업데이트 해라.

 

#unbias_m += (1 - self.beta1) * (grads[key] - self.m[key]) # correct bias

#unbisa_b += (1 - self.beta2) * (grads[key]*grads[key] - self.v[key]) # correct bias

#params[key] += self.lr * unbias_m / (np.sqrt(unbisa_b) + 1e-7)

6. Adam

Momentum + RMSProp

= 기존의 '관성'을 반영 + 내분점을 반영 ( 현재에 치중할 것인가, 과거에 치중할 것인가)

관성 반대방향, 중력 반대방향을 반영하려고 각각 - 를 붙였다.

 

m = 관성 역할, 초기값 0

b = 감마 역할 (내분점), 초기값 0, 보통 1에 가까운 아주 큰 수로 감마를 둔다. 그래서 시작점에서 아주 가깝게, 점이 이동한다.(과거에 치중하고 있으니까 초기값 0에 편향되는 경향) -> 보정작업이 필요함.

mn = B1mn-1 + (1 - B1) * df(xn)

가중치 B2 등장

vn = B2vn-1 + (1-B2)*df(xn)*(df(xn)

 

보정작업

(new)mn = mn/1-b1^n+1 (n이 진행될수록 점점 더 작아지는. 원점에 가까울 수록 더 멀리 보내는 역할)

(new)vn = vn/1-b2^n+1

 

6-1 점화식

Xn+1 = Xn - 학습률 * 1/ 루트 (new)vn * (new)mn

 

매우 어렵다. 연습문제 풀면서 익혀볼래.

 

연습문제 1 :

f(x, y) = xy

x0 = (1, 2)

학습률 = 1

B1= 1/2 , B2= 1/2 (과거, 현재 똑같이 치중하겠다는 말)

 

df(x, y) = (y, x)

df(1, 2) = (2, 1)

m0 = 1/2 * m-1 + 1/2 * (2, 1) -> m-1 초기값 (0,0)

m0 = (1, 1/2) -> 보정작업 거쳐야 함

(new)m0 = m0/1/2 = 2 * (1, 1/2) = (2, 1)

 

v0 = 1/2 * v-1 + 1/2 * (4, 1) -> v-1 초기값 (0,0)

v0 = (2, 1/2) -> 보정작업 거쳐야 함

(new)v0 = (2, 1/2)/1/2 = (4, 1)

 

X1 = (1, 2) - 1/ 루트 (4, 1) * (2, 1)

X1 = (1, 2) - (1/2, 1) * (2, 1) = (0, 1)

 

df(X1) = (1, 0)

m1 = 1/2 * (1, 1/2) + 1/2 * (1, 0) = (1/2, 1/4) + (1/2, 0) = (1, 1/4)

(new)m1 = (1, 1/4)/1- 1/4 = (1, 1/4)/3/4 = (4, 1)/3 = (4/3, 1/3)

v1 = 1/2 * (2, 1/2) + 1/2*(1, 0) =(1, 1/4)+ (1/2 ,0) = (3/2 , 1/4)

(new)v1 = v1/1-1/4 = (3/2 , 1/4)/3/4 = (2, 1/3)

 

 

X2 = (0, 1) - 1/ 루트(2, 1/3) *(4/3, 1/3) =(0, 1) - (1/루트2, 루트3) * (4/3 , 1/3 ) = (-2루트2/3, 1-루트3/3)

 

코드로 풀어보았다.

 

#Adam 1번문제

BTS = Adam(1., 1/2, 1/2)

params= {'x':1.,'y':2.}

grads = {'x':2.,'y':1.}

BTS.update(params,grads)

print(BTS.m)

print(BTS.v)

print(params)

 

grads = {'x':1.,'y':0}

BTS.update(params,grads)

print(BTS.m)

print(BTS.v)

print(params)

 

연습문제2:

f(x, y) = x2+xy

x0 = (1, 1)

학습률 = 1

B1 = 1/2 B2 =1/2

df(x, y) = (2x + y, x)

df(1, 1) = (3, 1)

m0 = 1/2 * (0, 0) + 1/2 * (3, 1) = (3/2, 1/2)

v0 = 1/2 * (0, 0) + 1/2 *(9, 1) = (9/2, 1/2)

 

(new)m0 = (3/2, 1/2)/1/2 = (3, 1)

(new)v0 = (9/2, 1/2)/1/2 = (9, 1)

 

X1 = (1, 1) - 1/ 루트 (9, 1) * (3, 1) = (1, 1) - (1/3, 1) * (3, 1) = (0, 0)

df(X1) = (0, 0)

 

m1 = 1/2 * (3/2, 1/2) = (3/4, 1/4)

v1 = 1/2 * (9/2, 1/2) = (9/4, 1/4)

 

(new)m1 = (3/4, 1/4)/3/4 = (1, 1/3)

(new)v1 = (9/4, 1/4)/3/4 = (3, 1/3)

 

6-1 점화식

X2 = (0, 0) - 1/ 루트 (3, 1/3) * (1, 1/3) = (-루트3/3, -루트3/3)

 

#Adam 2번문제

BTOB = Adam(1., 1/2, 1/2)

params= {'x':1.,'y':1.}

grads = {'x':3.,'y':1.}

BTOB.update(params,grads)

print(BTOB.m) # (3/2, 1/2)

print(BTOB.v) # (9/2, 1/2)

print(params)

 

grads = {'x':0,'y':0}

BTOB.update(params,grads)

print(BTOB.m) # (3/4, 1/4)

print(BTOB.v) # (9/4, 1/4)

print(params)

print(-np.sqrt(3)/3)

 

7.옵티마이저 벤치마크

 

경사하강법 - 가장 가파른 방향으로 눈 감고 이동

Momentum - 관성 + 중력

NAG - 모멘텀 스텝만큼 먼저 이동

AdaGrad - 스텝, 변수마다 학습률 조정

RMSProp - 정체되지 않게끔 가중치 평균(내분) 해 학습률 보정

Adam - Momentum + RMSProp

 

7-1 반복문 사용해서 각각 그래프 그려보기

 

optimizer_compare_naive.py

 

# coding: utf-8

import sys, os

sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정

import numpy as np

import matplotlib.pyplot as plt

from collections import OrderedDict

from optimizer import *

 

 

def f(x, y):

return x**2 / 20.0 + y**2 # f(x, y) = 1/20 * x^2 + y^2

 

 

def df(x, y):

return x / 10.0, 2.0*y # df(x, y) = (x/10 , 2y)

 

init_pos = (-7.0, 2.0) # 시작점

params = {}

params['x'], params['y'] = init_pos[0], init_pos[1]

grads = {}

grads['x'], grads['y'] = 0, 0

 

 

optimizers = OrderedDict()

optimizers["SGD"] = SGD(lr=0.95) # 이 것들로 이동해서 그려보라는 뜻

optimizers["Momentum"] = Momentum(lr=0.1) # 누락된 정보들은 디폴트값으로 하겠다는 말.

optimizers["AdaGrad"] = AdaGrad(lr=1.5) # 유독 학습률이 큰 이유 : 처음은 보폭을 크게 점점 잰걸음으로...

optimizers["Adam"] = Adam(lr=0.3) # 각각 클래스로 만든 인스턴스를 밸류값으로 취함

optimizers["RMSprop"] = RMSprop(lr=0.3)

optimizers["Nesterov"] = Nesterov(lr=0.3)

 

 

idx = 1 # 1씩 늘어날 것이다

 

plt.figure(figsize = (10, 15))

for key in optimizers:

optimizer = optimizers[key] # SGD, Momentum 등 차례로 키값에 들어갈거임

x_history = []

y_history = []

params['x'], params['y'] = init_pos[0], init_pos[1] # init_pos = (-7.0, 2.0) [0], [1]

 

for i in range(30): # 30 걸음 걷겠다

x_history.append(params['x']) # 점의 x좌표 기록하겠다

y_history.append(params['y']) # 점의 y좌표 기록하겠다

 

grads['x'], grads['y'] = df(params['x'], params['y']) #미분값 딕셔너리 밸류값으로 정의해주기

optimizer.update(params, grads)

 

 

x = np.arange(-10, 10, 0.01) # 범위 -10 ~ 10이고 공차가 0.01인 등차수열

y = np.arange(-5, 5, 0.01)

 

X, Y = np.meshgrid(x, y) # x는 행에 붙이고, y는 열에 붙이겠다는 말.

Z = f(X, Y)

 

# 외곽선 단순화

mask = Z > 7 # 함수값이 7보다 크면 True, 아니면 False.

Z[mask] = 0 # True 부분은 날려버리고 등위선 그리지 않는다.

 

# 그래프 그리기

plt.subplot(3, 2, idx)

idx += 1 # 인덱스 늘어나는 순서대로(key 순서대로) 그림 그린다.

plt.plot(x_history, y_history, 'o-', color="red") # 점좌표 모아놓은 리스트를 이용해 그림을 그린다.

plt.contour(X, Y, Z) #등위선 그려라

plt.ylim(-10, 10)

plt.xlim(-10, 10)

plt.plot(0, 0, '+')

#colorbar()

#spring()

plt.title(key)

plt.xlabel("x")

plt.ylabel("y")

 

plt.show()

 

7-2 np.meshgrid(x, y) 보충설명

 

import numpy as np

 

x= np.array([1, 2, 3])

y= np.array([4, 5, 6])

X, Y = np.meshgrid(x, y)

 

print(X)

# [[1 2 3]

# [1 2 3]

# [1 2 3]]

 

print(Y)

# [[4 4 4]

# [5 5 5]

# [6 6 6]]

 

Z = X**2 + Y**2

print(Z) # 행렬 제곱이 아닌, 원소별 제곱

# [[17 20 25]

# [26 29 34]

# [37 40 45]]

 

7-3 6가지 그래프 mnist 같이 경주시켜보기.

optimizer_compare_mnist.py

 

# coding: utf-8

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] # 60000개 데이타 * 784

batch_size = 128

max_iterations = 2000 # 2000 걸음으로 내려가겠다.

 

 

# 1. 실험용 설정==========

optimizers = {} #각각 변수별 인스턴스 밸류로 취함

optimizers['SGD'] = SGD() # 784- 100 - 100 - 100- 100 -10

optimizers['Momentum'] = Momentum() # 784- 100 - 100 - 100- 100 -10

optimizers['AdaGrad'] = AdaGrad() # 784- 100 - 100 - 100- 100 -10

optimizers['Adam'] = Adam() # 784- 100 - 100 - 100- 100 -10

optimizers['RMSprop'] = RMSprop() # 784- 100 - 100 - 100- 100 -10

optimizers['Nesterov'] = Nesterov()

 

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: # 100의 배수가 될 때마다 출력해주세요. ( 잘 되고 있는지 확인을 위해서 )

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", "RMSprop": "v", "Nesterov": "^"}

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()

 

8. Xavier/ He 초기값

옵티마이저 6가지의 방법은 산을 어떤 효율적인 방법으로 내려갈지 고르는 것.

가중치의 초기값 설정은 초기값 설정은 어느지점에서 출발을 해야 산을 잘 내려갈 수 있을지, 출발지점을 선택하는 것.

표준편차 1로 설정하고 히스토그램 그렸더니, 아파인 시그모이드 거쳐서 양쪽으로 찰딱 붙은 형태의 그래프.

표준편차 0.1로 설정하고 그렸더니, 아파인 시그모이드 거쳐서 중간으로 완전 쏠린 형태의 그래프.

적절한 값 설정이 아주 중요하겠네.

 

weight_init_activation_histogram.py

 

 

 

 

'2022.01. > 코딩 수업' 카테고리의 다른 글

02.11  (0) 2022.02.11
02.04 옵티마이저  (0) 2022.02.07
01.28  (0) 2022.01.28
01.26 softmax(확률), 추론(배치처리), 손실함수  (0) 2022.01.26
01.25 퍼셉트론, 신경망  (0) 2022.01.25