티스토리 뷰

2020/10/26 - [Study/인공지능] - Xavier/He 초기값 ( 인공지능 기초 # 18 )

 

초기값은 은닉층에서 데이터의 분포가 너무 가운데로 쏠리거나 양 사이드에 치우치지 않게 함으로써 학습이 순조롭게 되도록 하는게 목표였습니다.

 

오늘 공부할 배치 노멀레이션은 초기값을 통해서 데이터의 분포를 컨트롤하는게 아닌, 아파인층과 활성화 층 사이에 데이터의 분포를 컨트롤해주는 층을 끼워 넣습니다. 

아파인과 렐루 사이에 배치 정규화를 추가함

머신이 데이터로부터 가장 효율적인 평균과 표준편차를 스스로 학습을 해 나가는 것입니다.

 

데이터가 n개가 주어져있고, 

 

평균을 0으로 만드려면 평균을구해서 빼준다. u도 역시 배터이다. 

 

첫번째 열의 평균을 구해서 첫번쨰 열에 일일이 다 뺴주고 첫번째 열의 표준편차를 구해서 첫번째 열에 일일이 다 나눠주는 작업 ( 평균을 0, 표준편차를 1로 만드는 작업 )

이렇게 나온 Xn의 각 행에 갑마를 곱해준다.[ 표준편차가 곱해줌으로써 갑마의 값으로 바뀜 ] 그리고 Xn의 각 행에 베타를 더해준다[ 평균이 더해줌으로써 베타의값으로 바뀜 ] .

 

결과적으로는 표준편차를 갑마 벡터로 바꾸고, 평균을 베타 벡터로 바뀌게 되는것.

 

이는 사람이 설정하지않고, 머신이 가장효율적인 갑마와 베타를 학습해 나갑니다.

 

초기 갑마와 베타를 사람이 지정해주면, 학습해가면서 머신이 스스로 찾아간다. 

 

    def __forward(self, x, train_flg):
        if self.running_mean is None:
            N, D = x.shape
            self.running_mean = np.zeros(D)
            self.running_var = np.zeros(D)
                        
        if train_flg:#훈련할때
            mu = x.mean(axis=0) #평균
            xc = x - mu #평균빼준거
            var = np.mean(xc**2, axis=0) #표준편차
            std = np.sqrt(var + 10e-7) #나누기전 0방지
            xn = xc / std#표준편차 나눠준거( 평균 0 표준편차 1 )
            
            self.batch_size = x.shape[0]
            self.xc = xc
            self.xn = xn
            self.std = std # 결국은 running_mean은 계속된 학습을 통해 이상적인 초기값을 찾아가게됨
            self.running_mean = self.momentum * self.running_mean + (1-self.momentum) * mu#모멘텀으로 내분하라 [running_mean은 처음 원점이고 mu는 방금 구한 평균벡터 이를 내분하라 (과거 또는 미래에 중점을 둬라)]
            self.running_var = self.momentum * self.running_var + (1-self.momentum) * var#위와 같다.           
        else:#테스트할때 테스트할때는 평균과 표준편차를 최종적으로 구해진걸로 사용하라는 뜻 
            xc = x - self.running_mean
            xn = xc / ((np.sqrt(self.running_var + 10e-7)))
            
        out = self.gamma * xn + self.beta #마지막, 표준편차를 곱하고 평균을 더한다 ( 갑마 곱, 베타 덧 )
        return out

 

Batch Normalization의 역전파

Batch Normalization의 역전파

 

역전파의 목적은 그레디언트를 구하는 것입니다. 

 

그레디언트를 구해서 옵티마이저에게 넘기면, 옵티마이저는 그걸 이용해 파라미터를 업데이트합니다.

 

배치 노멀레이션층에서 구해야 할 그레디언트는 총 3개입니다. 갑마, 베타, 아래층으로 흘려보낼 그레디언트

 

    def __backward(self, dout): #dout , 밖에서 미분이 흘러들어옴
        dbeta = dout.sum(axis=0)#repeat노드가 숨어있어 각 열을 다 더해서 베타를 만들어줌
        dgamma = np.sum(self.xn * dout, axis=0)#반대편에 들어오는거랑 곱하기 (아담하르프러덕트) 하고 학 역을 다 더해서 갑마를 만들어줌
        dxn = self.gamma * dout #반대편 갑마랑 곱하기
        dxc = dxn / self.std #흘러들어온 미분 (dxn)에다가 반대편에 있는 1/시그마 해준다. 
        dstd = -np.sum((dxn * self.xc) / (self.std * self.std), axis=0)#
        dvar = 0.5 * dstd / self.std
        dxc += (2.0 / self.batch_size) * self.xc * dvar
        dmu = np.sum(dxc, axis=0)
        dx = dxc - dmu / self.batch_size
        
        self.dgamma = dgamma
        self.dbeta = dbeta
        
        return dx

역전파만 나오면 머리가 어지러워지네요....

 

파란색이 배치 노멀레제이션 들어간거, 주황색이 안들어간거

 

Batch Normalization의 장점

 

1. 학습속도 개선

2. 초기값에 덜 의존한다.

3. overfitting 억제

 

 

댓글
최근에 올라온 글
최근에 달린 댓글
250x250