2021. 3. 10. 23:07ㆍ개인 공부 공간/딥러닝
파이썬 함수로 이용하기
기존 Square클래스를 사용하는 코드는 다음과 같다.
x = Variable(np.array(0.5))
f = Square()
y = f(x)
f
를 이용해 Square
클래스의 인스턴스를 생성후 그 인스턴스를 호출해야 하는 번거로움이 있다. 이를 효율적으로 변경하기 위해 파이썬 함수를 사용하면 편리하다.
def square(x):
f = Square()
return f(x)
def exp(x):
f = Exp()
return f(x)
생성한 square
, exp
두 함수를 이용해 역전파 과정을 코드로 구현하면 다음과 같다.
x = Variable(np.array(0.5))
y = square(exp(square(x)))
y.grad = np.array(1.0)
y.backward()
print(x.grad)
실행 결과
3.297442541400256
위의 코드를 보면 기존의 코드와 또 다른 차이점이 하나 존재한다. square(exp(square(x)))
이 부분을 보면 기존과 다르게 함수를 연속으로 한번에 적용에 한줄에 표현하였다.
backward 메서드 간소화
기존의 코드를 조금 더 단순화 하기 위해 매번 역전파 과정에서 y.grad = np.array(1.0)
를 입력하는 대신 Variable
의 backward
메서드에 다음과 같은 코드를 추가한다.
class Variable:
... # 생략
def backward(self):
if self.grad is None:
self.grad = np.ones_like(self.data)
funcs = [self.creator]
while funcs: # 빈 리스트가 아닐때까지
f = funcs.pop() # 함수를 가져온다
x, y = f.input, f.output # 함수의 입력과 출력을 가져온다
x.grad = f.backward(y.grad) # backward 메서드를 호출한다
if x.creator is not None:
funcs.append(x.creator) # 하나 앞의 함수를 리스트에 추가한다
np.ones_like
를 이용해 변수의 grad
가 None
이면 즉, 변수의 생성자가 없으면 자동으로 1을 채운 self.data
형상과 데이터 타입이 같은 ndarray
인스턴스를 생성한다. 이를 통해 매번 y.grad
값을 1로 지정해주고 시작해야 하는 번거로움이 사라진다.
x = Variable(np.array(0.5))
y = square(exp(square(x)))
y.backward()
print(x.grad)
실행 결과
3.297442541400256
ndarray만 취급하기
Variable
의 데이터로 ndarray
의 데이터 타입만 취급하도록 의도했지만 실수로 float
, int
등의 다른 데이터 타입을 입력하는 경우가 발생할수도 있다. 이를 방지하기 위해 다른 데이터타입을 입력할 경우 오류를 발생시키게 할 필요성이 존재한다.
class Variable:
def __init__(self, data):
if data is not None:
if not isinstance(data, np.ndarray):
raise TypeError('{}은(는) 지원하지 않습니다.'.format(type(data)))
self.data = data
self.grad = None
self.creator = None
... # 생략
x = Variable(np.array(1.0)) # Ok
x = Variable(None) # ok
x = Variable(1.0) # RaiseError
실행 결과
TypeError: <class 'float'>은(는) 지원하지 않습니다.
이와 같이 데이터 타입이 None
이거나 ndarray
인 경우에는 문제가 없지만 그 외의 데이터 타입을 입력하면 예외가 발생한다.
하지만 이 경우 주의해야 할 부분이 하나 존재한다. 0차원 ndarray
를 이용해 연산을 하면 출력이 np.float64
의 형태가 되어 문제가 발생한다. 이를 방지하기 위해 다음과 같은 함수를 생성해 Function
클래스에 추가해야 한다.
def as_array(x):
if np.isscalar(x):
return np.array(x)
return x
위의 함수는 입력 데이터가 스칼라 타입인지 확인해주는 기능을 제공한다.
class Function:
def __call__(self, input):
x = input.data
y = self.forward(x)
output = Variable(as_array(y))
output.set_creator(self) # 출력 변수에 창조자를 설정
self.input = input
self.output = output # 출력도 저장
return output
위와 같이 순전파의 결과인 y
를 Variable
로 감쌀 때 as_array()
를 이용한다. 이를 통해 출력 결과는 항상 ndarray
인스턴스임을 보장해준다.
출처: 사이토 고키, 『밑바닥부터 시작하는 딥러닝3』, 개앞맵시, 한빛미디어(2020)
'개인 공부 공간 > 딥러닝' 카테고리의 다른 글
밑바닥부터 시작하는 딥러닝3 - STEP 11 (0) | 2021.03.15 |
---|---|
밑바닥부터 시작하는 딥러닝3 - STEP 10 (0) | 2021.03.10 |
밑바닥부터 시작하는 딥러닝3 - STEP 8 (0) | 2021.03.10 |
밑바닥부터 시작하는 딥러닝3 - STEP 7 (0) | 2021.03.10 |
밑바닥부터 시작하는 딥러닝3 - STEP 6 (0) | 2021.03.10 |