1. 코드의 목적과 역할 분석
주어진 데이터(공부 시간, 커피 수)로 학생의 시험 결과(합격 or 불합격)를 예측하는 신경망 모델 구축.
역할 :
- 데이터 학습을 통한 합격 확률 예측
- 데이터 기반으로 합격과 불합격을 자동 분류
- 실제 현업에서 쓰이는 이진 분류 문제의 기초적인 이해
2. 필수 라이브러리
- Numpy : 수치 데이터 배열 생성 및 처리 (np.array(
- TensorFlow/Keras
- sequential : 순차적으로 층(layer)을 추가하여 간편하게 모델 구축
- Dense : 각 층을 구성할 때 사용하는 기본 뉴런층 (완전 연결층)
3. 주요 기능 분석
신경망 설계 : 입력층 (공부 시간, 커피 수 ) -> 은닉층(Dense/ReLu) -> 출력층 (Dense/Sigmoid)
모델 컴파일 : 손실함수 (binary_crossentropy), 최적화함수(adam), 평가지표(accuracy)
학습 및 예측 : 주어진 데이터로 학습 후 새로운 입력 데이터를 분류 및 확률 예측
4. 코드
# layer2.py (완료)
# sigmoid 활성화 함수
# 라이브러리 임포트
from tensorflow.keras.models import Sequential # 케라스의 순차 모델 클래스, 층을 차례로 쌓아 올리는 구조
from tensorflow.keras.layers import Dense # 완전 연결층. 입력 노드와 출력 노드가 모두 연결된 형태
import numpy as np #기본적인 수치 연산과 배열 생성, 조작을 담당
# 입력 데이터 (공부시간, 커피 수)
# 입력값 범위가 작아서 정규화를 생략해도 크게 무방하지 않지만 일반적으로는 MinMaxScaler 같은 전처리 권장
X = np.array([[1, 0], [2, 1], [3, 1], [4, 2], [5, 3]])
# 출력 데이터 (합격=1, 불합격=0), 이진분류
y = np.array([0, 0, 0, 1, 1])
# 모델 컴파일
model = Sequential() # 빈 시퀀셜 모델 객체 생성
model.add(Dense(4, input_dim=2, activation='relu')) # 은닉층
# 은닉 뉴런 4개, 입력 특성이 2차원임을 지정, 비선형성을 부여, 음수 값은 0으로 잘라 학습 속도 높임, 희소성 유도
model.add(Dense(1, activation='sigmoid')) # 출력층
# 하나의 값(합격 확률) 출력, 출력 범위 0~1 확률 해석에 적합하다.
# 모델 컴파일
model.compile(
optimizer='adam', # 최적화 함수 (적응적 학습률을 사용하는 확률적 경사하강법 변형)
loss='binary_crossentropy', # 손실 함수 (이진분류용 로그 손실 함수)
metrics=['accuracy'] # 지표 : 정확도를 추가로 계산, 출력
)
# 모델 학습
# 전체 데이터 셋을 200번 반복 학습
# verbose=0 : 학습 진행 로그를 출력하지 않음
# verbose=1 로 하면 진척 바, 2로 하면 epoch별 요약 로그가 실시간으로 출력됨
model.fit(X, y, epochs=200, verbose=0)
# 예측 테스트
test_data = np.array([[3, 2], [5, 1], [1, 0]])
# 공부 3시간, 커피 2잔, 공부 5시간 커피 1잔, 공부 1시간 커피 0잔 데이터
predictions = model.predict(test_data) # 각 샘플의 합격 확률 (0~1 실수)
# 결과 출력
for i, pred in enumerate(predictions):
print(f"입력:{test_data[i]}, 예측확률:{pred[0]:.4f}, \
분류: {'합격' if pred[0]>=0.5 else '불합격'}")
# 결과
입력:[3 2], 예측확률:0.5565, 분류: 합격
입력:[5 1], 예측확률:0.6189, 분류: 합격
입력:[1 0], 예측확률:0.4395, 분류: 불합격
# 합격 분류는 맞지만 모델은 아직 확신이 낮은 상태임
# 불합격 분류 역시 0.44라는 확률은 낮은 자신감
=> Classification(분류) 관점에서는 맞혔지만, Probablility(확률) 관점에서 보면 경계에 걸쳐있어 판별 기준 바로 위아래에서 왔다 갔다 하는 모습
=> 예측 확률이 0.56~0.62 정도로 낮게 나왔음. 모델의 신뢰도를 높이기 위한 개선 방안 필요
원인 분석
1. 입력 스케일 불일치
- 공부시간과 커피수를 정규화 없이 그대로 사용
- 각 피처의 영향력이 왜곡되어, 학습이 덜 안정적일 수 있음
2. 데이터 양, 다양성 부족
- 5개의 샘플만으로 복잡한 경계면을 학습하기엔 정보가 충분치 않음
3. 모델 구조, 하이퍼파라미터
- 은닉층 4개 뉴런, epoch 200회로는 과소 적합 가능성
- 학습률 기본값, 배치 크기 등도 미세 조정이 필요함
4. 이진 분류 손실 특성
- binary_crossentropy는 확률 예측 시 경계 근처 값(0.5±ε)에 덜 패널티를 줄 수 있음
# layer2_improved.py
# sigmoid 활성화 함수 기반 이진 분류 모델
# 입력 정규화(MinMaxScaler), 훈련/검증 데이터 분리, 하이퍼파리미터 튜닝, 조기 종료 콜백, 학습 로그 출력
from tensorflow.keras.models import Sequential # 케라스 순차 모델 클래스
from tensorflow.keras.layers import Dense # 전결합(Dense) 레이어
from tensorflow.keras.optimizers import Adam # Adam 옵티마이저
from tensorflow.keras.callbacks import EarlyStopping # 조기 종료 콜백
from sklearn.preprocessing import MinMaxScaler # 입력 피처 정규화
import numpy as np # 수치 연산용
# 1) 데이터 준비
# X: [공부시간, 커피 수], y: [불합격=0, 합격=1]
X = np.array([[1, 0],
[2, 1],
[3, 1],
[4, 2],
[5, 3]])
y = np.array([0, 0, 0, 1, 1])
# 2) 입력 데이터 정규화 (0~1 범위로 스케일링)
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X) # fit: min/max 계산, transform: 스케일링 적용
# 3) 모델 구성
model = Sequential()
model.add(Dense(8, # 은닉층 뉴런 8개
input_dim=2, # 입력 특성 2차원 지정
activation='relu' # ReLU 활성화로 비선형성 부여
))
model.add(Dense(1, # 출력층 뉴런 1개 → 확률값 예측
activation='sigmoid' # Sigmoid 활성화로 0~1 확률 출력
))
# 4) 모델 컴파일: Adam 옵티마이저(학습률 조정), 이진분류 손실, 정확도 지표
optimizer = Adam(learning_rate=0.01) # 기본 0.001 → 0.01로 조정해 빠른 수렴 시도
model.compile(optimizer=optimizer,
loss='binary_crossentropy',
metrics=['accuracy'])
# 5) EarlyStopping 콜백 설정: val_loss 기준 10회 연속 개선 없으면 학습 중단
es = EarlyStopping(monitor='val_loss',
patience=10,
restore_best_weights=True)
# 6) 모델 학습: 검증셋 20% 분리, 최대 500 epochs, EarlyStopping 적용
history = model.fit(X_scaled, # 정규화된 입력
y, # 레이블(0/1)
epochs=500, # 최대 반복 횟수
validation_split=0.2, # 20%는 검증용
callbacks=[es], # 조기 종료 콜백
verbose=1 # 학습 진행바 출력
)
# 7) 예측 테스트: 새로운 샘플도 동일한 스케일링 적용 후 예측
test_data = np.array([[3, 2], # 공부 3h, 커피 2잔
[5, 1], # 공부 5h, 커피 1잔
[1, 0]]) # 공부 1h, 커피 0잔
test_scaled = scaler.transform(test_data) # 스케일 변환
predictions = model.predict(test_scaled) # 확률 예측 (0~1)
# 8) 결과 출력: threshold=0.5로 분류, 소수점 4자리까지 표시
for i, prob in enumerate(predictions):
label = '합격' if prob[0] >= 0.5 else '불합격'
print(f"입력:{test_data[i]}, 예측확률:{prob[0]:.4f}, 분류: {label}")
--
입력:[3 2], 예측확률:0.9353, 분류: 합격
입력:[5 1], 예측확률:0.5650, 분류: 합격
입력:[1 0], 예측확률:0.0001, 분류: 불합격
'Data Analysis Study' 카테고리의 다른 글
| 딥러닝 다중 클래스 분류(Multi‑class Classification), 레이블 원-핫 인코딩, Softmax 출력, Categorical Cross‑Entropy 손실 함수 (3) | 2025.07.20 |
|---|---|
| 딥러닝 예제 : 회귀 (점수 예측) (0) | 2025.07.20 |
| 시험 점수 예측 딥러닝 모델 (0) | 2025.07.19 |
| 딥러닝의 기초 개념과 이론 총정리 (0) | 2025.07.19 |
| TensorFlow의 핵심 개념과 사용법 (1) | 2025.07.10 |