1. 코드 개요 & 목적
공부시간 (x) 한 개만으로 시험점수 (y)를 연속값 회귀(regression) 예측
손실 함수로 MSE 사용
입출력 모두 Z-score 정규화(표준화) 진행 -> 평균 0, 표준편차 1
2. 이전 예제와 주요 차이점
항목 layer2.py (분류) layer3.py (회귀)
| 문제 유형 | 이진 분류 (합격/불합격) | 회귀 (점수 예측) |
| 레이블 형식 | 0 또는 1 | 연속값 (50, 60, … 90) |
| 출력층 활성화 함수 | sigmoid (0~1 확률) | 없음 (선형 출력) |
| 손실 함수 | binary_crossentropy | mse (평균제곱오차) |
| 정규화 방법 | Min–Max (0∼1 스케일) | Z‑score: (x−평균)/표준편차(x-평균)/표준편차 |
| 입력 차원 | 2개 피처 (공부시간, 커피 수) | 1개 피처 (공부시간) |
| 평가 지표 | accuracy | (기본 설정에선 지표 없음→loss만) |
| 추가 구성 요소 | validation_split, EarlyStopping, LR 조정 등 | 간단한 구조, 별도 검증/콜백 없음 |
3. 코드
# layer3.py
# 손실함수 - mse
from tensorflow.keras.models import Sequential # 케라스 모델 레이어
from tensorflow.keras.layers import Dense # 케라스 모델 레이어
import numpy as np # 수치 연산, 배열 처리
# 공부시간(입력), 시험점수(출력)
X = np.array([[1], [2], [3], [4], [5]]) # 5개 샘플, 1차원 피처
y_raw = np.array([50, 60, 70, 80, 90]) # 실제 점수
# 정규화 함수 (z-score)
# 데이터에서 데이터들의평균을 뺀값을 표준편차로 나눔
def normalize(data):
return (data-np.mean(data)) / np.std(data)
# 정규화 적용 (X, y_raw를 각각 평균, 표준편차 기준으로 변환)
X = normalize(X)
y = normalize(y_raw)
# 모델 구성
model = Sequential()
model.add(Dense(8, input_dim=1, activation='relu')) # 뉴런 8개, relu 활성화
model.add(Dense(1)) # 하나의 선형 노드 -> 회귀 예측
# 모델 컴파일 MSE 손실, Adam 옵티마이저
# optimizer='adam': 적응적 학습률, loss='mse' : 회귀용 평균제곱오차
model.compile(optimizer='adam', loss='mse')
# 모델 학습 : 200 epoch, 로그 생략
model.fit(X, y, epochs=200, verbose=0)
# 예측 / 출력
# 예측 : 입력 3 -> 정규화 -> 예측 -> 역정규화
pred = model.predict(normalize(np.array([[3]])))
pred = pred * np.std(y_raw) + np.mean(y_raw) # 역정규화
print(f"공부 3시간 > 예측 점수 {pred[0][0]:.2f}")
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 37ms/step
공부 3시간 > 예측 점수 72.53
=> 3시간 공부에 대해, 학습된 회귀 모델이 약 72.53점을 예측함
원래 데이터 패턴 상으로는 3시간 공부 시 70점이지만(단순 선형이면 80점), 실제 모델은 72.5점으로 약간 다른 값을 반환했음
4. 인사이트
1. 단순 선형 대비 편차
- 실제 관찰값 (70점)에 비해 +2.5점이 높고, 이론적 직선(80점)에 비해 -7.5점 낮은 위치
- 표준화, 역정규화 과정에서 사용된 평균 표준편차, 그리고 학습된 가중치가 단순 선형 관계를 완벽히 재현하지 못했음을 뜻함
2. 모델 용량과 활성화 함수 영향
- 은닉층(relu)이 도입된 비선형 모델이지만, 실제 데이터는 완전한 선형 패턴
- ReLU 특성상 음영 처리된 영역이 생겨, 작은 데이터셋에선 오히려 편향(bias) 발생 가능
3. 데이터 샘플 수 부족
- 총 5개 샘플로는 회귀선을 안정적으로 학습하기 어렵다.
- 학습 데이터가 적으면 초기 가중치 설정과 학습률 변화에 모델 예측이 크게 흔들릴 수 있기 때문
5. 개선 방향
1. 모델 구조 단순화
- 비선형층 없이 Dense(1, input_dim=1, activation='linear') 한 줄로만 구성 -> 순수 선형 회귀
2. 데이터 확대
- 더 많은 (공부시간, 점수) 페어를 수집하거나, 임의 노이즈를 추가한 합성 데이터로 학습 안정성 강화
3. 정규화 방식 비교
- 현재 z-score 대신 MinMaxScaler 사용 실험
- 두 방식 간 예측 성능, 안정성 차이 점검
4. 하이퍼파라미터 튜닝
- 학습률, epochs, 은닉 뉴런 수 등을 그리드 서치 혹은 수동 실험으로 최적 조합 탐색
5. 평가 지표 확대
MSE 외에 MAE, R2 Score 등을 함께 계산해서 오차 크기와 설명력을 다각도로 평가
# layer3_improved.py
# 회귀 예제에 “검증 분리”, “EarlyStopping”, “MAE 지표” 추가
from tensorflow.keras.models import Sequential # 케라스 순차 모델
from tensorflow.keras.layers import Dense # 전결합(Dense) 레이어
from tensorflow.keras.callbacks import EarlyStopping # 조기 종료 콜백
import numpy as np # 수치 연산
# 1) 데이터 준비
X_raw = np.array([[1], [2], [3], [4], [5]]) # 공부시간
y_raw = np.array([50, 60, 70, 80, 90]) # 시험점수
# 2) Z‑score 정규화 함수
def normalize(data):
return (data - np.mean(data)) / np.std(data)
# 3) 정규화 적용
X = normalize(X_raw)
y = normalize(y_raw)
# 4) 모델 구성
model = Sequential()
model.add(
Dense(
8, # 은닉 뉴런 8개
input_dim=1, # 입력 특성 1차원
activation='relu' # 비선형성 도입
)
)
model.add(
Dense(
1 # 선형 노드 1개 → 회귀 예측
# activation='linear' # 기본값이 선형이므로 생략 가능
)
)
# 5) 모델 컴파일
# - loss: MSE (평균제곱오차)
# - metrics: MAE (평균절대오차) 추가 → 오차 크기 직관적으로 확인
model.compile(
optimizer='adam',
loss='mse',
metrics=['mae']
)
# 6) EarlyStopping 설정
# - val_loss(검증 손실) 기준으로 10회 연속 개선 없으면 중단
# - restore_best_weights=True: 최적 검증 모델 가중치 복원
es = EarlyStopping(
monitor='val_loss',
patience=10,
restore_best_weights=True
)
# 7) 모델 학습
# - validation_split=0.2: 전체의 20%를 검증용으로 자동 분리
# - callbacks=[es]: 조기 종료 적용
# - verbose=1: epoch별 진행바 및 loss/mae 출력
history = model.fit(
X, y,
epochs=200,
validation_split=0.2,
callbacks=[es],
verbose=1
)
# 8) 예측
# - 입력 3시간도 정규화 → 예측 → 역정규화
test = np.array([[3]])
test_norm = normalize(test)
pred_norm = model.predict(test_norm)
pred = pred_norm * np.std(y_raw) + np.mean(y_raw)
print(f"\n공부 3시간 > 예측 점수 {pred[0][0]:.2f}")
# 9) 학습 결과 요약 (MAE 지표 포함)
final_train_mae = history.history['mae'][-1]
final_val_mae = history.history['val_mae'][-1]
print(f"최종 Train MAE: {final_train_mae:.4f}")
print(f"최종 Val MAE: {final_val_mae:.4f}")
공부 3시간 > 예측 점수 67.36
최종 Train MAE: 0.6054
최종 Val MAE: 0.7915
현재 모델은 오히려 선형 패턴에 부적합하게 학습돼 평균 +-8~11점 오차가 나는 상태
'Data Analysis Study' 카테고리의 다른 글
| 최적화 함수 (Optimizer)의 차이 시각적 이해 (0) | 2025.07.20 |
|---|---|
| 딥러닝 다중 클래스 분류(Multi‑class Classification), 레이블 원-핫 인코딩, Softmax 출력, Categorical Cross‑Entropy 손실 함수 (3) | 2025.07.20 |
| 딥러닝 분류(Classification) 이진분류 + 추가 학습 (0) | 2025.07.20 |
| 시험 점수 예측 딥러닝 모델 (0) | 2025.07.19 |
| 딥러닝의 기초 개념과 이론 총정리 (0) | 2025.07.19 |