728x90
신경망 구현
3층 신경망 구현







신경망 기초 : 순전파와 활성화 함수 이해하기
- 이번 공부에서는 신경망의 기본 구조와 순전파(Forward Pass)를 Python 으로 구현하는 방법을 다뤘습니다.
- 회귀 문제와 분류 문제를 해결하는 간단한 신경망을 구성하고, 이를 확장하여 4층 구조로 변형하는 과정을 공부하겠습니다.
신경망 기본 구성 요소
- 활성화 함수(Activation Functions)
- 신경망에서 각 층의 출력을 비선형으로 변환하기 위해 활성화 함수를 사용한다. 여기서는 세 가지 함수를 정의해보았습니다.
- ReLU: relu(z) = np.maximum(0, z)
- 입력값이 0보다 작으면 0, 크면 그대로 출력.
- Identity: identify(z) = z
- 회귀 문제에서 출력층에 사용. 입력값을 그대로 반환.
- Softmax: softmax(z)
- 분류 문제에서 사용. 출력값을 확률로 변환.
- ReLU: relu(z) = np.maximum(0, z)
- 신경망에서 각 층의 출력을 비선형으로 변환하기 위해 활성화 함수를 사용한다. 여기서는 세 가지 함수를 정의해보았습니다.
import numpy as np # 활성화 함수 정의 # y값 변환주는 함수 # ReLU: 0 이하 값은 0으로, 양수는 그대로
def relu(z): return np.maximum(0, z) # Identity: 회귀 문제 출력층용, 입력값 그대로 반환
def identify(z): return z # Softmax: 분류 문제 출력층용, 확률로 변환
def softmax(z): exp_z = np.exp(z - np.max(z, axis=0, keepdims=True)) # 오버플로우 방지 return exp_z / np.sum(exp_z, axis=0, keepdims=True) |
순전파(Forward Pass)
- 순전파는 입력 데이터를 각 층을 거쳐 출력으로 변환하는 과정입니다. 3층 구조(입력층 -> 은닉층 -> 출력층)를 다음과 같이 정의했습니다.
# 순전파 함수 def forward_pass(X, W1, b1, W2, b2, output_activation): Z1 = W1 @ X + b1 # 은닉층 선형 결합 A1 = relu(Z1) # 은닉층 활성화 Z2 = W2 @ A1 + b2 # 출력층 선형 결합 A2 = output_activation(Z2) # 출력층 활성화 return A1, Z2, A2 |
- X: 입력 데이터 (피처 수 × 샘플 수)
- W1, b1: 첫 번째 층의 가중치와 편향
- W2, b2: 두 번째 층의 가중치와 편향
- output_activation: 출력층에 사용할 활성화 함수
가중치 초기화 - 3층 구조
- 가중치와 편향을 무작위로 초기화합니다.
# 가중치 초기화 함수 def initialize_parameters(input_size, hidden_size, output_size): W1 = np.random.randn(hidden_size, input_size) * 0.1 b1 = np.random.randn(hidden_size, 1) * 0.1 W2 = np.random.randn(output_size, hidden_size) * 0.1 b2 = np.random.randn(output_size, 1) * 0.1 return W1, b1, W2, b2 |
# 이제 항등합수를 이용해서 회귀문제처럼 풀어보겠습니다.
회귀 문제 해결
- 데이터 생성
- 집의 면적과 위치 점수를 기반으로 집값을 예측하는 회귀 문제를 설정합니다.
np.random.seed(1) X_reg = np.random.rand(2, 100) # 2피처, 100 샘플 Y_reg = (4 * X_reg[0] + 2 * X_reg[1] + 1 + np.random.randn(100) * 0.1).reshape(-1, 1) |
- X_reg: 2개의 피처(랜덤 값)
- Y_reg: 선형 결합 + 노이즈
초기화 및 순전파 - 회귀
3층 신경망으로 예측합니다.
# 파라미터 초기화 및 순전파 진행 W1_reg, b1_reg, W2_reg, b2_reg = initialize_parameters(2, 3, 1) # 회귀문제 순전파로 풀어 봄 _, _, y_pred_reg = forward_pass(X_reg, W1_reg, b1_reg, W2_reg, b2_reg, identify) |
소프트맥스 함수를 사용해 이진 분류 문제 해결
#### 소프트맥스 함수를 사용해서 이진 분류 문제 해결 X_clf=np.random.randn(2,100) Y_clf_true = ((X_clf[0] * X_clf[1])> 0).astype(int) Y_clf =np.zeros((2,100)) Y_clf[Y_clf_true, np.arange(100)] = 1 |
데이터 타입을 만들었으니 실제 신경망에 학습함
## 데이터 타입을 만들었으니 실제 신경망에 학습 W1_clf, b1_clf, W2_clf, b2_clf =initialize_parameters(2,3,2) |
분류문제 순전파로 풀이
## 분류문제 순전파로 풀어 봄 _,_,y_pred_clf =forward_pass(X_clf, W1_clf, b1_clf, W2_clf, b2_clf, softmax) |
y_pred_clf |
array([[0.45357359, 0.45394567, 0.45126141, 0.46078338, 0.46182956,
0.46750891, 0.44092459, 0.46029064, 0.46957912, 0.46957912,
0.45576538, 0.46774883, 0.4564977 , 0.45723816, 0.46408276,
0.4564989 , 0.45422334, 0.43852023, 0.44684039, 0.46424365,
0.44929089, 0.46010553, 0.45210385, 0.45805978, 0.4651937 ,
0.46464154, 0.46445303, 0.46010132, 0.46957912, 0.46665664,
0.4624558 , 0.46240906, 0.46604321, 0.45494932, 0.45527261,
0.44409248, 0.44628709, 0.46075686, 0.43274781, 0.45147791,
0.45366966, 0.44731388, 0.4583828 , 0.45700261, 0.46067911,
0.46522972, 0.46406566, 0.45398557, 0.46127394, 0.46092419,
0.45710573, 0.46957912, 0.45689007, 0.45776443, 0.45171147,
0.46957912, 0.45730534, 0.44749247, 0.46909043, 0.45769332,
0.46957912, 0.46816914, 0.46367349, 0.45567859, 0.46957912,
0.46263046, 0.46423095, 0.46532756, 0.45549138, 0.46109211,
0.46957912, 0.46957912, 0.44967781, 0.45875349, 0.46399956,
0.45912959, 0.4552199 , 0.46775466, 0.45546222, 0.44587744,
0.4647066 , 0.45274557, 0.44901334, 0.4491213 , 0.46317171,
0.44155035, 0.43976131, 0.4669402 , 0.46957912, 0.46957912,
0.44965955, 0.45241724, 0.44111246, 0.45966016, 0.44018591,
0.46068036, 0.46854685, 0.45379454, 0.46957912, 0.45278094],
[0.54642641, 0.54605433, 0.54873859, 0.53921662, 0.53817044,
0.53249109, 0.55907541, 0.53970936, 0.53042088, 0.53042088,
0.54423462, 0.53225117, 0.5435023 , 0.54276184, 0.53591724,
0.5435011 , 0.54577666, 0.56147977, 0.55315961, 0.53575635,
0.55070911, 0.53989447, 0.54789615, 0.54194022, 0.5348063 ,
0.53535846, 0.53554697, 0.53989868, 0.53042088, 0.53334336,
0.5375442 , 0.53759094, 0.53395679, 0.54505068, 0.54472739,
0.55590752, 0.55371291, 0.53924314, 0.56725219, 0.54852209,
0.54633034, 0.55268612, 0.5416172 , 0.54299739, 0.53932089,
0.53477028, 0.53593434, 0.54601443, 0.53872606, 0.53907581,
0.54289427, 0.53042088, 0.54310993, 0.54223557, 0.54828853,
0.53042088, 0.54269466, 0.55250753, 0.53090957, 0.54230668,
0.53042088, 0.53183086, 0.53632651, 0.54432141, 0.53042088,
0.53736954, 0.53576905, 0.53467244, 0.54450862, 0.53890789,
0.53042088, 0.53042088, 0.55032219, 0.54124651, 0.53600044,
0.54087041, 0.5447801 , 0.53224534, 0.54453778, 0.55412256,
0.5352934 , 0.54725443, 0.55098666, 0.5508787 , 0.53682829,
0.55844965, 0.56023869, 0.5330598 , 0.53042088, 0.53042088,
0.55034045, 0.54758276, 0.55888754, 0.54033984, 0.55981409,
0.53931964, 0.53145315, 0.54620546, 0.53042088, 0.54721906]])
실제 문제처럼 신경망을 이용해서 풀어봄
실제 문제 데이터 생성 - 회귀
집 면적과 위치 점수로 집값 예측
import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error n_samples = 200 X_reg = np.random.rand(2, n_samples) # 2피처, 100개의 샘플 ## 집의 면적과 위치에 대한 점수 Y_reg = (150 * X_reg[0] + 80 * X_reg[1] + 20 + np.random.randn(n_samples) * 5).reshape(1, -1) ## 집값 |
데이터 시각화 - 회귀
plt.figure(figsize=(6, 4)) plt.scatter(X_reg[0], Y_reg, label='ft_1', alpha=0.5) plt.scatter(X_reg[1], Y_reg, label='ft_2', alpha=0.5) plt.legend() plt.grid(True) plt.show() |

학습/테스트 분할 및 예측 - 회귀
from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error ## train/test 분할 Xr_train, Xr_test, Yr_train, Yr_test = train_test_split(X_reg.T, Y_reg.T, test_size=0.2, random_state=111) Xr_train, Xr_test = Xr_train.T, Xr_test.T Yr_train, Yr_test = Yr_train.T, Yr_test.T # 초기화 및 예측 W1_reg, b1_reg, W2_reg, b2_reg = initialize_parameters(2, 10, 1) _, _, y_pred_reg = forward_pass(Xr_test, W1_reg, b1_reg, W2_reg, b2_reg, identify) # MSE 계산 mse = mean_squared_error(Yr_test.flatten(), y_pred_reg.flatten()) print(f"MSE: {mse}" |
18039.627135504823
Yr_test.flatten() |
array([ 79.61511275, 153.96364596, 104.52077469, 134.16832042,
98.76949409, 187.07464587, 213.07545066, 89.41348882,
130.82195925, 75.12044304, 79.49712396, 185.04189686,
132.93228303, 98.49354465, 135.62399298, 211.48939181,
130.43970054, 154.39974627, 72.69893227, 131.34846281,
98.43418282, 75.92826905, 181.18289628, 67.02901064,
186.87219599, 113.60252368, 52.65981642, 138.77790125,
185.35792922, 120.54869772, 173.11080948, 124.03034714,
83.29643241, 52.83630021, 51.04366086, 118.64456577,
222.931479 , 167.05645502, 73.36393222, 145.89866674])
mean_squared_error(Yr_test.flatten(), y_pred_reg.flatten()) |
18081.877245910116
3. 분류 문제 해결
데이터 생성 - 분류
이진 분류를 위한 데이터셋 생성
X_clf = np.random.randn(2, 100) # 2피처, 100 샘플 Y_clf_true = ((X_clf[0] * X_clf[1]) > 0).astype(int) # 곱이 양수면 1, 음수면 0 Y_clf = np.zeros((2, 100)) Y_clf[Y_clf_true, np.arange(100)] = 1 |
초기화 및 순전파 - 분류
W1_clf, b1_clf, W2_clf, b2_clf = initialize_parameters(2, 3, 2) _, _, y_pred_clf = forward_pass(X_clf, W1_clf, b1_clf, W2_clf, b2_clf, softmax) # 결과 출력 print(y_pred_clf) |
출력은 각 샘플에 대한 클래스 확률(2×100 배열).
필수과제 1
- 1. PDF파일의 신경망 3층 구조를 -> 4층으로 만들어서 직접 손으로 (펜,종이, 아이패드 상관없음) - 계산되는 과정 모두 다 적어주세요. ( PDF 파일처럼 직접 노드 그려서 벡터 선형 결합 적고, 직접 활성화 함수 지정해서 어떤 식으로 계산되는지 적어주세요! )
필수과제 2
- 2. 실제 분류 문제도 동일하게 200개 정도 데이터셋을 만들어서 코드와 함께 직접 구현 - Ipynb 로 제출 요구
필수과제 1: 신경망 4층 구조 계산 과정
1. 신경망 구조
- 신경망은 입력층, 은닉층, 출력층으로 구성됩니다. 여기서 4층 신경망을 만든다는 것은 입력층 + 3개의 은닉층 + 출력층을 만들게 됩니다.
- 각 층은 뉴런들이 연결된 구조로, 각 뉴런에서 계산된 값은 다음 층으로 전달됩니다.
2. 구성 요소

