본문 바로가기
AI Naver boost camp/[Week 02] ML LifeCycle

2-layer MLP (Multi Layer Perceptron)

by AI-BT 2024. 8. 16.
728x90
반응형
 grad_y_pred = 2.0 * (y_pred - y)
grad_w2 = h_0.T.dot(grad_y_pred)
grad_h = grad_y_pred.dot(w2.T)
grad_w1 = x.T.dot(grad_h * h * (1 - h))
w1 -= learning_rate * grad_w1
w2 -= learning_rate * grad_w2

1. 정의

2-layer MLP (Multi-Layer Perceptron)은 두 개의 주요 층을 가진 신경망 모델이다.

여기서 "2-layer"는 일반적으로 입력층과 출력층 사이에 2개의 은닉층이 있는 구조를 의미합니다.

이 신경망은 비선형 변환을 통해 입력 데이터를 처리하고, 복잡한 패턴을 학습할 수 있습니다.


2. 2-layer MLP의 구성

  1. 입력층 (Input Layer):
    • 입력층은 데이터의 특성(feature)을 신경망에 전달합니다.
    • 입력층의 뉴런 수는 데이터의 차원과 같으며, 데이터의 각 특성(feature)을 나타냅니다.
  2. 은닉층 (Hidden Layers):
    • 첫 번째 은닉층: 입력층과 두 번째 은닉층(또는 출력층) 사이에 위치합니다. 이 층에서는 비선형 변환을 적용하여 입력 데이터의 복잡한 패턴을 학습합니다. 각 뉴런은 활성화 함수(예: ReLU, 시그모이드, tanh 등)를 통해 출력값을 생성합니다.
    • 두 번째 은닉층: 첫 번째 은닉층과 출력층 사이에 위치합니다. 이 층에서도 비선형 변환이 이루어지며, 복잡한 패턴을 학습하여 최종 출력을 결정합니다.
  3. 출력층 (Output Layer):
    • 출력층은 모델의 최종 결과를 생성합니다. 
    • 출력층의 활성화 함수는 문제에 따라 다릅니다. 예를 들어, 다중 클래스 분류 문제에서는 소프트맥스(softmax) 함수를 사용하고, 이진 분류 문제에서는 시그모이드(sigmoid) 함수를 사용할 수 있습니다.

순방향 전파 (Forward Propagation)

  1. 입력 데이터가 입력층으로 들어옵니다.
  2. 입력층에서 첫 번째 은닉층으로 데이터가 전달됩니다.
    • 데이터는 가중치와 편향을 곱한 후, 활성화 함수를 통해 변환됩니다.
  3. 첫 번째 은닉층의 출력이 두 번째 은닉층으로 전달됩니다.
    • 이 과정도 같은 방식으로 진행됩니다.
  4. 두 번째 은닉층의 출력이 출력층으로 전달됩니다.
    • 출력층에서 최종 예측값이 계산됩니다.

역전파 (Backpropagation)

  1. 손실 함수 (Loss Function) 계산: 모델의 예측값과 실제 값 간의 차이를 계산하여 손실을 측정합니다.
  2. 오차의 그래디언트 계산: 손실 함수에 대한 각 가중치의 그래디언트를 계산합니다.
  3. 가중치 업데이트: 계산된 그래디언트를 사용하여 가중치를 업데이트하여 모델을 개선합니다.

3. 수식 및 코드 이해

1. 모델 정의

import numpy as np
from numpy.random import randn

n, d, h, c = 64, 1000, 100, 10
x, y = randn(n, d), randn(n, c)
w1, w2 = randn(d, h), randn(h, c)
learning_rate = 1e-4

 

n : 데이터의 수

d: 입력차원

h: 히든차원

c : 클래스 수

 

x: (64, 1000) 64개의 데이터와 1000개 열(피쳐)

y: (64,10) 64개의 데이터 샘플이 각각의 10개의 클래스 또는 출력값을 가진 상태

w1, w2 정의

 


2. 순전파 코드

for t in range(1000):
    # 순전파 계산
    y_0 = x.dot(w1)  # y = xw + b
    h_0 = 1 / (1 + np.exp(-y_0))  # sigmoid
    y_pred = h_0.dot(w2)  # 마지막 결과값

 

 

1. y_0 = x.dot(w1) 편향 b 는 생략

 

