Skip to main content

μ—­μ „νŒŒ μ•Œκ³ λ¦¬μ¦˜

μ½”λ“œμ™€ ν•¨κ»˜ κ°„λ‹¨ν•˜κ²Œ 정리​

import numpy as np
from data_prep import features, targets, features_test, targets_test

# μž¬ν˜„μ„±μ„ μœ„ν•œ 랜덀 μ‹œλ“œ μ„€μ •
np.random.seed(21)

def sigmoid(x):
"""
μ‹œκ·Έλͺ¨μ΄λ“œ ν™œμ„±ν™” ν•¨μˆ˜
μž…λ ₯값을 0~1 μ‚¬μ΄μ˜ κ°’μœΌλ‘œ λ³€ν™˜
Parameters:
x: μž…λ ₯ κ°’
Returns:
sigmoid ν•¨μˆ˜λ₯Ό μ μš©ν•œ κ²°κ³Ό κ°’
"""
return 1 / (1 + np.exp(-x))

# ν•˜μ΄νΌνŒŒλΌλ―Έν„° μ„€μ •
n_hidden = 2 # μ€λ‹‰μΈ΅μ˜ λ‰΄λŸ° 개수
epochs = 900 # 전체 데이터셋을 ν•™μŠ΅ν•  횟수
learnrate = 0.005 # ν•™μŠ΅λ₯  - κ°€μ€‘μΉ˜ μ—…λ°μ΄νŠΈ μŠ€ν… μ‚¬μ΄μ¦ˆ

# 데이터 차원 정보
n_records, n_features = features.shape
last_loss = None

# κ°€μ€‘μΉ˜ μ΄ˆκΈ°ν™” - Xavier/Glorot μ΄ˆκΈ°ν™” 방법 μ‚¬μš©
weights_input_hidden = np.random.normal(scale=1 / n_features ** .5,
size=(n_features, n_hidden))
weights_hidden_output = np.random.normal(scale=1 / n_features ** .5,
size=n_hidden)

# ν•™μŠ΅ μ‹œμž‘
for e in range(epochs):
# κ°€μ€‘μΉ˜ λ³€ν™”λŸ‰μ„ μ €μž₯ν•  ν–‰λ ¬ μ΄ˆκΈ°ν™”
del_w_input_hidden = np.zeros(weights_input_hidden.shape)
del_w_hidden_output = np.zeros(weights_hidden_output.shape)

# 각 ν›ˆλ ¨ 데이터에 λŒ€ν•΄ μˆœμ „νŒŒμ™€ μ—­μ „νŒŒ μˆ˜ν–‰
for x, y in zip(features.values, targets):
### μˆœμ „νŒŒ(Forward Pass) ###
# μž…λ ₯μΈ΅ -> 은닉측
hidden_input = np.dot(x, weights_input_hidden) # 은닉측 μž…λ ₯ 계산
hidden_output = sigmoid(hidden_input) # 은닉측 ν™œμ„±ν™”

# 은닉측 -> 좜λ ₯μΈ΅
output = sigmoid(np.dot(hidden_output, weights_hidden_output)) # μ΅œμ’… 좜λ ₯

### μ—­μ „νŒŒ(Backward Pass) ###
# 좜λ ₯μΈ΅ 였차 계산
error = y - output # μ‹€μ œκ°’κ³Ό μ˜ˆμΈ‘κ°’μ˜ 차이

# 좜λ ₯측의 델타 계산
# Ξ΄ = error * output * (1 - output)
output_error_term = error * output * (1 - output)

# μ€λ‹‰μΈ΅μœΌλ‘œ 였차 μ „νŒŒ
# 은닉측이 좜λ ₯μΈ΅ μ˜€μ°¨μ— κΈ°μ—¬ν•œ 정도 계산
hidden_error = np.dot(output_error_term, weights_hidden_output)

# μ€λ‹‰μΈ΅μ˜ 델타 계산
# Ξ΄ = hidden_error * hidden_output * (1 - hidden_output)
hidden_error_term = hidden_error * hidden_output * (1 - hidden_output)

# κ°€μ€‘μΉ˜ λ³€ν™”λŸ‰ λˆ„μ 
del_w_hidden_output += output_error_term * hidden_output # 은닉측->좜λ ₯μΈ΅ κ°€μ€‘μΉ˜
del_w_input_hidden += hidden_error_term * x[:, None] # μž…λ ₯μΈ΅->은닉측 κ°€μ€‘μΉ˜

# λ―Έλ‹ˆλ°°μΉ˜μ˜ ν‰κ· μœΌλ‘œ κ°€μ€‘μΉ˜ μ—…λ°μ΄νŠΈ
weights_input_hidden += learnrate * del_w_input_hidden / n_records
weights_hidden_output += learnrate * del_w_hidden_output / n_records

# ν›ˆλ ¨ κ³Όμ • λͺ¨λ‹ˆν„°λ§ - λ§€ 10%λ§ˆλ‹€ 손싀 좜λ ₯
if e % (epochs / 10) == 0:
hidden_output = sigmoid(np.dot(x, weights_input_hidden))
out = sigmoid(np.dot(hidden_output, weights_hidden_output))
loss = np.mean((out - targets) ** 2) # MSE 손싀 계산

# 손싀이 μ¦κ°€ν•˜λŠ”μ§€ 확인 (κ²½κ³  좜λ ₯)
if last_loss and last_loss < loss:
print("Train loss: ", loss, " WARNING - Loss Increasing")
else:
print("Train loss: ", loss)
last_loss = loss

# μ΅œμ’… ν…ŒμŠ€νŠΈ μ„ΈνŠΈ μ„±λŠ₯ 평가
hidden = sigmoid(np.dot(features_test, weights_input_hidden))
out = sigmoid(np.dot(hidden, weights_hidden_output))
predictions = out > 0.5 # 0.5λ₯Ό μž„κ³„κ°’μœΌλ‘œ 이진 λΆ„λ₯˜
accuracy = np.mean(predictions == targets_test)
print("Prediction accuracy: {:.3f}".format(accuracy))