페이지

2022년 8월 27일 토요일

21.1 ndarray와 함께 사용하기

 우선 Variable응 ndarray 인스턴스와 함께 사용할 수 있게 하겠습니다. 전략은 간단합니다. 예를 들어 a가 Variable 인스턴스일 때 a *  np.array(2.0)이라는 코드를 만나면 ndarray인스턴스를 자동으로 Variable 인스턴스로 변환하는 것입니다. 즉, Variable(np.array(2.0))으로 변환해버리면 그다음 계산은 지금까지와 같습니다.

이를 위한 사전 준비로 as_variable이라는 편의 함수를 준비합니다. 인수로 주어진 객체를 Variable 인스턴스로 변환해부는 함수입니다. 구현은 다음과 같습니다.

def as_variable(obj):
  if isinstance(obj, Variable):
    return obj
  return Variable(obj)

이 함수는 인수 obj가 Variable 인스턴스 또는 ndarray 인스턴스라고 가정합니다.  obj가 Variable 인스턴스면 아무것도 손보지 않고 그대로 반환하고, 그렇지 않으면 Variable인스턴스로 변환하여 반환합니다.

그럼 Function클래스의 __call__ 메서드가 as_variable 함수를 이용하도록 다음 음영부분의 코드를 추가합니다.

import weakref    
class Function(object):
  def __call__(self, *inputs):
    inputs = [as_variable(x) for x in inputs]
    
    xs = [x.data for x in inputs]
    ys = self.forward(*xs)  
    if not isinstance(ys, tuple):   
      ys = (ys,)
    outputs = [Variable(as_array(y)) for y in ys]

    self.generation = max([x.generation for x in inputs]) 

    for output in outputs:
      output.set_creator(self)  
    self.inputs = inputs  #
    self.outputs = [weakref.ref(output) for output in outputs]  
   
    return outputs if len(outputs) > 1 else outputs[0]

이와 같이 인수 inputs에 담긴 각각의 원소 x를 Variable 인스턴스로 변환합니다. 따라서 ndarray 인스턴스 주어지면 Variable 인스턴스로 변환됩니다. 그러면 이후의 처리는 모든 변수가 Variable 인스턴스인 상태로 진행됩니다.

DeZero에서 사용하는 모든 함수(연산)는 Function클래스를 상속하므로 실제 연산은 Function클래스의 __call__ 메서드에서 이루어집니다. 따라서 이 __call__ 메서드에 가한 수정은 DeZero에서 사용하는 모든 함수에 적용됩니다.


그러면 새로운 DeZeror를 사용하여 계산을 해봅시다.

x = Variable(np.array(2.0))
y = add(x, np.array(3.0))
#y = x + np.array(3.0)
print(y)
variable(5.0)

y = x + np.array(3.0)이라는 코드를 실행했고, 출력을 보면 제대로 작동함을 알 수 있습니다. ndarray 인스턴스가 Variable 인스턴스로 자동 변환된 결과죠, 이렇게 ndarray와 Variable을 함께 사용할 수 있게 되었습니다.


댓글 없음: