C++로 스크래치에서 backprop을 설치하고 mnist를 배워봤습니다.

교과서에서 신경망의 백프로파게이션(오차반전파법)에 대한 설명을 읽고 형식을 보면 왠지 알겠지만 시간이 지나면 잊어버린다.
따라서 공식을 정리하고 C++로 스크래치에서 설치하고 보존합니다.
백 프로파일링의 내보내기와 설치를 한 번만 하면 머릿속에 남았으면 좋겠습니다.
무엇이든 이런 리듬으로 천천히 할 수는 없지만 기본적인 부분은 마침내 되었다.

방정식 주석


벡터는 모두 세로 벡터다.공식과 의심 코드가 섞여 있지만 마음의 눈으로 읽어야 한다.
대체적으로 심층 학습(기계학습 전공 시리즈)의 기법을 모방하지만 설치 시 혼란을 피하기 위해 0층부터 다소 변경된다.

$L$: 입력 레이어를 제외한 모든 레이어 수입니다.각 레이어는 $l$($0\le l${\bf x}$: 전체 네트워크를 입력합니다.편의를 위해 ${\bfz}^{(-1)}={\bfx}$라고 생각합니다.
${\bfy}$: 전체 네트워크에서 출력됩니다.
${\bfd}$: 대상 출력(정답 탭).
${\bfW}^(l)}$: L층의 권중 행렬입니다.
${\bfu}^(l)}$: ${\bfx}^(i)}$에 권중 행렬 ${\bfW}^(l)}$를 입력한 다음 녀석입니다.
$f^ (l)}$: $l$층의 활성화 함수입니다. ${\bfu}^{(l)}$를 넣으면 ${\bfz}^{(l)}$가 나오는 느낌이 듭니다.
${\bfz}^(l)}$: ${\bfu}^(i)}$함수 $f^(l)}$다음에 있는 것을 활성화합니다. ${\bfz}^{(L-1)}$는 전체 네트워크의 출력이기 때문에 ${\bfy}$와 등가합니다.
$L$: 손실 함수입니다.근사한 범위 내에서 제곱 오차입니까 아니면 교차 엔트로피입니까?
벡터 및 행렬의 크기 (차원):
${\bfu}^(l)}$와 ${\bfz}^(l)}$의 크기가 같습니다.
${\bf W} ^ (l)} $은 ${\rm len} ({\bf u} ^ (l) $행 $({\rm len} ({\bf z} ^ (l-1)}) +1) $열입니다.
${\bfx}$와 ${\bfy}$의 크기는 선택할 수 없지만 $0\le

정방향 전파


$0\le l{\bf u}^{(l)}={\bf W}^{(l)}\cdot[{\bf z}^{(l-1)};1] (여기, $\cdot$는 행렬적, $[{\bfz}^{(l-1)};1]$는 벡터의 끝에 편치 항목에 대응하는 1의 분위기가 붙어 있습니다)
{\bf z}^{(l)}= f({\bf u}^{(l)})
최종 출력
{\bf y}= {\bf z}^{(L-1)}
$L$cross entropy loss function 시 손실
L({\bf y}, {\bf d})=\sum_i {d_i \log(y_i)}

역방향 오차 전파


