Foward
$x$ : $ ( N, XH, XW, XC ) $
$w$ : $ ( KH, KW, XC, YC ) $
$ y $ : $ ( N, YH, YW, YC ) $
$ b $ : $ (1, 1, 1, YC ) $
$x$ : 입력 이미지 데이터
$y$ : 출력 이미지 데이터
$w$ : 가중치 행렬
$b$ : 편향 벡터
$N$ : 데이터 개수 (batch size)
$XH$ , $XW$ , $XC$ : 입력 이미지 높이, 너비, 채널 사이즈
$YH$ , $YW$ , $YC$ : 출력 이미지 높이, 너비, 채널 사이즈
$KH$, $KW$ : 커널 높이, 너비 사이즈
$SH$ , $SW$ : 높이, 너비 Stride 사이즈
$PH$ , $PW$ : 높이, 너비 Padding 사이즈
$$ \\ YH = \frac{XH - KH + 2PH}{SH} + 1
\\ YW = \frac{XW - KW + 2PW}{SW} + 1 $$
$x'$ : padding 을 적용한 입력 이미지 데이터 - $ ( N, XH + 2PH, XW + 2PW, XC ) $
$ XH + 2PH = SH(YH - 1) + KH \\ XW + 2PW = SW(YW - 1) + KW $
$$ y_{h_y, w_y, c_y} = \sum_{h_k=1}^{KH}\sum_{w_k=1}^{KW}\sum_{c_x=1}^{XC}
w_{h_k, w_k, c_x, c_y} x'_{(s_h(h_y-1)+h_k), (s_w(w_y-1) + w_k), c_x} $$
수식으로 이렇게 전개되지만, 실제 구현에서는 성능상의 문제가 존재한다.
반복문을 통해 forward 를 진행하면, x 위치를 y, k 좌표로 치환한다고 해도,
$N$, $YC$ , $KH$ , $KW$, $XC$ 를 순환해야되서 5중 반복문을 수행하게 된다.
따라서 이 방식을 피하기 위해, 두 행렬의 곱 형식으로 변환해서 구현한다. 이 방법이 반복문 보다 훨씬 빠르다.
결국 $y'$ = $x'$$w'$+$b'$ 형태로 나타내고, $y'$ 을 $y$ 로 reshape 하는 과정으로 forward 한다.
여기서 $x'$ 는 ( $N$ x $YH$ x $YW$ , $XC$ x $KH$ x $KW$ ) 차원, $w'$ 는 ( $XC$ x $KH$ x $KW$ , $YC$ ) 차원, $b'$ 는 ( $1$ x $1$ x $1$ , $YC$ ) 차원, $y'$ 는 ( $N$ x $YH$ x $YW$ , $YC$ ) 차원으로 구성된다.
$y'$ 을 $y$ = ( $N$ , $YH$, $YW$, $YC$ ) 의 형태로 reshape 하게 되면 행렬곱 방식의 forward output 이 만들어진다.
예시 ) x : 5x5x3, w : 3x3x3x5, y : 2x2x5 일 때 ( bias, batch 는 무시, stride 는 2 )
$x'$
$x_c$,$k_h$, $k_w$ $y_h$ , $y_w$ \ |
1,1,1 | 1,1,2 | 1,1,3 | 1,2,1 | $x_c$, $k_h$, $k_w$ | 3,2,3 | 3,3,1 | 3,3,2 | 3,3,3 |
1,1 | $x_{1,1,1}$ | $x_{1,2,1}$ | $x_{1,3,1}$ | $x_{2,1,1}$ | $x_{s_h(y_h-1) + k_h, s_w(y_w-1) + k_w, x_c}$ | $x_{2,3,3}$ | $x_{3,1,3}$ | $x_{3,2,3}$ | $x_{3,3,3}$ |
1,2 | $x_{1,3,1}$ | $x_{1,4,1}$ | $x_{1,5,1}$ | $x_{2,3,1}$ | $x_{2,5,3}$ | $x_{3,3,3}$ | $x_{3,4,3}$ | $x_{3,5,3}$ | |
2,1 | $x_{3,1,1}$ | $x_{3,2,1}$ | $x_{3,3,1}$ | $x_{4,1,1}$ | $x_{4,3,3}$ | $x_{5,1,3}$ | $x_{5,2,3}$ | $x_{5,3,3}$ | |
2,2 | $x_{3,3,1}$ | $x_{3,4,1}$ | $x_{3,5,1}$ | $x_{4,3,1}$ | $x_{4,5,3}$ | $x_{5,3,3}$ | $x_{5,4,3}$ | $x_{5,5,3}$ |
$w'$
$y_c$ $x_c$,$k_h$, $k_w$ \ |
1 | 2 | 3 | 4 | 5 |
1,1,1 | $w_{1,1,1,1}$ | $w_{1,1,1,2}$ | $w_{1,1,1,3}$ | $w_{1,1,1,4}$ | $w_{1,1,1,5}$ |
1,1,2 | $w_{1,2,1,1}$ | $w_{1,2,1,2}$ | $w_{1,2,1,3}$ | $w_{1,2,1,4}$ | $w_{1,2,1,5}$ |
1,1,3 | $w_{1,3,1,1}$ | $w_{1,3,1,2}$ | $w_{1,3,1,3}$ | $w_{1,3,1,4}$ | $w_{1,3,1,5}$ |
1,2,1 | $w_{2,1,1,1}$ | $w_{2,1,1,2}$ | $w_{2,1,1,3}$ | $w_{2,1,1,4}$ | $w_{2,1,1,5}$ |
... | $w_{k_h,k_w,x_c,y_c}$ | ||||
3,2,3 | $w_{2,3,3,1}$ | $w_{2,3,3,2}$ | $w_{2,3,3,3}$ | $w_{2,3,3,4}$ | $w_{2,3,3,5}$ |
3,3,1 | $w_{3,1,3,1}$ | $w_{3,1,3,2}$ | $w_{3,1,3,3}$ | $w_{3,1,3,4}$ | $w_{3,1,3,5}$ |
3,3,2 | $w_{3,2,3,1}$ | $w_{3,2,3,2}$ | $w_{3,2,3,3}$ | $w_{3,2,3,4}$ | $w_{3,2,3,5}$ |
3,3,3 | $w_{3,3,3,1}$ | $w_{3,3,3,2}$ | $w_{3,3,3,3}$ | $w_{3,3,3,4}$ | $w_{3,3,3,5}$ |
$y'$
$y_c$ $y_h$, $y_w$ \ |
1 | 2 | 3 | 4 | 5 |
1,1 | $y_{1,1,1}$ | $y_{1,1,2}$ | $y_{1,1,3}$ | $y_{1,1,4}$ | $y_{1,1,5}$ |
1,2 | $y_{1,2,1}$ | $y_{1,2,2}$ | $y_{1,2,3}$ | $y_{1,2,4}$ | $y_{1,2,5}$ |
2,1 | $y_{2,1,1}$ | $y_{2,1,2}$ | $y_{2,1,3}$ | $y_{2,1,4}$ | $y_{2,1,5}$ |
2,2 | $y_{2,2,1}$ | $y_{2,2,2}$ | $y_{2,2,3}$ | $y_{2,2,4}$ | $y_{2,2,5}$ |
이 y' 을 y 으로 변형한다.
코드 구현
입력 $x$ 를 통해 $x'$ 을 만드는 함수, y_shape 이 있는 이유는, $YH$ $YW$ 를 알기 위해서.
def img2col(x, y_shape, kernel_size, stride, padding_size):
# x : N, XH, XW, XC
# y : N, YH, YW, YC
KH, KW = kernel_size
SH, SW = stride
PH, PW = padding_size
N, XH, XW, XC = x.shape
N, YH, YW, YC = y_shape
# N, XH + 2PH, XW + 2PW, XC
padded_x = np.pad(x, [(0, 0), (PH, PH), (PW, PW), (0, 0)], 'constant')
# N, KH, KW, YH, YW, XC
col = np.zeros((N, KH, KW, YH, YW, XC))
for h in range(KH):
h_max = h + SH * YH
for w in range(KW):
w_max = w + SW * YW
col[:, h, w, :, :, :] = padded_x[:, h:h_max:SH, w:w_max:SW, :]
# Transpose : N , YH , YW , XC , KH, KW
# Reshape : N x YH x YW , XC x KH x KW
col = col.transpose((0,3,4,5,1,2)).reshape(N*YH*YW, -1)
return col
주의해야할 점은, 행렬이 1 부터가 아니라, 0 부터 시작하기 때문에 조금 다른점이 존재한다.
def forward(self, inputs):
if inputs.dtype != self.dtype:
warnings.warn("입력과 커널의 데이터 타입이 일치하지 않습니다. input dtype : {}, kernel dtype : {}".format(inputs.dtype, self.weight.dtype))
inputs = inputs.astype(self.dtype)
x = inputs
# ( N x YH x YW , XC x KH x KW )
flat_x = conv_utils.img2col(x, self.output_shape, self.kernel_size, self.strides, self.padding_size)
# weight : KH x KW x XC x YC
#Transpose : XC x KH x KW x YC
#Reshape : ( XC x KH x KW , YC )
flat_w = self.weight.transpose((2,0,1,3)).reshape(-1, self.filters)
flat_b = self.bias.reshape(1, -1)
# Dot : ( N x YH x YW , YC ) + ( 1 x 1 x 1, YC)
flat_y = np.dot(flat_x, flat_w)
if self.use_bias:
flat_y += flat_b
# Reshape : N x YH x YW x YC
y = flat_y.reshape(*self.output_shape)
if self.training:
self.flat_x = conv_utils.average_flat_x(flat_x, y.shape)
self.flat_w = flat_w
return y
여기서 flat_x, flat_w 를 저장하는 이유는 backprop 시에 이용되기 때문이다.
average_flat_x 는 upstream gradient $ \frac{\partial L}{\partial y} $ 가 batch 차원이 없는 행렬이라 $x$ 을 batch 차원기준 평균한것인데, 아직 정확한 방법인지는 분명하지 않다. 사실 구현하기 나름인데, 맨꼭대기 $ \frac{\partial L}{\partial y} $ 의 차원부터 batch를 유지한다고하면 그대로 사용하면 되긴하지만, 훈련시에 layer 가 깊어질수록 + batch size 가 커질수록 메모리에 대한 압박이 심해질 것같은 예상으로 이렇게 구현하게 되었다.
그런데 당연하게도 2차원 행렬로 변환하는 과정에서 데이터의 중복이 생기는데 ( stride 가 kernel size 보다 작다면 ), 아직 어쩔수 없는 부분이라고 생각하고 있다.
Backprop
$ \frac{\partial L}{\partial y} $ : ( $YH$ , $YW$ , $YC$ )
Weight
$$ \begin{matrix}
y_{h_y, w_y, c_y} = \sum_{h_k=1}^{KH}\sum_{w_k=1}^{KW}\sum_{c_x=1}^{XC} x_{s_h(h_y-1)+h_k, s_w(w_y-1)+w_k,c_x} w_{h_k, w_k, c_x, c_y} \\ \\
\frac{\partial y_{h_y, w_y, c_y}}{\partial w_{h_k, w_k, c_x, c_y}} = x_{s_h(h_y-1)+h_k, s_w(w_y-1)+w_k,c_x}
\end{matrix} $$
이때 $y$ 의 $c_y$ 와 $w$ 의 $c_y$ 가 동일하지 않은 경우는 모두 0 이된다. ( forward 참고, 고려안해도됨. )
$$ \frac{\partial y_{h_y, w_y, c_y}}{\partial w} = \frac{\partial y_{h_y, w_y, c_y}}{\partial w_{,,,c_y}} = \begin{bmatrix}
\frac{\partial y_{h_y, w_y, c_y}}{\partial w_{1,1,c_x,c_y}} & ... & \frac{\partial y_{h_y, w_y, c_y}}{\partial w_{1,KW,c_x,c_y}} \\
... & \frac{\partial y_{h_y, w_y, c_y}}{\partial w_{h_k,w_k,c_x,c_y}} & ... \\
\frac{\partial y_{h_y, w_y, c_y}}{\partial w_{KH,1,c_x,c_y}} & ... & \frac{\partial y_{h_y, w_y, c_y}}{\partial w_{KH,KW,c_x,c_y}} \\
\end{bmatrix}, (c_x = \text{1 to XC}) \\ = \begin{bmatrix}
x_{s_h(h_y-1)+1, s_w(w_y-1)+1, c_x} & ... & x_{s_h(h_y-1)+1, s_w(w_y-1)+KW, c_x} \\
... & x_{s_h(h_y-1)+h_k, s_w(w_y-1)+w_k, c_x} & ... \\
x_{s_h(h_y-1)+KH, s_w(w_y-1)+1, c_x} & ... & x_{s_h(h_y-1)+KH, s_w(w_y-1)+KW, c_x} \\
\end{bmatrix}, (c_x = \text{1 to XC}) $$
여기서 식을 자세히 들여다보면 위 $ \frac{\partial y_{h_y, w_y, c_y}}{\partial w} $ 은 $y_{h_y, w_y, c_y}$ 를 구하기 위해 $w$ 가 곱했던 $x$ 들을 의미한다. 그리고 $c_y$ 변수에 영향을 받지 않기때문에, $w$ 의 $c_y$ 차원에 대해서는 모두 동일한 값을 가지고, $ \frac{\partial L}{\partial y_{h_y, w_y, c_y}} $ 에 영향을 받는다.
이 $ \frac{\partial y_{h_y, w_y, c_y}}{\partial w}$ 를 1 차원으로 늘리게 되면, 위의 $x'$ 의 row 가 되고, $c_y$ 에 상관 없이 동일한 값을 가지기 때문에, $h_y$ , $w_y$ 에 관해서만 전부 펼치면 $x'$ 와 동일한 행렬이 만들어지고 이를 이용할 수 있다.
$x'$ 의 row 들은 $ \frac{\partial y_{h_y,w_y,c_y}}{\partial w_{,,,c_y}} $ 인데, col 들은 $ \frac{\partial y_{,,c_y}}{\partial w_{h_k,w_k,c_x,c_y}} $ 으로 볼 수 있다. 그래서 위에서 구했던 $x'^T$ 와 $ \frac{\partial L}{\partial y} $ 를 dot product 하면 우리가 원하는 $ \frac{\partial L}{\partial w} $ 을 구할 수 있다.
변수들의 연관관계를 이해하기 쉽게 위와 동일한 예시를 들어보자.
예시 ) x : 5x5x3, w : 3x3x3x5, y : 2x2x5 일 때 ( bias, batch 는 무시, stride 는 2 )
$ \frac{\partial L}{\partial y} $ : ($YH$, $YW$, $YC$ ) = ( 2, 2, 5 ) -> ( 2x2 , 5 )
$c_y$ $h_y$, $w_y$ \\ |
1 | 2 | 3 | 4 | 5 |
1,1 | $\frac{\partial L}{\partial y_{1,1,1}}$ | $\frac{\partial L}{\partial y_{1,1,2}}$ | $\frac{\partial L}{\partial y_{1,1,3}}$ | $\frac{\partial L}{\partial y_{1,1,4}}$ | $\frac{\partial L}{\partial y_{1,1,5}}$ |
1,2 | $\frac{\partial L}{\partial y_{1,2,1}}$ | $\frac{\partial L}{\partial y_{1,2,2}}$ | $\frac{\partial L}{\partial y_{1,2,3}}$ | $\frac{\partial L}{\partial y_{1,2,4}}$ | $\frac{\partial L}{\partial y_{1,2,5}}$ |
2,1 | $\frac{\partial L}{\partial y_{2,1,1}}$ | $\frac{\partial L}{\partial y_{2,1,2}}$ | $\frac{\partial L}{\partial y_{2,1,3}}$ | $\frac{\partial L}{\partial y_{2,1,4}}$ | $\frac{\partial L}{\partial y_{2,1,5}}$ |
2,2 | $\frac{\partial L}{\partial y_{2,2,1}}$ | $\frac{\partial L}{\partial y_{2,2,2}}$ | $\frac{\partial L}{\partial y_{2,2,3}}$ | $\frac{\partial L}{\partial y_{2,2,4}}$ | $\frac{\partial L}{\partial y_{2,2,5}}$ |
$ \frac{\partial y}{\partial w} $ : ( $YH$, $YW$, $XC$, $KH$, $KH$ ) = ( 2, 2, 3, 3, 3 ) -> ( 2x2, 3x3x3 )
$c_x$, $h_k$, $w_k$ $h_y$,$w_y$ \\ |
1,1,1 | 1,1,2 | 1,1,3 | 1,2,1 | ... | 3,2,3 | 3,3,1 | 3,3,2 | 3,3,3 |
1,1 | $\frac{\partial y_{1,1,-}}{\partial w_{1,1,1,-}}$ | $\frac{\partial y_{1,1,-}}{\partial w_{1,2,1,-}}$ | $\frac{\partial y_{1,1,-}}{\partial w_{1,3,1,-}}$ | $\frac{\partial y_{1,1,-}}{\partial w_{2,1,1,-}}$ | $x_{s_h(h_y-1)+h_k, s_w(w_y-1)+w_k, c_x}$ | $\frac{\partial y_{1,1,-}}{\partial w_{2,3,3,-}}$ | $\frac{\partial y_{1,1,-}}{\partial w_{3,1,3,-}}$ | $\frac{\partial y_{1,1,-}}{\partial w_{3,2,3,-}}$ | $\frac{\partial y_{1,1,-}}{\partial w_{3,3,3,-}}$ |
1,2 | $\frac{\partial y_{1,2,-}}{\partial w_{1,1,1,-}}$ | $\frac{\partial y_{1,2,-}}{\partial w_{1,2,1,-}}$ | $\frac{\partial y_{1,2,-}}{\partial w_{1,3,1,-}}$ | $\frac{\partial y_{1,2,-}}{\partial w_{2,1,1,-}}$ | ... | $\frac{\partial y_{1,2,-}}{\partial w_{2,3,3,-}}$ | $\frac{\partial y_{1,2,-}}{\partial w_{3,1,3,-}}$ | $\frac{\partial y_{1,2,-}}{\partial w_{3,2,3,-}}$ | $\frac{\partial y_{1,2,-}}{\partial w_{3,3,3,-}}$ |
2,1 | $\frac{\partial y_{2,1,-}}{\partial w_{1,1,1,-}}$ | $\frac{\partial y_{2,1,-}}{\partial w_{1,2,1,-}}$ | $\frac{\partial y_{2,1,-}}{\partial w_{1,3,1,-}}$ | $\frac{\partial y_{2,1,-}}{\partial w_{2,1,1,-}}$ | ... | $\frac{\partial y_{2,1,-}}{\partial w_{2,3,3,-}}$ | $\frac{\partial y_{2,1,-}}{\partial w_{3,1,3,-}}$ | $\frac{\partial y_{2,1,-}}{\partial w_{3,2,3,-}}$ | $\frac{\partial y_{2,1,-}}{\partial w_{3,3,3,-}}$ |
2,2 | $\frac{\partial y_{2,2,-}}{\partial w_{1,1,1,-}}$ | $\frac{\partial y_{2,2,-}}{\partial w_{1,2,1,-}}$ | $\frac{\partial y_{2,2,-}}{\partial w_{1,3,1,-}}$ | $\frac{\partial y_{2,2,-}}{\partial w_{2,1,1,-}}$ | ... | $\frac{\partial y_{2,2,-}}{\partial w_{2,3,3,-}}$ | $\frac{\partial y_{2,2,-}}{\partial w_{3,1,3,-}}$ | $\frac{\partial y_{2,2,-}}{\partial w_{3,2,3,-}}$ | $\frac{\partial y_{2,2,-}}{\partial w_{3,3,3,-}}$ |
$ \frac{\partial L}{\partial w} = \frac{\partial y}{\partial w}^T \cdot \frac{\partial L}{\partial y} $ : ( $KH$, $KW$, $XC$, $YC$ ) = ( 3, 3, 3, 5 ) -> ( 3x3x3, 5 )
$c_y$ $h_k$, $w_k$, $c_x$ \\ |
1 | 2 | 3 | 4 | 5 |
1,1,1 | $\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,w_y,1}}{\partial w_{1,1,1,1}}\frac{\partial L}{\partial y_{h_y,w_y,1}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,w_y,2}}{\partial w_{1,1,1,2}}\frac{\partial L}{\partial y_{h_y,w_y,2}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,w_y,3}}{\partial w_{1,1,1,3}}\frac{\partial L}{\partial y_{h_y,w_y,3}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,w_y,4}}{\partial w_{1,1,1,4}}\frac{\partial L}{\partial y_{h_y,w_y,4}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,w_y,5}}{\partial w_{1,1,1,5}}\frac{\partial L}{\partial y_{h_y,w_y,5}}$ |
1,2,1 | $\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,1}}{\partial w_{1,2,1,1}}\frac{\partial L}{\partial y_{h_y,h_w,1}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,2}}{\partial w_{1,2,1,2}}\frac{\partial L}{\partial y_{h_y,h_w,2}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,3}}{\partial w_{1,2,1,3}}\frac{\partial L}{\partial y_{h_y,h_w,3}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,4}}{\partial w_{1,2,1,4}}\frac{\partial L}{\partial y_{h_y,h_w,4}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,5}}{\partial w_{1,2,1,5}}\frac{\partial L}{\partial y_{h_y,h_w,5}}$ |
1,3,1 | $\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,1}}{\partial w_{1,3,1,1}}\frac{\partial L}{\partial y_{h_y,h_w,1}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,2}}{\partial w_{1,3,1,2}}\frac{\partial L}{\partial y_{h_y,h_w,2}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,3}}{\partial w_{1,3,1,3}}\frac{\partial L}{\partial y_{h_y,h_w,3}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,4}}{\partial w_{1,3,1,4}}\frac{\partial L}{\partial y_{h_y,h_w,4}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,5}}{\partial w_{1,3,1,5}}\frac{\partial L}{\partial y_{h_y,h_w,5}}$ |
2,1,1 | $\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,1}}{\partial w_{2,1,1,1}}\frac{\partial L}{\partial y_{h_y,h_w,1}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,2}}{\partial w_{2,1,1,2}}\frac{\partial L}{\partial y_{h_y,h_w,2}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,3}}{\partial w_{2,1,1,3}}\frac{\partial L}{\partial y_{h_y,h_w,3}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,4}}{\partial w_{2,1,1,4}}\frac{\partial L}{\partial y_{h_y,h_w,4}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,1}}{\partial w_{2,1,1,1}}\frac{\partial L}{\partial y_{h_y,h_w,1}}$ |
... | ... | ... | $\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,w_y,c_y}}{\partial w_{h_k,w_k,c_x,c_y}}\frac{\partial L}{\partial y_{h_y,w_y,c_y}}$ |
... | ... |
2,3,3 | $\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,1}}{\partial w_{2,3,3,1}}\frac{\partial L}{\partial y_{h_y,h_w,1}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,2}}{\partial w_{2,3,3,2}}\frac{\partial L}{\partial y_{h_y,h_w,2}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,3}}{\partial w_{2,3,3,3}}\frac{\partial L}{\partial y_{h_y,h_w,3}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,4}}{\partial w_{2,3,3,4}}\frac{\partial L}{\partial y_{h_y,h_w,4}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,5}}{\partial w_{2,3,3,5}}\frac{\partial L}{\partial y_{h_y,h_w,5}}$ |
3,1,3 | $\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,1}}{\partial w_{3,1,3,1}}\frac{\partial L}{\partial y_{h_y,h_w,1}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,2}}{\partial w_{3,1,3,2}}\frac{\partial L}{\partial y_{h_y,h_w,2}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,3}}{\partial w_{3,1,3,3}}\frac{\partial L}{\partial y_{h_y,h_w,3}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,4}}{\partial w_{3,1,3,4}}\frac{\partial L}{\partial y_{h_y,h_w,4}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,5}}{\partial w_{3,1,3,5}}\frac{\partial L}{\partial y_{h_y,h_w,5}}$ |
3,2,3 | $\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,1}}{\partial w_{3,2,3,1}}\frac{\partial L}{\partial y_{h_y,h_w,1}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,2}}{\partial w_{3,2,3,2}}\frac{\partial L}{\partial y_{h_y,h_w,2}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,3}}{\partial w_{3,2,3,3}}\frac{\partial L}{\partial y_{h_y,h_w,3}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,4}}{\partial w_{3,2,3,4}}\frac{\partial L}{\partial y_{h_y,h_w,4}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,5}}{\partial w_{3,2,3,5}}\frac{\partial L}{\partial y_{h_y,h_w,5}}$ |
3,3,3 | $\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,1}}{\partial w_{3,3,3,1}}\frac{\partial L}{\partial y_{h_y,h_w,1}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,2}}{\partial w_{3,3,3,2}}\frac{\partial L}{\partial y_{h_y,h_w,2}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,3}}{\partial w_{3,3,3,3}}\frac{\partial L}{\partial y_{h_y,h_w,3}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,4}}{\partial w_{3,3,3,4}}\frac{\partial L}{\partial y_{h_y,h_w,4}}$ |
$\sum_{h_y=1}^{YH}\sum_{w_y=1}^{YW} $ $\frac{\partial y_{h_y,h_w,5}}{\partial w_{3,3,3,5}}\frac{\partial L}{\partial y_{h_y,h_w,5}}$ |
아, 다 작성하고나서 $y$ 첨자가 잘못작성되어있는걸 확인했는데, 귀찮아서 첫번째 row 만 바꿨다,, $y_{h_y, w_y, c_y}$ 가 맞는 첨자이다.
이렇게 두 행렬의 곱을 수행하면 위 행열을 얻고, 이를 reshape 해주면 $\frac{\partial L}{\partial w}$ 를 구할 수 있다.
코드구현
def backprop(self, dLdy, optimizer):
# dLdy : YH x YW x YC
# dydw : ( YH x YW x YC ) x ( KH x KW x XC x YC )
# dLdw : KH x KW x XC x YC
YH, YW, YC = dLdy.shape
KH, KW, XC, YC = self.weight.shape
# Reshape : ( YH x YW , YC )
flat_dLdy = dLdy.reshape(-1, YC)
# flat_x.T : ( XC x KH x KW , YH x YW )
# flat_dLdy : ( YH x YW , YC )
# Dot : ( XC x KH x KW , YC )
# Reshape : XC x KH x KW x YC
# Transpose : KH x KW x XC x YC
dLdw = np.dot(self.flat_x.T, flat_dLdy).reshape(XC, KH, KW, YC).transpose((1, 2, 0, 3))
kernel_regularize_term = self.kernel_regularizer(self.weight) if self.kernel_regularizer is not None else 0
kernel_delta = dLdw + kernel_regularize_term
self.weight = self.weight - optimizer.learning_rate * kernel_delta
if self.use_bias:
bias_regularize_term = self.bias_regularizer(self.bias) if self.bias_regularizer is not None else 0
bias_delta = dLdy + bias_regularize_term
self.bias = self.bias - optimizer.learning_rate * bias_delta
# flat_dLdy : ( YH x YW , YC )
# flat_w.T : ( YC , XC x KH x KW )
# Dot : ( YH x YW , XC x KH x KW )
flat_dLdx = np.dot(flat_dLdy ,self.flat_w.T)
dLdx = conv_utils.col2img(flat_dLdx, self.input_shape, self.output_shape, self.kernel_size, self.strides, self.padding_size)
return dLdx
'머신러닝 > CustomFramework' 카테고리의 다른 글
Residual Connection (0) | 2022.04.04 |
---|---|
Batch Normalization (0) | 2022.04.03 |
Dropout (0) | 2022.04.03 |
L1 L2 Regularizer (0) | 2022.04.03 |
Dense (Fully Connect) Layer (0) | 2022.03.21 |