Search
🤖

MLP(1)

생성일
2025/05/27 13:48
태그
머신러닝
딥러닝
데이터마이닝
작성자

1. 선형분류기의 실패

결정 경계가 비선형이거나, 데이터를 완전히 분할하기 어려운 경우 선형 분류기의 성능이 저하됨.
특히 XOR 연산은 선형 함수로 구현이 불가하다.

2. 비선형 분류

AND, OR, NAND 연산은 선형 함수로 구현이 가능함.
1-layer perceptron으로 구현이 가능하다는 것
입력 데이터에 가중치가 곱해지고, 해당 값이 계단 함수를 거치도록 하면, 각 연산을 구현할 수 있다.
NAND, OR을 거친 데이터에 AND 연산을 취하면 NAND 구현이 가능
Layer를 깊게 쌓으면 비선형 분류가 가능

3. 신경망의 입력 데이터

이미지
1-D : Flatten
2-D : CNN 계열
시계열
1-D
3-D : 동영상
텍스트
One-hot encoding
각 단어를 고차원 공간에서 서로 다른 단 하나의 위치만 1인 벡터로 표현하여, 단어 간 유사도나 관계 없이 독립적으로 처리하는 방식

4. 신경망 구조

1-layer
Input : 데이터의 종류에 따라 고정된 크기
Output : 목적에 따라 고정된 크기
위의 예에서는 10개의 class 중 하나로 구분하는 것이므로 output은 10개의 unit으로 표현됨
⇒ Input unit과 output unit 사이를 적절히 mapping하는 가중치 ww를 학습
2-layer
Input : 데이터의 종류에 따라 고정된 크기
Output : 목적에 따라 고정된 크기
Hidden : Hidden의 개수는 표현 가능한 정보량에 비례함
활성함수 : 모델의 목적에 따라 다름
Softmax(다중 분류), Sigmoid(이진 분류) ..
2-layer 예시를 보면, 마지막에는 Hidden을 선형 분류하는 것과 마찬가지임을 알 수 있다. 즉, MLP는 여러 층을 거치면서 입력 데이터를 선형 분류 가능한 형태로 변환하고 마지막 층에서 선형 분류를 실시하는 형태임을 알 수 있다.

5. 손실함수

실제 값과 예측 값의 차이를 정의하는 방식
SSE, MSE, RMSE : 회귀에서 주로 사용
Cross-entropy : 분류에서 주로 사용
분류 문제의 경우 sigmoid 함수나 softmax함수를 통해 얻은 특정 class에 속할 확률 값을 바탕으로 Cross-entropy를 목적함수로 하여 MLE를 실시
정답값에 대해 그 확률값을 높이는 방식으로 학습을 진행

6. MLP 최적화

역전파 알고리즘 사용
손실 함수를 정의하고 이를 바탕으로 가중치 update를 진행하고자 할 때, 일반적으로 gradient descent를 사용함.
MLP에서는 손실함수가 합성 함수를 포함하고 있어, 특정 가중치가 최종 출력에 직접적으로 기여하는 정도를 정확히 계산하기 위해서는 역방향으로 update를 진행하여야 함.
Gradient 계산
위와 같이 계산할 경우 각 편미분 값 계산이 용이하며, 이전 층 연산에서 사용한 결과를 재활용할 수 있어 연산량에서 이점을 가진다. (위의 예시에서 빨간 박스)

7. Code

import numpy as np # 데이터 생성 np.random.seed(0) X = np.random.randn(100,2) y = (X[:, 0]*X[:,1]>0).astype(int).reshape(-1,1) # 활성함수 & 미분값 정의 def sigmoid(x): return 1/(1+np.exp(-x)) def d_sigmoid(x): s = sigmoid(x) return s*(1-s) def relu(x): return np.maximum(0,x) def d_relu(x): return(x>0).astype(int) # 초기값 설정 input_size = 2 output_size = 1 hidden1_size = 5 hidden2_size = 3 lr = 0.1 # 가중치 초기화 w1 = np.random.randn(input_size, hidden1_size) * np.sqrt(2 / input_size) b1 = np.zeros((1,hidden1_size)) w2 = np.random.randn(hidden1_size, hidden2_size) * np.sqrt(2 / hidden1_size) b2 = np.zeros((1,hidden2_size)) w3 = np.random.randn(hidden2_size, output_size) * np.sqrt(2 / hidden2_size) b3 = np.zeros((1,output_size)) # 학습 for e in range(10000): #forward z1 = X @ w1 + b1 a1 = relu(z1) z2 = a1 @ w2 + b2 a2 = relu(z2) z3 = a2 @ w3 + b3 a3 = sigmoid(z3) loss = -np.mean(y*np.log(a3+1e-8)+(1-y)*np.log(1-a3+1e-8)) if e==99 : print(loss) # backward N = X.shape[0] dz3 = a3 - y dw3 = a2.T @ dz3 / N db3 = np.mean(dz3, axis=0, keepdims=True) da2 = dz3 @ w3.T dz2 = da2 * d_relu(z2) # relu의 gradient는 해당 뉴런에만 영향을 줌 dw2 = a1.T @ dz2 / N db2 = np.mean(dz2, axis=0, keepdims=True) da1 = dz2 @ w2.T dz1 = da1 * d_relu(z1) dw1 = X.T @ dz1 / N db1 = np.mean(dz1, axis=0, keepdims=True) w3 -= lr * dw3 b3 -= lr * db3 w2 -= lr * dw2 b2 -= lr * db2 w1 -= lr * dw1 b1 -= lr * db1 # 평가 y_pred = (a3 > 0.5).astype(int) acc = np.mean(y_pred == y) print(f"accuracy: {acc:.2f}"
Python
복사