지금까지 단계마다 구성한 코드를 한 파일에 담았다. 이제는 DeZero의 규모가 커졌기 때문에 패키지로 정리할 것이다.
1. 패키지로 정리
파이썬에는 모듈, 패키지, 라이브러리라는 용어를 사용하는데 각각의 의미는 다음과 같다.
모듈 | 모듈은 파이썬 파일이다. 다른 파이썬 프로그램에서 import하여 사용하는 것을 가정하고 만ㄴ들어진 파이썬 파일을 '모듈'이라 한다. |
패키지 | 패키지느 어러 모듈을 묶은 것이다. 패키지를 만들려면 먼저 디렉터리를 만들고 그 안에 모듈(파이썬 파일)을 추가한다. |
라이브러리 | 라이브러리는 여러 패키지를 묶은 것이다. 하나 이상의 디렉터리로 구성된다. 때로는 패키지를 라이브러리라고 부르기도 한다. |
1) 파일 구성
|
|ㅡㅡ dezero
| |ㅡㅡ __init__.py
| |ㅡㅡ core_simple.py
| |ㅡㅡ ⋯
| |ㅡㅡ utils.py
|
|
|ㅡㅡ steps
| |ㅡㅡ step01.py
| |ㅡㅡ ⋯
| |ㅡㅡ step60.py
|
위 처럼 구성한 뒤 dezero디렉터리에 모듈을 추가할 것이다. 이 dezero라는 패키지가 바로 현재 만들고 있는 딥러닝 프레임워크이다.
2) core 클래스로 옮기기
앞서 정의했던 클래스들과 함수들을 core_simple.py라는 파일로 옮길 것이다. 이 파일은 나중에는 최종 형태인 core.py로 바꿀 계획이다. 참고로 exp, square 등의 함수는 나중에 function.py 파일에 추가할 것이다.
<클래스>
· Config
· Variable
· Function
· Add(Function)
· Mul(Function)
· Neg(Function)
· Sub(Function)
· Div(Function)
· Pow(Function)
<함수>
· using_config
· no_grad
· as_array
· as_variable
· add
· mul
· neg
· sub
· rsub
· div
· rdiv
· pow
위의 클래스와 함수를 core_simple.py 파일에 복사를 하면 외부의 파이썬 파일에서 다음과 같이 dezero를 import할 수 있다.
import numpy as np
from dezero.core_simple import Variable
x = Variable(np.array(1.0))
print(x) #Variable(1.0)
from 모듈 import 클래스/ 함수 형태로 임포트할 수 있다. 그리고 import 모듈 as A 형태로 임포트하면 A라는 이름으로 모듈을 임포트 할 수 있다. 예를 들어, import dezero.core_simple as dz 라고 임포트 하면, 임포트한 모듈 내의 클래스나 함수는 dz.Variable과 같이 사용할 수 있다.
3) 연산자 오버로드
이제 오버로드한 연산자들을 dezero/core_simple.py에 옮길 것이다. 연산자를 오버로드하는 함수 setup_variable은 아래와 같다.
def setup_variable():
Variable.__add__ = add
Variable.__radd__ = add
Variable.__mul__ = mul
Variable.__rmul__ = mul
Variable.__neg__ = neg
Variable.__sub__ = sub
Variable.__rsub__ = rsub
Variable.__truediv__ = div
Variable.__rtruediv__ = rdiv
Variable.__pow__ = pow
연산자를 오버로드하는 함수 setup_variable()은 dezero/__init__.py에서 호출할 것이다. __init__.py는 모듈이 임포트되면 처음으로 실행되는 파일이다. 따라서 dezro/__init__.py에 아래 코드를 작성할 것이다.
from dezero.core_simple import Variable
from dezero.core_simple import Function
from dezero.core_simple import using_config
from dezero.core_simple import no_grad
from dezero.core_simple import as_array
from dezero.core_simple import as_variable
from dezero.core_simple import setup_variable
setup_variable()
__init__.py에서 setup_variable()을 호출함으로써 dezero패키지 사용자는 연산자 오버로드가 된 상태에서 Variable을사용할 수 있다. 또한 __init__.py에 위의 코드들을 작성하고 나면 dezero패키지에서 다음과 같이 간소화된 형태로 Variable클래스를 임포트할 수 있다.
#from dezero.core_simple import Variable
from dezero import Variable
4) 실제 __init__.py 파일
23단계부터 32단계까지는dezero/core_simple.py 파일을 사용하다가 33단계부터는 dezero/core.p로 대체할 것이다. 그래서 __init__.py에서는 core_simple.py와 core.py중 하나를 선택하여 임포트하도록 작성한다.
is_simple_core = True
if is_simple_core:
from dezero.core_simple import Variable
from dezero.core_simple import Function
from dezero.core_simple import using_config
from dezero.core_simple import no_grad
from dezero.core_simple import as array
from dezero.core_simple import as_variable
from dezero.core_simple import setup_variable
else:
from dezero.core import Variable
from dezero.core import Function
#생략
setup_variable()
5) dezero 임포트하기
이제 모듈간 이동을 할 수 있도록 모듈 검색 경로를 추가할 것이다.
if '__file__' in globals():
import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import numpy as np
from dezero import Variable
x = Variable(np.array(1.0))
y = (x + 3) ** 2
y.backward()
print(y) #variable(16.0)
print(x.grad) #8.0
if '__file__' in globals(): 에서 __file__ 이라는 전역 변수가 정의되어 있는지 확인한다. 이번 단계용 step23.py로 예를 들면, 터미널에서 step23.py를 실행하면 __file__변수가 정의된다. 그리고 현재 파일 step23.py이 위치한 디렉터리의 부모 디렉터리를 모듈 검색 경로에 추가 한다. 이제 파이썬 명령어를 어떤 위치에서 실행하든 디렉터리 파일들을 제대로 임포트할 수 있다.
※ 참고로 검색 경로 추가 코드는 이후에 pip install dezero 명령어로 DeZero 패키지가 설치되면 DeZero 패키지가 파이썬 검색 경로에 추가되므로 위와 같이 경로를 수동으로 추가하지 않아도 된다.
2. 복잡한 함수의 미분
이제 DeZero는 대표 연산자(*, +, -, /, **)를 지원하므로 파이썬 프로그래밍을 하듯 코딩할 수 있다. 물론 input과 output의 type은 Variable이다. 이번 단계에서는 최적화 문제에서 자주 사용되는 테스트 함수를 볼 것이다. DeZero를 이용하여 함수를 직접 미분할 예정이다.
1) Sphere 함수
import numpy as np
from dezero import Variable
def sphere(x, y):
z = x ** 2 + y ** 2
return z
x = Variable(np.array(1.0))
y = Variable(np.array(1.0))
z = sphere(x, y)
z.backward()
print(x.grad, y.grad) #2.0 2.0
2) matyas 함수
def matyas(x, y):
z = 0.26 * (x ** 2 + y ** 2) - 0.48 * x * y
return z
x = Variable(np.array(1.0))
y = Variable(np.array(1.0))
z = matyas(x, y)
z.backward()
print(x.grad, y.grad) #0.0400000000000036 0.0400000000000036
3) Goldstein-Price 함수
def goldstein(x, y):
z = (1 + (x + y + 1)** 2 * (19 - 14*x + 3*x**2) - 14*y + 6*x*y + 3*y**2)) *
(30 + (2*x - 3*y)**2 * (18 -32*x + 12*x**2 + 48*y - 36*x*y + 27*y**2))
return z
x = Variable(np.array(1.0))
y = Variable(np.array(1.0))
z = goldstein(x, y)
z.backward()
print(x.grad, y.grad) #-5376.0 8064.0
이제 mul(), add(), pow() 등의 함수를 쓰지 않고도 *, +, -, /, **과 같은 연산자를 통해 복잡한 함수도 간단하게 코딩하고 미분을 자동으로 계산할 수 있다.
'AI > 딥러닝 프레임워크 개발' 카테고리의 다른 글
27단계) 테일러 급수 미분 (0) | 2021.06.29 |
---|---|
25~26단계) 계산 그래프 시각화 , DOT (0) | 2021.06.29 |
20~22단계) 연산자 오버로드 (0) | 2021.06.19 |
19단계) 변수 사용성 개선 (0) | 2021.06.19 |
17~18단계) 메모리 관리 방식 , 순환 참조 , 메모리 절약 모드 (0) | 2021.06.19 |
댓글