티스토리 뷰

AI/Deep Learning

밑시딥3 정리

미남잉 2023. 3. 8. 17:59
728x90

제1고지

- 다차원 배열을 tensor라고 하며, 방향을 차원(dimension) 혹은 축(axis)라고 합니다.

- 컴퓨터 과학에서 그래프는 노드(node)와 에지(edge)로 구성된 데이터 구조를 말함

- __call__ 메서드는 파이썬의 특수 메서드. 이 메메서드를 정의하면 f = Function() 형태로 함수의 인스턴스 변수를 변수 f에 대입해두고, 나중에 f(...) 형태로 __call__ 메서드를 호출

- 'NotImplementedError'는 ㅇ이 메서드는 상속하여 구현해야 한다는 의미

- assert 문은 결과가 True가 아니면 예외가 발생함


class Variable:
    def __init__(self, data):
        self.data = data
        self.grad = None
        self.creator = None

    def set_creator(self, func):
        self.creator = func

    def backward(self):
        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) # 하나 앞의 함수를 리스트에 추가한다

- 반복문을 이용한 구현. 처리해야 할 함수들을 funcs라는 리스트에 차례대로 집어넣음

- while 블록 안에서 funcs.pop()을 호출하여 처리할 함수 f를 꺼내고, f의 backward 메서드를 호출함

- 이때 f.input과 f.output에서 함수 f의 입력과 출력 변술르 얻음으로써 f.backward()의 인수와 반환값을 올바르게 설정 가능


- 재귀는 함수를 재귀적으로 호출할 때마다 중간 결과를 메모리에 유지하면서(스택에 쌓으면서) 처리를 이어감

- numpy는 0차원의 ndarray를 제곱하면 결과의 데이터 타입이 np.float32/64로 바뀜

- np.isscaler는 입력 데이터가 numpy.float64 같은 스칼라 타입인지 확인해주는 함수임 (int와 float 타입은 스칼라로 판단)

 

제2고지

class Function:
    def __call__(self, input):
        x = input.data  # 1
        y = self.forward(x) # 2
        output = Variable(as_array(y)) # 3
        output.set_creator(self)    # 4
        self.input = input
        self.output = output
        return output
    
    def forward(self, x):
        raise NotImplementedError()
    
    def backward(self, gy):
        raise NotImplementedError()

- __call__ 메서드는 1) Variable이라는 상자 안에서 실제 데이터를 꺼낸 다음, 2) forward 메서드에서 구체적인 계산을 진행

- 3)계 산 결과를 Variable에 넣고, 4) 자신이 창조자라고 원산지를 표시함

- 이상의 로직을 염두에 두고 __call__ 메서드의 인수와 반환값을 리스트로 바꿈

class Function:
    def __call__(self, inputs):
        xs = [x.data for x in inputs]
        ys = self.forward(xs)
        outputs = [Variable(as_array(y)) for y in ys]

        for output in outputs:
            output.set_creator(self)
        self.inputs = inputs
        self.outputs = outputs

    def forward(self, xs):
        raise NotImplementedError()
    
    def backward(self, gys):
        raise NotImplementedError()

- 리스트 내포를 사용

- 현재 코드와 개선 코드: 개선 전 코드의 경우 현재의 Add 클래스는 인수를 리스트에 모아서 받고 결과는 튜플로 반환하여 ㅆ음. 그러나 개선한 코드는 리스트나 튜플을 거치지 않고 인수와 결과를 직접 주고받음

# 현재 코드

xs = [Variable(np.array(2)), Variable(np.array(3))]
f = Add()
ys = f(xs)
y = ys[0]

# 개선 코드

x0 = Variable(np.array(2))
x1 = Variable(np.array(3))

f = Add()

y = f(x0, x1)

- 함수를 정의할 때, 인수에 별표를 붙이면 호출할 때 넘긴 인수들을 별표를 붙인 인수 하나로 모아서 받을 수 있음

- 현재 코드와 개선 코드: 개선 전 코드는 인수는 리스트로 전달되고, 결과는 튜플로 반환합니다. 개선 후는 입력도 변수를 직접 받고, 결과도 변수를 직접 돌려줍니다.

# 개선 전 코드
class Add(Function):
	def forward(self, xs):
    	x0, x1 = xs
        y = x0 + x1
        return (y,)
        
# 개선 후 코드
class Add(Function):
	def forwrad(self, x0, x1):
    	y = x0 + x1
        return y

- * : 리스트 언팩. 리스트의 원소를 낱개로 풀어서 전달하는 기법

 

728x90
댓글