chainer의 connection을 괴롭히고 새로운 층을 만든다 (2)

환경



GPU GTX1070
우분투 14.04
chainer 1.14.0


소개



chainer에서 최신 모델을 구현할 때는 links/connection이나 functions/connection을 괴롭힐 필요가 있다. 그래서 가장 단순한 linear.py를 만나 새로운 레이어를 만들어 보자.

전회는 chainer/functions/connection/linear.py 의 forward 함수를 만져 순전파를 개량했다.
ぃ tp // 코 m / 설마 46 / ms / 1 A 5d6cbd49279 Ah f734

이번에는 backward 함수를 만지면서 오차 역전파를 개량한다.

오차 역전파 계산



오차 역전파의 연산은 이하의 도면과 같이 된다.

gx를 구하는데, W의 in_size/n측을 n배하면 계산이 편해진다. 또한 gW를 구하는 연산을 도식화하면 다음과 같다.

이번에는 gx와 x와의 행렬 곱으로 출력된 것을 in_size축측에 압축·합치게 할 필요가 있다. 이때 cupy.sum()을 사용한다.

linear.py 변경


chainer/functions/connection/linear.py 내의 backward 함수를 다음과 같이 수정한다.
    def backward(self, inputs, grad_outputs):

        x = _as_mat(inputs[0])
        W = inputs[1]
        gy = grad_outputs[0]

        W_tile = cupy.tile(W, (1, common_num)).astype(W.dtype, copy=False)

        gx = gy.dot(W_tile).astype(gy.dtype, copy=False)
        gW_wide = gy.T.dot(x).astype(W.dtype, copy=False)
        gW_cube = gW_wide.reshape(len(gW_wide), common_num, -1).astype(W.dtype, copy=False)
        gW = gW_cube.sum(axis=1).astype(W.dtype, copy=False)

        if len(inputs) == 3:
            gb = gy.sum(0)
            return gx, gW, gb
        else:
            return gx, gW

행렬 곱의 결과 (gW_wide)에 대해 먼저 차원을 늘립니다 (gW_cube). 다음으로 그 차원에 대해 더해(sum 함수) 있다.

수정 모델 학습 결과



수정 모델을 실행하여 accuracy와 처리 속도를 원래 모델과 비교합니다.
python train_mnist3.py -g=0 -e=50
GPU: 0
# unit: 1000
# Minibatch-size: 100
# epoch: 50

epoch       main/loss   validation/main/loss  main/accuracy  validation/main/accuracy
1           0.204286    0.10436               0.936834       0.9683                    
2           0.0795502   0.0783082             0.975266       0.974
・・・
49          0.00331749  0.124306              0.999166       0.9843                    
50          0.00580243  0.136195              0.998583       0.9836    

50회의 학습으로 1분 30초, accuracy는 0.968에서 0.984로 상승했다. 원래 모델이라고 학습 시간 1분 54초에 accuracy는 0.971에서 0.985이다. 따라서 예상대로 학습 시간이 줄어들어 accuracy가 약간 감소했습니다.

좋은 웹페이지 즐겨찾기