앞 장에서 가중치 매개변수 에 대한 손실 함수의 기울기를 수치 미분을 사용해 구했다. 하지만 수치 미분은 계산 시간이 오래 걸린다.

하지만 오차역전파법(backpropagation)은 이를 효율적으로 계산할 수 있다.

 

5.1 계산 그래프 (computational graph)

 

계산 그래프는 계산 과정을 그래프로 나타낸 것이다. 

 

1. 계산 그래프를 구성한다.

2. 그래프에서 계산을 왼쪽에서 오른쪽으로 진행한다.

 

'계산을 왼쪽에서 오른쪽으로 진행'하는 단계를 순전파(forward propagation), 그 반대를 역전파(backward propagation)

 

 

5.1.3 왜 계산 그래프로 푸는가?

 

  • '국소적 계산'에 집중하여 문제를 단순화할 수 있다.
  • 중간 계산 결과를 보관할 수 있다. 
  • 역전파를 통해 '미분'을 효율적으로 계산할 수 있다.

역전파에 의한 미분값의 전달

 

5.2 연쇄법칙

 

'국소적 미분'을 전달하는 원리는 연쇄법칙(Chain rule)에 따른 것이다. 다음 내용부터 연쇄법칙을 설명하고 그것이 계산 그래프 상의 역전파와 같다는 사실을 밝힐 것이다.

##앞으로 계산그래프는 computational graph, 연쇄법칙은 Chain rule로 서술하겠습니다. 특히나 Chain rule 같은 경우는 미분적분학에 나오는 부분인 만큼 원어를 사용할 것입니다.

 

5.2.1 Computational graph의 역전파

역전파의 계산 절차는 신호 에 노드의 국소적 미분(편미분)을 곱한 후에 다음 노드로 전달하는 것이다. 

 

 

5.2.2 Chain rule 이란?

 

미분적분학의 내용으로 Chain rule을 검색해서 알아보자. 아주 쉽다.

 

 

5.2.3 Chain rule과 Computational Graph

 

그림1

 

5.3 역전파 

 

5.3.1 덧셈 노드의 역전파

 

그림2
그림3

t = x+y의 x에 대한 t의 편미분을 생각해보자, x는 1차항이기 때문에 편미분 값은 1이 나오게 된다. 그렇기 때문에 [그림2]에서 편미분값이 그대로 전달되는 것이다. ([그림1]에서의 dt/dx 가 1임)

 

 

5.3.2 곱셈 노드의 역전파

 

 

곱셈 노드 역전파는 상류의 값의 순전파 때 입력 신호들을 '서로 바꾼 값'을 곱해서 하류로 보낸다. 

**암기하려고 하지말자, 단순한 수학일 뿐이다!!

 

곱셈 역전파의 예시

 

5.4 단순한 계층 구현하기

 

5.4.1 곱셈 계층

 

class MulLayer:
    def __init__(self):
        self.x=None
        self.y=None

    def forward(self, x, y): #순전파
        self.x=x
        self.y=y
        out = x*y
        
        return out
    
    def backward(self, dout): #역전파
        dx = dout * self.y
        dy = dout * self.x
        
        return dx, dy

dx, dy는 실제로 dz/dx, dz/dy 를 의미한다. 다음 그림을 내용을 코드로 옮겨보자

apple = 100
apple_num = 2
tax = 1.1 

mul_apple_layer = MulLayer()
mul_tax_layer = MulLayer()

apple_price = mul_apple_layer.forward(apple, apple_num)
price = mul_tax_layer.forward(apple_price, tax)

print(price) #순전파 결과

#역전파
dprice = 1
dapple_price, dtax = mul_tax_layer.backward(dprice)
dapple, dapple_num = mul_apple_layer.backward(dapple_price)

print(dapple, dapple_num, dtax)

 

5.4.2 덧셈 계층

class AddLayer:
    def __init__(self, x,y):
        pass #실행할 코드가 없음을 의미
        
    def forward(self, x, y):
        out = x+y
        return out
    
    def backward(self, dout):
        dx = dout *1
        dy = dout *1
        return dx, dy

apple = 100
apple_num = 2
orange = 150
orange_num = 3
tax = 1.1

# layer
mul_apple_layer = MulLayer()
mul_orange_layer = MulLayer()
add_apple_orange_layer = AddLayer()
mul_tax_layer = MulLayer()

# forward
apple_price = mul_apple_layer.forward(apple, apple_num)  # (1)
orange_price = mul_orange_layer.forward(orange, orange_num)  # (2)
all_price = add_apple_orange_layer.forward(apple_price, orange_price)  # (3)
price = mul_tax_layer.forward(all_price, tax)  # (4)

# backward
dprice = 1
dall_price, dtax = mul_tax_layer.backward(dprice)  # (4)
dapple_price, dorange_price = add_apple_orange_layer.backward(dall_price)  # (3)
dorange, dorange_num = mul_orange_layer.backward(dorange_price)  # (2)
dapple, dapple_num = mul_apple_layer.backward(dapple_price)  # (1)

print("price:", int(price))
print("dApple:", dapple)
print("dApple_num:", int(dapple_num))
print("dOrange:", dorange)
print("dOrange_num:", int(dorange_num))
print("dTax:", dtax)
price: 715
dApple: 2.2
dApple_num: 110
dOrange: 3.3000000000000003
dOrange_num: 165
dTax: 650

+ Recent posts