본문 바로가기
Study 공부할레나

[스터디/밑시딥3] 제 4고지 신경망 만들기_46. Optimizer로 수행하는 매개변수 갱신

by LENA-cfg 2023. 10. 15.

46.1 Optimizer 클래스

class Optimizer:
    def __init__(self):
        self.target = None
        self.hooks = []

    def setup(self, target):
        self.target = target
        return self

    def update(self):
        params = [p for p in self.target.params() if p.grad is not None]

        for f in self.hooks:
            f(params)

        for param in params:
            self.update_one(param)

    def update_one(self, param):
        raise NotImplementedError()

    def add_hook(self, f):
        self.hooks.append(f)

Optimizer 클래스의 초기화 메서드에서는 target과 hooks라는 두 개의 인스턴스 변수를 초기화하고 setup 메서드는 매개변수를 갖는 클래스를 인스턴스 변수인 target으로 설정합니다.

 

update 메서드는 모든 매개변수를 갱신하지만 인스턴스 변수가 grad가 None인 매개변수는 갱신을 건너 뀌고 구체적인 매개변수 갱신은 update_one 메서드에서 수행하는데, 바로 이 메서드를 Optimizer의 자식 클래스에서 재정의합니다.

 

Optimizer 클래스는 매개변수 생신에 앞서 전체 매개변수를 전처리해주는 기능도 갖췄고 원하는 전처리가 있다면 add_hook 메서드를 사용하여 전처리를 수행하는 함수를 추가합니다. 

이구조때문에 가중치 감소, 기울기 클리핑 같은 기법을 이용할 수 있습니다. 

46.2 SGD 클래스 구현

class SGD(Optimizer):
    def __init__(self, lr=0.01):
        super().__init__()
        self.lr = lr

    def update_one(self, param):
        param.data -= self.lr * param.grad.data

Optimizer를 상속하는 SGD클래스입니다.

초기화 메서드는 학습률을 받아 초기화하고 update_one 메서드에서 매개변수 갱신코드를 구현합니다. 

*SGD 확률적 경사 하강법으로 확률적은 대상 데이터 중에서 무작위로 선별한 데이터에 대해 경사하강법을 수행한다는 뜻입니다. 

46.3 SGD 클래스를 사용한 문제 해결

if '__file__' in globals():
    import os, sys
    sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import numpy as np
from dezero import optimizers
import dezero.functions as F
from dezero.models import MLP


np.random.seed(0)
x = np.random.rand(100, 1)
y = np.sin(2 * np.pi * x) + np.random.rand(100, 1)

lr = 0.2
max_iter = 10000
hidden_size = 10

model = MLP((hidden_size, 1))
optimizer = optimizers.SGD(lr).setup(model)

for i in range(max_iter):
    y_pred = model(x)
    loss = F.mean_squared_error(y, y_pred)

    model.cleargrads()
    loss.backward()

    optimizer.update()
    if i % 1000 == 0:
        print(loss)

model = MLP((hidden_size, 1))
optimizer = optimizers.SGD(lr).setup(model)

MLP 클래스를 사용해 모델을 생성해주고 SGD 클래스로 매개변수를 갱신합니다. 

46.4 SGD 이외의 최적화 기법

Momentum 구현하겠습니다.

46.1의 수식은 물체가 기울기 방향으로 힘을 받아 가속된다는 물리 법칙을 나타내고 46.2의 식에 의해 속도만큼 위치(매개변수)가 이동합니다.

class MomentumSGD(Optimizer):
    def __init__(self, lr=0.01, momentum=0.9):
        super().__init__()
        self.lr = lr
        self.momentum = momentum
        self.vs = {}

    def update_one(self, param):
        v_key = id(param)
        if v_key not in self.vs:
            xp = cuda.get_array_module(param.data)
            self.vs[v_key] = xp.zeros_like(param.data)

        v = self.vs[v_key]
        v *= self.momentum
        v -= self.lr * param.grad.data
        param.data += v

각 매개벼누에 속도에 해당하는 데이터가 있고 이 데이터들을 딕셔너리 타입의 인스턴스 변수 self.vs에 유지합니다. 초기화 시에는 vs가 안담겨있지만 update_one()이 처음 호출될 때 매개변수와 같은 타입의 데이터를 생성합니다.