[밑바닥부터 시작하는 딥러닝] #6 오차역전파, Affine층의 역전파

Clay Ryu's sound lab·2022년 3월 8일
0

Note for 2022

목록 보기
16/47

오차역전파

오차역전파를 사용하는 것은 미분을 할때 평균 변화율의 극한으로 미분을 계산하는 것에서 미분의 공식을 이용하는 것으로의 변화이다. 계산 비용이 줄어든다.

그래프

1.함수의 그래프
2.node를 연결하는 방식

순전파

역전파






연쇄법칙chain rule

chain rule은 현재 flow의 순간 변화율을 구할때 upstream gradient와 local gradeint를 곱해주는 것이다.

코드 구현

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
        
class addlayer:
    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 * 1
        dy = dout * 1
        
        return dx, 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)

dprice = 1
dapple_price, dtax = mul_tax_layer.backward(dprice)
dapple, dapple_num = mul_apple_layer.backward(dapple_price)

print(dapple, dapple_num, dtax)

Affine layer의 역전파

X dot W 형태의 순방향의 역전파를 할때 upstream gradient를 ug라고 한다면
dX = ug dot WT, dW = XT dot ug가 된다. 또한 연산이 2가지 밖에 없기 때문에 더하기는 ug를 그대로 나눠가지고 곱하기는 ug에 상대방의 값을 그대로 가져오면 된다.

문제풀이

아래의 문제는 dx, dw, db를 구하는 문제이다.
답은 db = [2,1,-1], dx = [1,7], dw = [[2,1,-1],[2,1,-1]]이다.

코드구현

import numpy as np

class Affine:
    def __init__(self, W, b):
        self.W = W
        self.b = b
        
        self.x = None
        self.original_x_shape = None
        
        self.dW = None
        self.db = None
        
    def forward(self, x):
        self.original_x_shape = x.shape
        x = x.reshape(x.shape[0], -1)
        self.x = x
        
        out = np.dot(self.x, self.W) + self.b
        
        return out
    
    def backward(self, dout):
        dx = np.dot(dout, self.W.T)
        self.dW = np.dot(self.x.T, dout)
        self.db = np.sum(dout, axis=0)
        
        dx = dx.reshape(*self.original_x_shape)
        
        return dx
x = np.array([[1,1]])
W = np.array([[1,2,3],[4,5,6]])
b = np.array([7,8,9])

affine = Affine(W,b)
affine.forward(x)

affine.backward(np.array([[2,1,-1]]))
affine.dW
affine.db

배치처리를 고려해보자

배치처리를 하게되면 인풋의 shape의 첫번째 값은 batch_num(N)이 된다.
다만 db의 경우에 그렇게 되는 것을 증명하기가 좀 까다로운데 여기서에서는 numpy.sum(dout, axis=0)을 하는 것으로 shape을 맞춰주는 것으로 충분하다고 하고 넘어가기로 한다.

Repeat노드와 Sum노드

repeat 노드를 통해 벡터가 행렬이 된다. sum 노드를 통해 행렬이 벡터가 된다.
또한 repeat노드의 역전파는 sum 노드가 되고, sum노드의 역전파는 repeat 노드가 된다.

repeat 노드의 역전파라는 관점에서 db를 구하는 원리를 알 수 있다.

profile
chords & code // harmony with structure

0개의 댓글