class Variable:
def __init__(self, data):
self.data = data
ex) x는 Variable 인스턴스 / 실제 데이터는 x 안에
x는 데이터 자체가 아니라 데이터를 담은 상자
import numpy as np
data = np.array(1.0)
x = Variable(data)
#######################
x.data = np.array(2.0)
넘파이의 다차원 배열 (텐서, tensor)
숫자 등의 원소가 일정하게 모여 있는 데이터 구조
0차원 배열(스칼라), 1차원 배열(벡터), 2차원 배열(행렬)
넘파이의 ndarray 인스턴스에는 ndim 이라는 변수 존재 number of dimensions, '차원 수' 를 의미)
함수 (Function)?
어떤 변수로부터 다른 변수로의 대응 관계를 정한 것
계산 그래프
class Function:
def __call__(self, input):
x = input.data
y = x ** 2
output = Variable(y)
return output
- Function 클래스는 Variable 인스턴스를 입력받아 Variable 인스턴스를 출력
- Variable 인스턴스의 실제 데이터는 인스턴스 변수인 data에 있음
__call__ 메서드
파이썬의 특수 메서드 함수를 호출하는 것처럼 클래스의 객체도 호출 가능하도록 만들어줌 f = Function() 형태로 함수의 인스턴스를 변수 f 에 대입한 후, 이후에 f(...) 형태로 __call__ 메서드 호출 가능
위에서 만든 클래스 사용
x = Variable(np.array(10))
f = Function()
y = f(x)
print(type(y)) # -> <class '__main__.Variable>
print(y.data) # -> 100
- Function 클리스를 기반 클래스로서, 모든 함수에 공통되는 기능 구현으로 수정
- 구체적인 함수는 Function 클래스를 상속한 클래스에서 구현
class Function:
def __call__(self, input):
x = input.data
y = self.forward(x) #구체적인 계산은 forward 함수에서
output = Variable(y)
return output
def forward(self, x):
raise NotImplementedError()
raise NotImplementedError()
raise 키워드와 NotImplementedError를 조합하여 사용하면 "아직 구현되지 않은 부분입니다"라는 오류를 강제로 발생시키는 것이 가능하다.
forward 메서드가 예외를 발생시키는 이유는 이 클래스의 forward 메서드를 직접 호출한 사람에게 '이 메서드는 상속하여 구현해야 한다'는 사실을 알려주기 위함이다.
class Square(Function):
def forward(self, x):
return x**2
#동작 확인 코드
x = Variable(np.array(10))
f = Square()
y = f(x)
print(type(y)) # -> <class '__main__.Variable>
print(y.data) # -> 100
상속 : class 자식클래스(부모클래스) 물려주는 클래스(Parent, Super)의 내용(속성과 메소드)을 물려받는 클래스(Child, sub)가 가지게 되는 것 다중상속 가능
메소드 오버라이딩 부모 클래스의 메소드를 자식 클래스에서 재정의 하는 것
#y=e^x 함수 구현
class Exp(Function):
def forward(self, x):
return np.exp(x)
합성 함수 (composite function)?
여러 함수로 구성된 함수 (순서대로 적용하여 변환 전체를 하나의 큰 함수로 보는 것도 가능)
Function 클래스의 __call__ 메서드는 입출력이 모두 Variable 인스턴스 이므로 연이어 사용할 수 있음
#y = (e^(x^2))^2 계산
A = Square()
B = Exp()
C = Square()
x = Variable(np.array(0.5))
a = A(x)
b = B(a)
y = C(b)
print(y.data) #-> 1.648721270
합성함수 그래프
미분?
'변화율'을 의미, 극한으로 짧은 시간(순간)에서의 변화량
미분 수식곡선 y=f(x) 위의 두 점을 지나는 직선
위 그림에서 폭 h 를 0에 가깝게 줄여 x의 변화 비율을 구하면 그 값이 y=f(x)의 미분
y=f(x) 가 어떤 구간에서 미분 가능하다면 해당 구간의 모든 x에 대하여 미분 가능이 성립
f'(x)는 f(x) 의 도함수
수치 미분 (numerical differentiation)?
미세한 차이를 이용하여 함수의 변화량을 구하는 방법
작은 값을 사용하여 '진정한 미분'을 근사 함 ==> 오차 포함
컴퓨터는 극한을 취급할 수 없으니 h를 극한과 비슷한 값으로 대체 (h=1e-4, 매우 작은 값)
- 그러나 너무 작은 값이어서 반올림 오차(rounding error)로 인해 소수점 8자리 이상은 생략 되어 0.0으로 나타남
진정한 미분 : x 위치의 함수의 기울기 (접선)
이번 구현에서의 미분 : ( x + h ) 와 x 사이의 기울기
==> 미분과 이번 구현의 값은 엄밀히 일치하지 않음 (무한히 h를 0으로 좁히지 못하기 때문에 발생)
"수치 미분" : 아주 작은 차분으로 미분하는 것 "해석적 미분" : 수식을 전개해 미분하는 것 / 오차를 포함하지 않는 “ 진정한 미분 “ 값
간단히 말해 해석적 미분은 우리가 수학 시간에 배운 바로 그 미분이고, 수치 미분은 이를 근사치로 계산하는 방법이다. 수치해석학은 해석학 문제에서 수치적인 근삿값을 구하는 알고리즘을 연구하는 학문이다
출처: https://ce-notepad.tistory.com/9
근사 오차를 줄이는 방법
중앙 차분
x 와 ( x + h ) 차이를 구하는 대신 ( x + h ) 와 ( x - h ) 일 때의 함수의 차분을 계산하는 방법