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