Deep learning/모델 구현

35. 매개변수를 모아두는 계층

jwjwvison 2021. 10. 17. 15:27
  • Parameter 클래스 구현

 Parameter 클래스는 Variable 클래스와 똑같은 기능을 갖게 한다. 그래서 다음과 같이 구현한다.

class Parameter(Variable):
    pass

 Parameter 인스턴스와 Variable 인스턴스는 기능은 같지만 구별할 수는 있다.

 이와 같이 Parameter 인스턴스와 Variable 인스턴스를 조합하여 계산할 수 있다.

 

  • Layer 클래스 구현

Layer 클래스는 매개변수를 유지하고 매개변수를 사용하여 변환을 하는 클래스이다.

 

Layer 클래스의 구현은 다음과 같다.

from dezero.core import Parameter

class Layer:
    def __init__(self):
        self._params=set()

    def __setattr__(self,name,value):
        # 이름이 name인 인스턴스 변수에 값으로 value로 전달해준다
        if isinstance(value,Parameter):
            self._params.add(name)
        super().__setattr__(name,value)

 Layer 클래스에는 _params 라는 인스턴스 변수가 있다. _params에는 Layer 인스턴스에 속한 매개변수를 보관한다.

 

 __setattr__은 인스턴스 변수를 설정할 때 호출되는 특수 메서드이다. __setattr__(self,name,value)는 이름이 name인 아닌 인스턴스 변수에 값으로 value로 전달해준다. 

 

 여기에서는 value가 Parameter 인스턴스라면 self._params에 name을 추가한다. 이렇게 하여 Layer 클래스가 갖는 매개변수를 인스턴스 변수 _params에 모아둘 수 있다. 다음은 예시 코드이다.

 이와 같이 layer 인스턴스 변수를 설정하면 Parameter 인스턴스를 보유하고 있는 인스턴스 변수 이름만 layer._params에 추가된다. 또한 인스턴스 변수 __dict__에는 모든 인스턴스 변수가 딕셔너리 타입으로 저장되기 때문에 Parameter 인스턴스만 꺼낼 수 있다.

 

 그런 다음 Layer 클래스에 다음 4개의 메서드를 추가한다.

    def __call__(self, *inputs):
        outputs=self.forward(*inputs)
        if not isinstance(outputs,tuple):
            outputs=(outputs,)
        self.inputs=[weakref.ref(x) for x in inputs]
        self.outputs=[weakref.ref(y) for y in outputs]
        return outputs if len(outputs) > 1 else outputs[0]

    def forward(self,inputs):
        raise NotImplementedError()

    def params(self): #Layer 인스턴스에 담겨 있는 Parameter 인스턴스들을 꺼내준다
        for name in self._params:
            yield self.__dict__[name]

    def cleargrads(self):
        for param in self.params():
            param.cleargrad()

 __call__ 메서드는 입력받은 인수를 건데 forward 메서드를 호출한다. forward 메서드는 자식 클래스에서 구현할 것이다. 

 

 params 메서드는 Layer 인스턴스에 담겨 있는 Parameter 인스턴스들을 꺼내주고, cleargrads 메서드는 모든 매개변수의 기울기를 재설정한다.

 

  • Linear 클래스 구현

 이어서 선형 변환을 하는 linear 클래스를 구현하겠다.

class Linear(Layer):
    def __init__(self,out_size,nobias=False,dtype=np.float32,in_size=None):
        super().__init__()
        self.in_size=in_size
        self.out_size=out_size
        self.dtype=dtype

        self.W=Parameter(None,name='W')
        if self.in_size is not None: # in_size가 지정되어 있지 않다면 나중으로 연기
            self._init_W()
        
        if nobias:
            self.b=None

        else:
            self.b=Parameter(np.zeros(out_size,dtype=dtype),name='b')

    def _init_W(self):
        I,O=self.in_size,self.out_size
        W_data=np.random.randn(I,O).astype(self.dtype) * np.sqrt(1/I)
        self.W.data=W_data

    def forward(self,x):
        # 데이터를 흘러보내는 시점에 가중치 초기화
        if self.W.data is None:
            self.in_size=x.shape[1]
            self._init_W()

        y=F.linear(x,self.W,self.b)
        return y

 가중치와 편향은 self.W = Parameter(...)와 self.b=Parameter(...) 형태로, Parameter 인스턴스를 인스턴스 변수에 설정한다. 이렇게 함으로써 두 Parameter 인스턴스 변수의 이름이 self._params에 추가된다.

 

 

  • Layer를 이용한 신경망 구현
import numpy as np
from dezero import Variable
import dezero.functions as F

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

I,H,O=1,10,1
W1=Variable(0.01 * np.random.randn(I,H))
b1=Variable(np.zeros(H))
W2=Variable(0.01 * np.random.randn(H,O))
b2=Variable(np.zeros(O))

def predict(x):
    y=F.linear(x,W1,b1)
    y=F.sigmoid(y)
    y=F.linear(y,W2,b2)
    return y

lr=0.2
iters=10000

for i in range(iters):
    y_pred=predict(x)
	loss=F.mean_squared_error(y,y_pred)
    
    W1.cleargrad()
    b1.cleargrad()
    W2.cleargrad()
    b2.cleargrad()
    loss.backward()
    
    W1.data -= lr * W1.grad.data
    b1.data -= lr * b1.grad.data
    W2.data -= lr * W2.grad.data
    b2.data -= lr * b2.grad.data
    
    if i % 1000 == 0:
        print(loss)

 

'Deep learning > 모델 구현' 카테고리의 다른 글

37. Optimizer 로 수행하는 매개변수 갱신  (0) 2021.10.23
36. Model 클래스  (0) 2021.10.23
34. 신경망  (0) 2021.10.17
33. 형상 변환 함수, 합계 함수  (0) 2021.10.16
32. 고차 미분  (0) 2021.10.14