TensorFlow / Keras — 딥러닝 모델 만들기
Sequential API로 신경망을 설계하고 MNIST 손글씨 인식 모델을 직접 학습하며 Dropout, EarlyStopping으로 과적합을 막는 법까지 정리
2026.04.10
0. 시리즈
| 편 | 제목 | 역할 |
|---|---|---|
| 1편 | NumPy 완벽 정리 — 숫자 배열 다루기 | 데이터 기초 |
| 2편 | Pandas 완벽 정리 — 데이터 불러오고 정리하기 | 데이터 전처리 |
| 3편 | Matplotlib / Seaborn — 데이터 시각화 | 시각화 |
| 4편 | Scikit-learn — 머신러닝 실습 입문 | ML 실습 |
| 5편⬅️ | TensorFlow / Keras — 딥러닝 모델 만들기 | DL 실습 |
| 6편 | PyTorch 입문 — Keras와 무엇이 다를까? | DL 심화 |
1. TensorFlow와 Keras란?
1-1. TensorFlow란?
TensorFlow(텐서플로우) 는 구글이 2015년에 공개한 딥러닝 연산 엔진입니다. 이름의 Tensor 는 다차원 배열(1편에서 배운 NumPy 배열과 같은 개념), Flow 는 데이터가 연산 그래프를 따라 흘러간다는 뜻입니다.
쉽게 말해 "딥러닝 모델 안에서 일어나는 수백만 번의 수학 계산을 빠르게 처리해주는 엔진" 입니다.
1-2. Keras란?
Keras(케라스) 는 TensorFlow 위에서 동작하는 고수준 인터페이스 입니다. TensorFlow 2.0부터는 tf.keras로 TensorFlow 안에 완전히 통합되었습니다.
TensorFlow로 모델을 직접 구현하면 수십 줄이 필요한 코드를, Keras는 몇 줄로 줄여줍니다.
1-3. TensorFlow vs Keras 관계
TensorFlow = 자동차 엔진 (강력하지만 직접 다루기 복잡함)
Keras = 핸들과 페달 (누구나 쉽게 조작할 수 있는 인터페이스)
우리는 핸들(Keras)을 잡고 운전하면 됩니다. 엔진(TensorFlow)은 내부에서 알아서 돌아갑니다.
1-4. PyTorch와 무엇이 다른가?
| 비교 항목 | TensorFlow/Keras | PyTorch |
|---|---|---|
| 개발사 | Meta(Facebook) | |
| 난이도 | 쉬움 (입문자 추천) | 비교적 어려움 |
| 주요 사용처 | 산업·서비스 배포 | 연구·논문 구현 |
| 사용자층 | 실무 개발자 | AI 연구자 |
PyTorch는 다음 편(6편)에서 다룹니다.
1-5. 설치 및 임포트
bashpip install tensorflow
pythonimport tensorflow as tf
print(tf.__version__) # 예: 2.15.0
from tensorflow import keras
from tensorflow.keras import layers
Google Colab은 이미 설치되어 있어 별도 설치 불필요합니다.
2. 딥러닝 기본 개념 복습
2-1. 뉴런과 레이어 한 줄 요약
입력층 (Input Layer) → 데이터를 받아들이는 문
은닉층 (Hidden Layer) → 패턴을 찾아내는 중간 처리 단계
출력층 (Output Layer) → 최종 결과를 내보내는 문
각 층은 뉴런(노드) 들로 구성되고, 뉴런끼리 가중치(weight) 로 연결됩니다. 학습이란 이 가중치를 조금씩 조정해 정답에 가까워지는 과정입니다.
2-2. Scikit-learn(4편)과 무엇이 다른가?
| 비교 항목 | Scikit-learn | TensorFlow/Keras |
|---|---|---|
| 방식 | 전통 머신러닝 | 딥러닝 (신경망) |
| 데이터 크기 | 소~중형 | 대형 |
| 특징 추출 | 사람이 직접 | 모델이 자동으로 |
| 학습 시간 | 빠름 | 느림 (GPU 권장) |
| 주요 용도 | 정형 데이터 | 이미지, 텍스트, 음성 |
2-3. 딥러닝이 유리한 상황
- 이미지, 텍스트, 음성처럼 비정형 데이터 를 다룰 때
- 데이터가 수만 건 이상 으로 충분히 많을 때
- 정확도가 최우선이고 학습 시간을 감수할 수 있을 때
반대로 데이터가 적거나 표 형태의 정형 데이터라면 Scikit-learn이 더 빠르고 효율적입니다.
3. Keras로 모델 만드는 방법
3-1. Sequential API
레이어를 순서대로 쌓아 모델을 만드는 방식입니다. 가장 기본적이고 직관적인 방법입니다.
pythonfrom tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Dropout
model = Sequential([
Dense(128, activation="relu", input_shape=(4,)), # 입력층 + 첫 번째 은닉층
Dense(64, activation="relu"), # 두 번째 은닉층
Dense(3, activation="softmax") # 출력층 (클래스 3개)
])
3-2. 주요 레이어 종류
| 레이어 | 역할 | 주로 쓰는 곳 |
|---|---|---|
Dense | 완전 연결층 — 모든 뉴런이 연결 | 기본 분류·회귀 |
Dropout | 뉴런 일부를 랜덤으로 꺼서 과적합 방지 | 모든 모델 |
Flatten | 다차원 배열을 1차원으로 펼침 | 이미지 → Dense 연결 시 |
Conv2D | 이미지의 특징을 추출하는 합성곱층 | 이미지 분류 |
LSTM | 순서가 있는 데이터 처리 | 텍스트, 시계열 |
3-3. 활성화 함수
뉴런의 출력 값을 어떻게 변환할지 결정합니다.
python# ReLU — 은닉층에서 가장 많이 쓰임
Dense(128, activation="relu")
# Sigmoid — 이진 분류 출력층 (0~1 사이 확률)
Dense(1, activation="sigmoid")
# Softmax — 다중 분류 출력층 (확률의 합 = 1)
Dense(10, activation="softmax") # 10개 클래스
3-4. 모델 구조 확인
pythonmodel.summary()
# 출력 예시:
# Layer (type) Output Shape Param #
# ─────────────────────────────────────────────
# dense (Dense) (None, 128) 640
# dense_1 (Dense) (None, 64) 8256
# dense_2 (Dense) (None, 3) 195
# ─────────────────────────────────────────────
# Total params: 9,091
Param #은 이 레이어가 학습해야 할 가중치의 수입니다. 숫자가 클수록 복잡한 모델입니다.
4. 모델 컴파일 & 학습
4-1. 컴파일 설정
모델을 학습하기 전에 "어떻게 학습할지" 를 설정합니다.
pythonmodel.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
4-2. 옵티마이저란?
모델이 오답을 냈을 때 가중치를 어느 방향으로, 얼마나 수정할지 결정합니다.
| 옵티마이저 | 특징 |
|---|---|
adam | 가장 많이 쓰임. 학습률 자동 조정. 입문자 기본값 |
sgd | 가장 기본. 안정적이지만 느림 |
rmsprop | RNN/LSTM에 자주 사용 |
4-3. 손실 함수란?
모델의 예측이 정답과 얼마나 틀렸는지 측정합니다. 이 값을 최소화하는 방향으로 학습합니다.
| 문제 유형 | 손실 함수 |
|---|---|
| 이진 분류 (0 or 1) | binary_crossentropy |
| 다중 분류 (정수 라벨) | sparse_categorical_crossentropy |
| 다중 분류 (원핫 라벨) | categorical_crossentropy |
| 회귀 (숫자 예측) | mse (평균 제곱 오차) |
4-4. 모델 학습
pythonhistory = model.fit(
X_train, y_train,
epochs=50,
batch_size=32,
validation_split=0.2,
verbose=1
)
- epoch — 전체 데이터를 한 번 다 보는 것. 50 epochs = 50번 반복
- batch_size — 한 번에 처리하는 데이터 수. 32 또는 64가 일반적
- validation_split — 과적합 여부를 실시간으로 확인하기 위해 검증 데이터 분리
4-5. 학습 곡선 시각화
pythonimport matplotlib.pyplot as plt
plt.plot(history.history["accuracy"], label="훈련 정확도")
plt.plot(history.history["val_accuracy"], label="검증 정확도", linestyle="--")
plt.title("정확도 변화")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.legend()
plt.grid(True)
plt.show()
plt.plot(history.history["loss"], label="훈련 손실")
plt.plot(history.history["val_loss"], label="검증 손실", linestyle="--")
plt.title("손실 변화")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend()
plt.grid(True)
plt.show()
💡 검증 손실이 다시 올라가기 시작하는 지점 = 과적합 시작. 이 지점에서 학습을 멈추는 것이 이상적입니다.
5. 분류 실습 — 손글씨 숫자 인식 (MNIST)
5-1. MNIST 데이터셋이란?
MNIST 는 0~9까지의 손글씨 숫자 이미지 70,000장으로 구성된 데이터셋입니다. AI 분야에서 "Hello, World!"와 같은 입문 데이터셋으로, 딥러닝 학습에 가장 많이 쓰입니다.
- 훈련 데이터: 60,000장
- 테스트 데이터: 10,000장
- 이미지 크기: 28 × 28 픽셀 (흑백)
- 클래스: 0~9 (총 10개)
5-2. 데이터 전처리
pythonfrom tensorflow.keras.datasets import mnist
(X_train, y_train), (X_test, y_test) = mnist.load_data()
print(X_train.shape) # (60000, 28, 28)
print(y_train.shape) # (60000,)
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2, 5, figsize=(12, 5))
for i, ax in enumerate(axes.flat):
ax.imshow(X_train[i], cmap="gray")
ax.set_title(f"정답: {y_train[i]}")
ax.axis("off")
plt.show()
# 정규화
X_train = X_train / 255.0
X_test = X_test / 255.0
# Flatten
X_train = X_train.reshape(-1, 784)
X_test = X_test.reshape(-1, 784)
print(X_train.shape) # (60000, 784)
5-3. 모델 설계 및 학습
pythonfrom tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Dropout
model = Sequential([
Dense(256, activation="relu", input_shape=(784,)),
Dropout(0.3),
Dense(128, activation="relu"),
Dropout(0.3),
Dense(10, activation="softmax")
])
model.summary()
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
history = model.fit(
X_train, y_train,
epochs=20,
batch_size=64,
validation_split=0.2
)
5-4. 예측 결과 시각화
pythonimport numpy as np
y_pred_proba = model.predict(X_test)
y_pred = np.argmax(y_pred_proba, axis=1)
fig, axes = plt.subplots(2, 5, figsize=(14, 6))
for i, ax in enumerate(axes.flat):
ax.imshow(X_test[i].reshape(28, 28), cmap="gray")
color = "blue" if y_pred[i] == y_test[i] else "red"
ax.set_title(f"예측:{y_pred[i]} / 정답:{y_test[i]}", color=color)
ax.axis("off")
plt.suptitle("파란색: 정답, 빨간색: 오답")
plt.show()
5-5. 정확도 확인
pythontest_loss, test_acc = model.evaluate(X_test, y_test)
print(f"테스트 정확도: {test_acc:.4f}") # 예: 0.9789 (97.89%)
6. 과적합 방지 기법
6-1. 과적합(Overfitting)이란?
모델이 훈련 데이터만 너무 잘 외워서 새로운 데이터에는 성능이 떨어지는 현상 입니다.
훈련 정확도: 99%
테스트 정확도: 72% ← 과적합 발생
6-2. Dropout
학습할 때마다 뉴런의 일부를 랜덤으로 꺼서, 모델이 특정 패턴에만 의존하지 않도록 합니다.
pythonfrom tensorflow.keras.layers import Dropout
Dropout(0.3) # 30%의 뉴런을 랜덤으로 비활성화
# 예측할 때는 모든 뉴런이 다시 켜집니다
6-3. EarlyStopping
검증 손실이 더 이상 개선되지 않으면 학습을 자동으로 멈춥니다.
pythonfrom tensorflow.keras.callbacks import EarlyStopping
early_stop = EarlyStopping(
monitor="val_loss",
patience=5,
restore_best_weights=True
)
history = model.fit(
X_train, y_train,
epochs=100,
validation_split=0.2,
callbacks=[early_stop]
)
print(f"실제 학습된 에폭 수: {len(history.history['loss'])}")
6-4. Dropout + EarlyStopping 적용 전/후 비교
python# 적용 전 — 과적합 발생
# 훈련 정확도: 99.5% 검증 정확도: 82.3%
# 적용 후 — 과적합 억제
# 훈련 정확도: 96.1% 검증 정확도: 95.7%
# → 훈련-검증 격차가 줄어들수록 일반화 성능이 좋아진 것
7. 모델 저장 & 불러오기
7-1. 모델 저장
학습을 마친 모델을 저장해두면 다시 학습할 필요 없이 바로 사용할 수 있습니다.
pythonmodel.save("mnist_model.keras")
7-2. 모델 불러오기
pythonfrom tensorflow.keras.models import load_model
loaded_model = load_model("mnist_model.keras")
y_pred = loaded_model.predict(X_test)
print(f"정확도: {loaded_model.evaluate(X_test, y_test)[1]:.4f}")
7-3. 실무에서 저장이 중요한 이유
- GPU가 있는 서버에서 학습하고, CPU 환경에서 예측만 실행
- 학습에 몇 시간~며칠이 걸리는 모델을 매번 다시 학습할 수 없음
- 여러 버전의 모델을 저장해두고 성능 비교
8. 마무리
8-1. 오늘 배운 것 한눈에 정리
| 개념 | 핵심 내용 |
|---|---|
| Keras | TensorFlow 위에서 모델을 쉽게 설계하는 인터페이스 |
| Sequential API | 레이어를 순서대로 쌓아 모델 구성 |
| compile | 옵티마이저 + 손실 함수 + 평가 지표 설정 |
| fit | epoch, batch_size로 학습 제어 |
| 과적합 방지 | Dropout + EarlyStopping |
| 저장/불러오기 | model.save / load_model |