페이지

2022년 8월 7일 일요일

6.2 Function클래스 추가 구현

 Function 클래스를 알아볼 차례입니다. 이전 단계까지 Function  클래스는 일반적인 계산을 하는 순전파(forward 메서드) 기능만 지원하는 상태입니다. 이외에 다음 두 기능을 추가하겠습니다.

- 미분을 계산하는 역전파(backward메서드)

- forward메서드 호출 시 건너받은 Variable 인스턴스 유지

class Function:
  def __call__(selfinput):
    x = input.data
    y = self.forward(x)
    output = Variable(y)
    self.input = input # 입력 변수를 기억(보관)한다.
    return output
  
  def forward(selfx):
    raise NotImplementedError()
  
  def backward(self, gy):
    raise NotImplementedError()


코드에서 보듯 __call__메서드에서 입력된 input을 인스턴스 변수인 self.input에 저장합니다. 이렇게 해서 나중에  backward 메서드에서 함수(Function)에 입력한 변수(Variable 인스턴스)가 필요할때 self.input에서 가져와 사용할 수 있습니다.

6.1 Variable 클래스 추가 구현

 역전파에 대응하는  Variable 클래스를 구현하겠습니다. 그러기 위해 통상값(data)과 더붙어 그에 대응하는 미분값(grad)도 저장하도록 확장합니다. 새로 추가된 코드에 음영을 덧쒸웠습니다.

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

이와 같이 새로 grad라는 인스턴스 변수를 추가했습니다. 인스턴수 변수인 data와 grad는 모두 넘파이의 다차원 배열(ndarray)이라고 가정합니다. 또한 grad는 None으로 초기화해둔 다음, 나중에 실제로 역전파를 하면 미분값을 계산하여 대입합니다.

벡터나 행렬등 다변수에 대한 미분은 기우기(gradent)라고 합니다. Variable 클래스에 새로 추가한 grad변수의 이름은 gradient를 줄인 것입니다.

STEP 6 수동 역전파

 이전 단계에서 역전파의 구동 원리를 설명했습니다. 이번 단계에서는 Variable과 Function클래스를 확장하여 역전파를 이용한 미분을 구현하겠습니다. Variable 클래스부터 살펴 보죠

5.3 계산 그래프로 살펴보기

 다음과 같이 통상적인 계산인 순전파 계산 그래프(그림 5-1)와 미분을 계산하는 역전파 계산 그래프(그림 5-4)를 위아래로 나련히 놓고 살펴봅시다.




이렇게 비교하니 순전파와 역전파의 관계가 명확히 보입니다. 예를 들어 순전파 시의 변수 a는 역전파 시의 미분  dy/da에 대응합니다, 마찬가지로 b와 dy/db가 대응하고 x 와 dy/dx가 대응합니다. 또한 함수에도 대응 관계가 보입니다. 함수 B는 역전파의 B'(a)에 대응하고 A는  A'(x)에 대응하는 식 입니다. 이렇게 변수는 '통상값'과 '미분값'이 존재하고, 함수는 '통상 계산(순전파)'과 '미분값을 구하기 위한 계산(역전파)'이 존재하는 것으로 생각할 수 있습니다. 이를 통해 역전파를 어떻게 구현할지 짐작해볼 수 있을 것 입니다.

마지막으로  [그림 5-5]의 함수 노드 C'(b)를 계산하려면 b값이 필요하다는 사실입니다. 마찬가지로 B'(a)를 구하려면 입력 a의 값이 필요합니다. 무슨 말인고 하니, 역전파 시에는 순전파 시 이용한 데이터가 필요하다는 것입니다. 따라서 역전파를 구현하려면 먼저 순전파를 하고, 이때 각 함수가 입력 변수(앞의 예에서는 x, a, b)의 값을 기억해두지 않으면 안 됩니다. 그런 다음에야 각 함수의 역전파를 계산할 수 있습니다.

이상이 역전파의 이론 설명입니다. 다소 복잡한가요? 좋은 소식을 알려드리겠습니다. 다행히 역전파는 이 책에서 가장 어려운 내용에 속한답니다. 그리고 아직 잘 이해되지 않는 부분도 실제로 코드를 실행해보면 이해될 것입니다. 다음 단계에서는 역전파를 구현하고 실제로 돌려보며 검증하겠습니다.

2022년 8월 6일 토요일

5.2 역전파 원리 도출

 이제 [식 5.2]를 차분히 살펴볼 시간입니다. [식 5.2]는 합성 함수의 미분은 구성 함수들의 미분의 곱으로 분해할 수 있음을 뜻합니다. '곱하는 순서'까지 말해주지는 않지만 사실 어떤 순서로 곱해도 상관없습니다. 그러니 [식 5.3]과 같이 출력에서 입력 방향으로(즉, 역방향으로)순서대로 계산해보겠습니다.

dy/dx = ((dy/dy*dy/db)*db/da)da/dx

[식 5.3]과 같이 출력에서 입력 방향으로, 즉 보통의 계산과는 반대 방향으로 미분을 계산합니다. 이때 [식 5.3]의 흐름은 [그림 5-2]와 같습니다.

