컴퓨터/밑딥3

[밑바닥부터 시작하는 딥러닝3] 연산자 오버로드

xeskin 2020. 12. 14. 11:04
반응형

20. 연산자 오버로드 (1)

20.2 연산자 오버로드

  • 곱셈/덧셈의 특수 메소드를 사용하여 연산자 오버로드를 했다.
# Variable 간 *를 사용하면 1) __mul__ 메소드가 호출, 2) 그 안의 mul() 함수를 호출
def __mul__(self, other):
  # a * b 연산시 a는 self, b는 other에 대응
  return mul(self, other)

def __add__(self, other):
  return add(self, other)

# 파이썬에서는 함수도 객체이므로 함수 자체를 할당하여 처리하면 다음과 같이 작성할 수 있다.
Variable.__mul__ = mul
Variable.__add__ = add

21. 연산자 오버로드 (2)

21.1 ndarray와 함께 사용하기

  • Variable 인스턴스 a,b가 있을 때 'a*b, a+b'와 같은 코드를 작성할 수 있지만 몇가지 제한이 있다.

    1. a*np.array(2.0)과 같이 ndarray 인스턴스와 함께 사용할 수 없다.
    2. 3+b와 같이 수치 데이터를 같이 사용할 수 없다.
  • 본 장에서는 이를 함께 사용할 수 있게끔 코드를 구현한다.

    • a가 Variable 인스턴스일 때 a * np.array(2.0)이라는 코드를 만나면 ndarray 인스턴스를 자동으로 Variable 인스턴스로 변환

      ( np.array(2.0) -> Variable(np.array(2.0)) )

def as_variable(obj):
  """
  인수 obj가 Variable 인스턴스면 그대로 반환
  그렇지 않으면 Variable 인스턴스로 변환하여 반환
  """
  if isinstance(obj, Variable):
    return obj
  return Variable(obj)

21.2 float, int와 함께 사용하기

  • 작성했던 add()에 "as_array()"를 추가하여 위에서 구현했던 것과 합치는 것은 부분적으로만 해결해주며, 크게 두 가지 문제점이 있다.

    1. 첫 번째 인수가 float나 int인 경우

    y = 2.0 * x
    • '*' 같은 이항 연산자는 피연산자의 위치에 따라 호출되는 특수 메소드가 다르다.
      • 곱셈의 경우 피연산자가 좌항이면 mul, 우항이면 rmul이 호출된다.
    • 이는 다음 특수 메소드를 추가해주면 된다.
    # __add__와 __radd__는 self, other에 대응하는 변수의 순서에 차이가 있다. mul도 같음.
    Variable.__add__ = add
    Variable.__radd__ = add
    Variable.__mul__ = mul
    Variable.__rmul__ = mul

    2. 좌항이 ndarray 인스턴스인 경우

    • 좌항이 ndarray 인스턴스이고 우항이 Variable 인스턴스면 좌항인 ndarray의 add 메소드가 호출된다.
    • 하지만, Variable 인스턴스인 radd 메소드가 호출되길 원한다.
    • 이를 위해서 '연산자 우선순위'를 지정해야한다.
      • Variable 인스턴스 속성에 array_priority를 추가하고 그 값을 큰 정수로 설정해야 한다.

22. 연산자 오버로드 (3)

  • 새로운 연산자를 추가하려면 다음 세 스텝을 밟으면 된다.
    1. Function 클래스를 상속하여 원하는 함수 클래스를 구현한다. (예: Mul 클래스)
    2. 파이썬 함수로 사용할 수 있게 만든다. (예: mul 함수)
    3. Variable 클래스의 연산자를 오버로드한다. (예: Variable.__mul__ = mul)
반응형