목적: $\frac{\partial L}{\partial w^{(l)}_모든 $i$, $j$, $l$에 대해 {ij}$를 계산합니다.이렇게 하면 라벨이 있는 학습 데이터 (${\bfx}$, ${\bfy}$) 에서 가장 가파른 하락 (또는 더 스마트한 비선형 최적화 알고리즘) 으로 ${\bfW}^ (l)}$를 학습할 수 있다.
중요한 등장인물: ${\bf\delta}^{(l)}$는 다음과 같습니다.(${\bf\delta}^(l)}$는 벡터이고, $\delta^(l)}_i$는 요소)
\delta^{(l)}_i=\frac{\partial L}{\partial u^{(l)}_i}
모든 ${\bf\delta}^(l)}$를 알면 $\frac{\partial L}{\partial w^(l)}_{ij}}$는 아래와 같이 쉽게 구할 수 있습니다.
\frac{\partial L}{\partial w^{(l)}_{ij}}=\frac{\partial L}{\partial u^{(l)}_i}\cdot\frac{\partial u^{(l)}_i}{\partial w^{(l)}_{ij}}
=\delta^{(l)}_i\cdot [z^{(l-1)}_j; 1] \cdots (★)
여기 있다
u^{(l)}_i=\sum_j w^{(l)}_{ij} \cdot [z^{(l-1)}_j; 1]
위하다
\frac{\partial u^{(l)}_i}{\partial w^{(l)}_{ij}}=[z^{(l-1)}_j; 1]
), 템플릿 이름은 다른 형식을 사용합니다.
${\bf\delta}^{(l)}$를 구하려면 먼저 출력층의 ${\bf\delta}$(즉 ${\bf\delta}^{(L-1)}$)를 구하고 입력층 옆으로 거슬러 올라갑니다.
출력층이 softmax이고 오차 함수가crossentropy일 때 ${\bf\delta}^{(L-1)}$아래와 같습니다 (약간을 내보냅니다. 미분만 노력하면 구해야 합니다)
\delta^{(L-1)}_i=y_i - d_i \cdots (★★)
$0\l\le L-2$범위 내의 $l$에 대해
\delta^{(l)}_i=\frac{\partial L}{\partial u^{(l)}_i}
=\sum_k\frac{\partial L}{\partial u^{(l+1)}_k} \cdot \frac{\partial u^{(l+1)}_k}{\partial u^{(l)}_i}
=\sum_k{\delta^{(l+1)}_k \cdot (w^{(l+1)}_{kj}f'(u^{(l)}_j))} \cdots (★★★)
여기 있다
u^{(l+1)}_k=\sum_j{w^{(l+1)}_{kj}z^{(l)}_j}=\sum_j{w^{(l+1)}_{kj}f(u^{(l)}_j})
그래서
\frac{\partial u^{(l+1)}_k}{\partial u^{(l)}_i}=w^{(l+1)}_{kj}f'(u^{(l)}_j)
), 템플릿 이름은 다른 형식을 사용합니다.
$f$는 ReLu,sigmoid,tanh의 이미 알고 있는 함수이기 때문에 $f'$를 해석하여 구합니다.
따라서 우선 입력층에서 출력층준으로 전파하여 ${\bfu}^{(l)}$와 ${\bfy}$를 구한 후
(★★)부터 (★★★★) 귀속적으로 (★★★) 모든 ${\bf\delta}^{(l)}$를 구하고, 그것(★)으로 모든 $\frac {\partial L}{\partial w^{(l)}_{ij}}$.

실시


C++14에서 위 공식에 따라 구현됩니다.실제 응용을 고려하지 않았기 때문에 표준 라이브러리만 사용하고 적과 연산은 모두 for순환이다.알고리즘(다시 읽을 때의 자신)은 추적하기 쉽다고 여겨지지만 소량마다tensor 연산을 하는 작법이 없기 때문에 느리다.
함수를 활성화하여 ReLu와sigmoid(약간 궁금한) swish를 구현합니다.
출력층은 당분간 softmax만 있습니다.
fully connected layer를 간단하게 불러오는 경우에만 적용됩니다.
이렇게 하면 네트워크 정의를 쓸 수 있다.
  Network<double> net;
  net.addLayer(28*28, 300, Layer<double>::ActivationType::RELU);
  net.addLayer(300, 10, Layer<double>::ActivationType::SOFTMAX);
그리고 사실은gradient checking 같은 걸 해야 하는데 안 했어요.

실험


모처럼의 기회라서 공부를 해봤습니다mnist.
학습 데이터는 60000 이미지, 테스트 데이터는 10000 이미지입니다.
입력 이미지는 각 픽셀 8bit 그레이스케일의 28*28이기 때문에 각 픽셀을 [0,1]의 더블로 정규화한 후 784차원 벡터 1개를 신경망의 입력으로 하고 0~9의 10값을 10차원의softmax 출력층으로 출력한다.
손실 함수는crossentropy입니다.
300비트 숨겨진 레이어 1개, 활성화 함수는 ReLu입니다.(입력 계층 수가 1 계층이라는 표현의 3 계층 네트워크)
최적화는 단순한 SGD입니다.소량 100.정규화 따위는 아무것도 없다.learningrate0.2부터 학습 데이터 손실이 이전의 epoch보다 증가하면learningrate를 반으로 줄인다.
50epoch를 돌린 후,testset error rate는 1.9% 정도입니다.

mnist 페이지에 따르면 3-layer NN, 500+300HU,softmax,cross entropy,weight decay(숨겨진 층 2개이기 때문에 입력층, 출력층을 계산하면 4층 네트워크)에서 error rate가 1.53% 정도이기 때문에 합리적인 정밀도로 보인다.
숨겨진 층을 늘려 보았습니다.
300+300 2 hidden layers:

숨겨진 층 2층에서 중도testloss가 중도부터 증가하기 때문에overfitting이 발생한 것을 알 수 있습니다.테스트 error rate는 좋은 곳이라도 2.4%-2.5% 정도입니다.
300+300+300 3 hidden layers:

숨겨진 층 3층(그림에는 나타나지 않았지만)에서 경사가 사라져 학습이 전혀 진전되지 않았다.

좋은 웹페이지 즐겨찾기