2. 시그모이드 함수 작성 
h_0 = 1 / (1 + np.exp(-y_0)

\begin{flalign*}
   \sigma(z) = \frac{1}{1 + e^{-z}} &&
\end{flalign*} 

 

3. 예측값 출력
y_pred = h_0.dot(w2)

 


3. Loss 코드

    # loss
    loss = np.square(y_pred - y).sum()  # MSE 평균제곱오차
    print(t, loss)

4. 역전파 (BackPropagation) 코드

 

 

최적의 기울기 (업데이트 뱡향 및 크기)를 구하는 것이 gradient 인데, 

기울기를 구하기 위해서 뒤에서 부터 앞까지 미분을 해서 기울기를 업데이트 한다.

Chain rlue(Upsteam * Local)  를 이용해서 미분 한다.

 

grad_y_pred = 2.0 * (y_pred - y)
grad_w2 = h_0.T.dot(grad_y_pred)
grad_h = grad_y_pred.dot(w2.T)
grad_w1 = x.T.dot(grad_h * h * (1 - h))
w1 -= learning_rate * grad_w1
w2 -= learning_rate * grad_w2

 

1. grad_y_pred = 2.0 * (y_pred - y)

\begin{flalign*}
MSE(L) = \frac{1}{n} \sum_{i=1}^{n} (y_{\text{pred},i} - y_i)^2 &&
\end{flalign*} 

위의 식을 미분

\begin{flalign*}
\frac{\partial (\text{MSE})}{\partial y_{\text{pred},i}} = \frac{2}{n} (y_{\text{pred},i} - y_i) &&
\end{flalign*} 

코드에서 배치크기 n에 대한 정규화가 없으므로 2.0 을 그대로 사용

 

2. grad_w2 = h_0.T.dot(grad_y_pred)

손실 함수 L을 w2에 대해 미분하여 그래디언트를 계산

\[\frac{\partial L}{\partial w2} = \frac{\partial L}{\partial y_{\text{pred}}} \cdot \frac{\partial y_{\text{pred}}}{\partial w2}\]

각각의 미분 값
\[\frac{\partial L}{\partial y_{\text{pred}}} = \frac{2}{n} \cdot (y_{\text{pred}} - y)\]

y_pred = h_0.dot(w2) 에서 미분
\[\frac{\partial y_{\text{pred}}}{\partial w2} = h_0\]

각 미분값을 곱해준 식

전치행렬을 한 이유는 차원을 맞춰주기 위해서

\[\frac{\partial L}{\partial w2} = h_0^T \cdot \frac{\partial L}{\partial y_{\text{pred}}}\]

 

3. grad_h = grad_y_pred.dot(w2.T)

출력층에서의 기울기(grad_y_pred)를 두 번째 은닉층으로 전파하여 grad_h를 계산

\begin{flalign*} \text{grad_h} &= \frac{\partial L}{\partial y_{\text{pred}}} \cdot \frac{\partial y_{\text{pred}}}{\partial h_0} && \end{flalign*}

 

\begin{flalign*} \frac{\partial y_{\text{pred}}}{\partial h_0} &= w2 && \end{flalign*} \begin{flalign*} \text{grad_h} &= \text{grad_y_pred} \cdot w2^T && \end{flalign*}

 

4. grad_w1 = x.T.dot(grad_h * h * (1 - h))

\( w1 \): \begin{flalign*} \frac{\partial L}{\partial w1} &= \frac{\partial L}{\partial y_0} \cdot \frac{\partial y_0}{\partial w1} && \end{flalign*}

 

Where:

\begin{flalign*} \frac{\partial L}{\partial y_0} &= \text{grad_h} \cdot (h \cdot (1 - h)) && \end{flalign*} \begin{flalign*} \frac{\partial y_0}{\partial w1} &= x && \end{flalign*}

 

Thus:

\begin{flalign*} \text{grad_w1} &= x^T \cdot \left(\text{grad_h} \cdot (h \cdot (1 - h))\right) && \end{flalign*} 

 

역전파 미분하는 과정이다.

 

모든 코드 정리

import numpy as np
from numpy.random import randn

# 2-layer mlp (multi layer perceptron)
n, d, h, c = 64, 1000, 100, 10  # 데이터 input 수, 입력차원, 히든차원, 클래스수
x, y = randn(n, d), randn(n, c)
w1, w2 = randn(d, h), randn(h, c)
learning_rate = 1e-4

for t in range(1000):
    # 순전파 계산
    y_0 = x.dot(w1)  # y = xw + b
    h_0 = 1 / (1 + np.exp(-y_0))  # sigmoid
    y_pred = h_0.dot(w2)  # 마지막 결과값

    # loss
    loss = np.square(y_pred - y).sum()  # MSE 평균제곱오차
    print(t, loss)

    # 역전파 (기울기 업데이트)
    grad_y_pred = 2.0 * (y_pred - y)
    grad_w2 = h_0.T.dot(grad_y_pred)
    grad_h = grad_y_pred.dot(w2.T)
    grad_w1 = x.T.dot(grad_h * h * (1 - h))
    w1 = w1 - learning_rate * grad_w1
    w2 = w2 - learning_rate * grad_w2
728x90
반응형

댓글