여기서 W_i 는 각 층의 가중치, b_i 는 편향, a_i 는 활성화 함수가 적용된 출력 값입니다.
3. 계산 과정


4. 활성화 함수
활성화 함수는 각 층에서 출력값을 비선형적으로 변화시키는 역할을 합니다. 일반적으로 사용하는 함수는 다음과 같다

5. 연산 예시 (4층 신경망)
Input X = [x1, x2, ..., xn] Layer 1: z1 = W1 * X + b1 a1 = ReLU(z1) Layer 2: z2 = W2 * a1 + b2 a2 = ReLU(z2) Layer 3: z3 = W3 * a2 + b3 a3 = ReLU(z3) Output Layer: z4 = W4 * a3 + b4 a4 = Softmax(z4) (예를 들어 다중 클래스 분류라면) |
6. 직접 손으로 계산

필수과제 2: 분류 문제 구현
이제 분류 문제를 해결하는 코드를 작성할 차례입니다. 이 예시에서는 간단한 이진 분류 문제를 다루며, 데이터셋은 랜덤으로 생성하여 사용할 수 있다.
Python의 scikit-learn 라이브러리를 사용하여 분류 문제를 풀 수 있습니다.
1. 필수과제 2: 코드 예시
# 필수과제 2: 이진 분류 문제 해결 import numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from sklearn.datasets import make_classification from sklearn.neural_network import MLPClassifier from sklearn.metrics import classification_report, accuracy_score # 데이터셋 생성 (200개 샘플) X, y = make_classification(n_samples=200, n_features=2, n_classes=2, random_state=42) # 훈련 데이터와 테스트 데이터로 분할 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 신경망 모델 생성 (MLP: 다층 퍼셉트론) model = MLPClassifier(hidden_layer_sizes=(4,), max_iter=1000, activation='relu', solver='adam', random_state=42) # 모델 학습 model.fit(X_train, y_train) # 예측 y_pred = model.predict(X_test) # 평가 print(f"Accuracy: {accuracy_score(y_test, y_pred)}") print(classification_report(y_test, y_pred)) # 시각화 (결과) plt.figure(figsize=(8, 6)) plt.scatter(X_test[:, 0], X_test[:, 1], c=y_pred, cmap=plt.cm.coolwarm) plt.title("Predicted Classes") plt.xlabel("Feature 1") plt.ylabel("Feature 2") plt.show() |
2. 코드 설명
- 데이터셋: make_classification을 사용하여 이진 분류 문제를 위한 200개 샘플을 생성합니다.
- 훈련 및 테스트 데이터 분리: train_test_split을 사용하여 70%는 훈련용, 30%는 테스트용 데이터로 분리합니다.
- 모델 생성: MLPClassifier를 사용하여 다층 퍼셉트론 신경망을 생성합니다. 4개의 뉴런을 가진 은닉층을 설정했습니다.
- 훈련 및 예측: 모델을 훈련시키고 테스트 데이터에 대해 예측합니다.
- 평가: 정확도와 분류 보고서를 출력하여 모델 성능을 평가합니다.
- 시각화: matplotlib을 사용하여 테스트 데이터와 예측된 클래스를 시각화합니다.
728x90
'ML' 카테고리의 다른 글
BDA_딥러닝의 이해반_0323_복습코드 (0) | 2025.03.28 |
---|---|
BDA_딥러닝의 이해반_250323 (0) | 2025.03.25 |
로지스틱 회귀 모델 (1) | 2024.07.04 |
비지도 학습 (0) | 2024.07.04 |
머신러닝 알고리즘 정리 (0) | 2024.07.04 |