[그림 5-2]처럼 y에서 입력 x 방향으로 곱하면서 순서대로 미분하면 최종적으로 dx/dy가 구해집니다. 계산 그래프로는 [그림 5-3]처럼 됩니다.

[그림 5-3]의 계산 그래프를 잘 관찰해봅시다. 우선 dx/dy(=1)에서 시작하여 dy/db와 곱합니다. 여기서 dy/db는 함수 y=C(b)의 미분입니다. 따라서 함수 C의 도함수를 C'의 도함수를 C''로 나타내면dy/db=C''(b)라고 쓸 수 있습니다. 마찬가지로 db/da=B'(a)이고 da/dx=A'(x)입니다. 이에 따라 [그림 5-3]의 계산 그래프는 다음과 같이 단순화할 수 있습니다.


[그림 5-4]와 같이 도함수의 곱을 함수 노드 하나로 그릴 수 있습니다. 이제 미분값이 전파되는 흐름이 평확해집니다. [그림 5-4]를 보면 'y의 각 변수에 대한 미분값'이, 즉 변수 y, b, a, x 에 대한 미분값이 오른쪽에서 왼쪽으로 전파되는 것을 알 수 있습니다. 이것이 역전파입니다. 여기서 중요한 점은 전파되는 데이터는 모두 'y의 미분값'이라는 것입니다. 구체적으로 dy/dy, dy/db, dy/da, dy/dx처럼 모두' y의 oo에 대한 미분값'이 전파되고 있습니다.


[식 5.3]과 같이 계산 순서를 출력에서 입력 방향으로 정한 이유는 y의 미분값을 전파하기 위해서입니다. 즉 y를 '중요 요소'로 대우하기 때문입니다. 만약 입력에서 출력방향으로 계산했다면 중요 요소는 입력인 x가 됩니다. 이 경우 전파되는 값은 dx/dx -> da/dx -> db/dx -> dy/dx가 되어 x 에 대한 미분을 전파하게 됩니다.


머신러닝은 주로 대량의 매개변수를 입력받아서 마지막에 손실 함수(loss function)를 거쳐 출력을 내는 형태로 진행됩니다. 손실 함수의 출력은(많은 경우) 단일한 스칼라값이며, 이 값이 '중요 요소'입니다. 즉, 손실 함수의 각 매개변수에 대한 미분을 계산해야 합니다. 이런 경우 미분값을 출려에서 입력 방향으로 전파하면 한 번의 전파만으로 모든 매개 변수에 대한 미분을 계산할 수 있습니다. 이처럼 계산이 효율적으로 이뤄지기 때문에 미분을 반대 방향으로 전파하는 방식(역전파)을 이용하는 것입니다.




5.1 연쇄 법칙

 역전파를 이해하는 열쇠는 연쇄법칙(chain rule)입니다. chain은 '사슬'이라는 뜻으로, 여러 함수를 사슬처럼 연결하여 사용하는 모습을 빗댄것입니다. 연쇄 법칙에 따르면 합성 함수(여러함수가 연결된 함수)의 미분은 구성 함수 각각을 미분한 후 곱한 것과 같습니다.

구체적인 예를 하나 들어보죠. y = F(x)라는 함수가 있다고 합시다. 이 함수는 a = A(x), b= B(a), c = C(b)라는 세 함수로 구성되어 있습니다. 계산 그래프로 그리면 [그림 5-1]처럼 됩니다.



이때 x 에 대한 y의 미분은 [식 5.1]로 표현할 수 있습니다.

dy/dx = dy/db * db/da * da/dx

[식 5.1]에서 알수 있듯이 x에 대한 y의 미분은 구성 함수 각각의 미분값을 모두 곱한 값과 같습니다. 즉, 합성 함수의 미분은 각 함수의 국소적인 미분들로 분해 할 수 있ㅆ브니다. 이것이 연쇄 법칙입니다. 또한 [식 5.1]앞에 다음과 같이 dx/dy를 명시할 수도 있습니다.

dy/dx = dy/dy*dy/db*db/da*da/dx


dy/dy는 '자신'에 대한 미분이라 항상 1입니다. 따라서 생략하는 것이 보통이지만 이 책에서는 역전파를 구현할 때를 대비하여 포함하도록 하겠습니다.

dy/dy는 y의 ㅛ에 대한 미분입니다. 이때 y가 작은 값만큼 변하면 자기 자신도 y도 당연히 같은 크기만큼 변합니다. 따라서 변화율은 어떤 함수의 경우에도 항상 1입니다.

STEP 5 역전파 이론

 우리는 수치 미분을 이용해 비분을 계산할 수 있게 되었지만 수치 미분은 계산 비용과 정확도면에서 문제가 있습니다. 지금이 바로 역전파(backpropatgation, 오차역전파법)가 구세주로 등장할 시점입니다! 역전파를 이용하면 미분을 효율적으로 계산할 수 있고 결괏값이 오차도 더 작습니다. 이 번 단계에서는 아직 역전파 구현까지는 들어가지 않고 이론 설명에 집중하겠습니다(구현은 다음 단계로 양보했습니다).