이미지 로딩 중...
AI Generated
2025. 11. 23. · 0 Views
TensorFlow와 Keras 완벽 입문 가이드
머신러닝과 딥러닝의 세계로 들어가는 첫걸음! TensorFlow와 Keras 프레임워크를 처음 접하는 분들을 위한 친절한 가이드입니다. 실무에서 바로 활용할 수 있는 핵심 개념과 예제를 통해 AI 모델 개발의 기초를 탄탄히 다져보세요.
목차
1. TensorFlow_기본_구조
시작하며
여러분이 처음 머신러닝을 배우려고 할 때 "도대체 어디서부터 시작해야 하지?"라는 막막함을 느낀 적 있나요? 수많은 라이브러리와 프레임워크 중에서 무엇을 선택해야 할지 모르겠고, 설치부터 난관에 부딪히는 경우가 많습니다.
이런 어려움은 초보자들이 흔히 겪는 문제입니다. 특히 TensorFlow는 강력하지만 처음에는 복잡해 보여서 진입장벽이 높게 느껴집니다.
하지만 핵심 개념만 이해하면 생각보다 훨씬 쉽습니다. 바로 이럴 때 필요한 것이 TensorFlow의 기본 구조 이해입니다.
텐서(Tensor)라는 개념만 제대로 알면 나머지는 레고 블록 조립하듯 자연스럽게 따라옵니다.
개요
간단히 말해서, TensorFlow는 구글이 만든 머신러닝 프레임워크로, 텐서(Tensor)라는 다차원 배열을 이용해 계산을 수행합니다. 텐서가 뭔지 어렵게 생각할 필요 없습니다.
숫자 하나는 0차원 텐서(스칼라), 숫자가 일렬로 나열되면 1차원 텐서(벡터), 표 형태면 2차원 텐서(행렬), 그리고 그 이상은 고차원 텐서입니다. 사진 한 장을 생각해보세요.
가로×세로×색상(RGB)으로 3차원 텐서로 표현됩니다. 동영상이라면?
시간이 추가되어 4차원 텐서가 됩니다. 기존에는 NumPy로 배열을 다루고 수동으로 계산했다면, 이제는 TensorFlow가 GPU를 활용해 자동으로 빠르게 계산해줍니다.
TensorFlow의 핵심 특징은 첫째, 자동 미분(Auto Differentiation) - 복잡한 수식의 미분을 자동으로 계산해주고, 둘째, GPU 가속 - 병렬 처리로 엄청난 속도 향상을 제공하며, 셋째, 확장성 - 스마트폰부터 서버 클러스터까지 다양한 환경에서 실행 가능합니다. 이러한 특징들이 실제 머신러닝 모델을 만들 때 개발 시간을 획기적으로 단축시켜줍니다.
코드 예제
import tensorflow as tf
import numpy as np
# 상수 텐서 생성 - 변하지 않는 값
constant_tensor = tf.constant([1, 2, 3, 4, 5])
print(f"상수 텐서: {constant_tensor}")
# 변수 텐서 생성 - 학습 과정에서 값이 변하는 가중치 등에 사용
variable_tensor = tf.Variable([[1.0, 2.0], [3.0, 4.0]])
print(f"변수 텐서:\n{variable_tensor}")
# 텐서 연산 - 덧셈, 곱셈 등
a = tf.constant([[1, 2], [3, 4]])
b = tf.constant([[5, 6], [7, 8]])
result = tf.matmul(a, b) # 행렬 곱셈
print(f"행렬 곱셈 결과:\n{result}")
설명
이것이 하는 일: 위 코드는 TensorFlow의 가장 기본적인 구성 요소인 텐서를 생성하고 연산하는 방법을 보여줍니다. 첫 번째로, tf.constant()는 값이 변하지 않는 상수 텐서를 만듭니다.
머신러닝에서 입력 데이터나 고정된 값을 표현할 때 사용합니다. 리스트나 NumPy 배열을 넣으면 자동으로 TensorFlow 텐서로 변환됩니다.
왜 이렇게 변환할까요? TensorFlow 텐서는 GPU에서 계산할 수 있고, 자동 미분이 가능하기 때문입니다.
그 다음으로, tf.Variable()을 사용하면 학습 과정에서 값이 바뀌는 변수 텐서를 만들 수 있습니다. 신경망의 가중치(weight)와 편향(bias)이 대표적인 예입니다.
모델이 학습하면서 이 값들이 조금씩 조정되어 더 정확한 예측을 할 수 있게 됩니다. 마지막으로, tf.matmul()은 행렬 곱셈을 수행합니다.
신경망에서 입력 데이터와 가중치를 곱하는 핵심 연산입니다. TensorFlow는 이런 연산을 GPU에서 병렬로 처리하여 NumPy보다 수십 배 빠른 속도를 자랑합니다.
여러분이 이 코드를 사용하면 복잡한 수학 연산을 간단한 함수 호출로 처리할 수 있습니다. 특히 대용량 데이터를 다룰 때 GPU 가속의 이점을 체감할 수 있고, 나중에 신경망을 만들 때 이 기본 연산들이 모두 활용됩니다.
실전 팁
💡 텐서의 shape(모양)을 확인하려면 tensor.shape을 사용하세요. 차원이 맞지 않으면 연산 에러가 발생하므로 항상 확인하는 습관을 들이세요.
💡 NumPy 배열을 TensorFlow 텐서로 변환할 때는 tf.convert_to_tensor()를 사용하고, 반대로 텐서를 NumPy로 바꿀 때는 .numpy() 메서드를 사용하세요.
💡 GPU 메모리를 효율적으로 사용하려면 필요한 데이터만 텐서로 변환하고, 불필요한 중간 결과는 바로 삭제하세요.
💡 복잡한 연산을 디버깅할 때는 tf.print()를 사용하면 텐서의 값을 실시간으로 확인할 수 있어 문제를 빠르게 찾을 수 있습니다.
2. Keras_Sequential_모델
시작하며
여러분이 신경망을 처음 만들어보려고 할 때 "레이어를 어떻게 쌓아야 하지? 복잡한 코드를 다 외워야 하나?"라는 걱정이 드나요?
논문에 나오는 수식들을 보면 머리가 아프고, 실제로 코드로 구현하는 것은 더 어렵게 느껴집니다. 이런 어려움은 딥러닝 입문자들의 공통된 고민입니다.
하지만 Keras는 이 모든 복잡함을 숨기고, 레고 블록처럼 레이어를 쌓기만 하면 신경망이 완성되도록 설계되었습니다. 바로 이럴 때 필요한 것이 Keras Sequential 모델입니다.
가장 직관적이고 간단한 방법으로 딥러닝 모델을 만들 수 있습니다.
개요
간단히 말해서, Sequential 모델은 레이어를 순차적으로 쌓아서 신경망을 만드는 가장 간단한 방법입니다. 왜 Sequential이라는 이름일까요?
데이터가 첫 번째 레이어에서 마지막 레이어까지 순서대로 흘러가기 때문입니다. 마치 파이프라인처럼 입력 데이터가 들어가면 각 레이어를 거치면서 변환되고, 최종적으로 예측 결과가 나옵니다.
이미지 분류, 텍스트 분류, 회귀 분석 등 대부분의 기본적인 딥러닝 문제에 사용할 수 있습니다. 기존에는 복잡한 계산 그래프를 직접 정의하고 변수를 관리했다면, 이제는 .add() 메서드로 레이어만 추가하면 됩니다.
Sequential 모델의 핵심 특징은 첫째, 직관적인 구조 - 코드만 봐도 모델의 구조가 한눈에 보이고, 둘째, 간결한 문법 - 몇 줄로 복잡한 신경망을 만들 수 있으며, 셋째, 빠른 프로토타이핑 - 아이디어를 바로 코드로 검증할 수 있습니다. 이러한 특징들이 개발 속도를 극대화하고 실험을 자유롭게 만들어줍니다.
코드 예제
from tensorflow import keras
from tensorflow.keras import layers
# Sequential 모델 생성 - 빈 모델로 시작
model = keras.Sequential()
# 입력 레이어 - 784개의 픽셀을 가진 이미지 (28x28)
model.add(layers.Input(shape=(784,)))
# 은닉 레이어 1 - 128개의 뉴런, ReLU 활성화 함수
model.add(layers.Dense(128, activation='relu'))
# 드롭아웃 - 과적합 방지 (20% 뉴런을 랜덤하게 끔)
model.add(layers.Dropout(0.2))
# 은닉 레이어 2 - 64개의 뉴런
model.add(layers.Dense(64, activation='relu'))
# 출력 레이어 - 10개 클래스 분류 (0~9 숫자)
model.add(layers.Dense(10, activation='softmax'))
# 모델 구조 확인
model.summary()
설명
이것이 하는 일: 위 코드는 손글씨 숫자(0~9)를 분류하는 신경망 모델을 만듭니다. 첫 번째로, keras.Sequential()로 빈 모델을 만들고 여기에 레이어를 하나씩 추가합니다.
Input 레이어는 784개의 값을 받는데, 이는 28×28 픽셀 이미지를 일렬로 펼친 것입니다. 왜 이렇게 펼칠까요?
Dense 레이어는 1차원 데이터만 받을 수 있기 때문입니다. 그 다음으로, Dense 레이어들이 실제 학습을 담당합니다.
첫 번째 Dense(128)는 784개의 입력을 받아 128개의 뉴런으로 압축하고, ReLU 활성화 함수로 비선형성을 추가합니다. 비선형성이 왜 필요할까요?
선형 함수만 쌓으면 아무리 레이어를 많이 쌓아도 결국 하나의 선형 함수와 같기 때문입니다. Dropout 레이어는 학습 시 20%의 뉴런을 랜덤하게 꺼서 과적합을 방지합니다.
마지막으로, 출력 레이어는 10개의 뉴런을 가지며 softmax 활성화 함수를 사용합니다. softmax는 10개의 값을 확률로 변환해주어(합이 1), 각 숫자일 확률을 알려줍니다.
예를 들어 [0.1, 0.05, 0.7, ...] 이런 식으로 나오면 2일 확률이 70%라는 뜻입니다. 여러분이 이 코드를 사용하면 몇 줄만으로 실제 동작하는 신경망을 만들 수 있습니다.
model.summary()로 전체 구조를 확인할 수 있고, 레이어별 파라미터 개수도 볼 수 있어 모델의 복잡도를 파악할 수 있습니다.
실전 팁
💡 레이어 개수와 뉴런 개수는 정답이 없습니다. 작은 모델부터 시작해서 성능이 부족하면 점진적으로 키우세요. 너무 큰 모델은 과적합의 위험이 있습니다.
💡 활성화 함수는 은닉층에는 ReLU, 이진 분류 출력에는 sigmoid, 다중 분류 출력에는 softmax를 주로 사용합니다. 이것만 기억해도 80%는 해결됩니다.
💡 Dropout 비율은 보통 0.2~0.5 사이를 사용합니다. 너무 높으면 모델이 제대로 학습하지 못하고, 너무 낮으면 과적합 방지 효과가 약합니다.
💡 모델 구조를 정의할 때 리스트 형태로 한 번에 정의할 수도 있습니다: Sequential([layer1, layer2, ...])
3. 데이터_전처리
시작하며
여러분이 모델을 학습시키려고 데이터를 넣었는데 "ValueError: 차원이 맞지 않습니다" 같은 에러가 나거나, 학습이 되긴 하는데 정확도가 10%도 안 나오는 상황을 겪어본 적 있나요? 분명 코드는 틀린 게 없는데 결과가 이상합니다.
이런 문제는 데이터 전처리를 제대로 하지 않아서 발생합니다. 신경망은 까다로운 미식가와 같아서, 데이터를 입맛에 맞게 정제해주지 않으면 제대로 학습하지 못합니다.
특히 숫자의 범위가 너무 크거나, 형태가 맞지 않으면 학습이 불안정해집니다. 바로 이럴 때 필요한 것이 올바른 데이터 전처리입니다.
정규화, 리쉐이핑, 원-핫 인코딩 등의 기법으로 데이터를 모델이 이해하기 좋은 형태로 바꿔줍니다.
개요
간단히 말해서, 데이터 전처리는 원본 데이터를 신경망이 학습하기 좋은 형태로 변환하는 과정입니다. 왜 전처리가 중요할까요?
신경망은 보통 01 또는 -11 범위의 숫자를 가장 잘 학습합니다. 만약 어떤 특성은 01 범위인데 다른 특성은 010000 범위라면, 큰 값이 학습을 지배해버려 작은 값의 중요한 정보를 놓치게 됩니다.
또한 이미지 데이터는 (높이, 너비, 채널) 형태여야 하고, 레이블은 원-핫 인코딩으로 바꿔야 하는 등 형태도 맞춰줘야 합니다. 기존에는 데이터를 그대로 넣어서 학습이 느리고 불안정했다면, 이제는 전처리를 통해 빠르고 안정적인 학습이 가능합니다.
데이터 전처리의 핵심 기법은 첫째, 정규화(Normalization) - 값을 01 범위로 조정하여 학습 안정화, 둘째, 리쉐이핑(Reshaping) - 모델 입력 형태에 맞게 차원 변경, 셋째, 원-핫 인코딩(One-hot Encoding) - 범주형 레이블을 벡터로 변환입니다. 이러한 기법들이 모델 성능을 3050% 이상 향상시킬 수 있습니다.
코드 예제
import numpy as np
from tensorflow import keras
# 예시 데이터 로드 - MNIST 손글씨 데이터셋
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
print(f"원본 shape: {x_train.shape}, 값 범위: {x_train.min()}~{x_train.max()}")
# 1. 정규화 - 0~255 범위를 0~1로 변환
x_train = x_train.astype('float32') / 255.0
x_test = x_test.astype('float32') / 255.0
# 2. 리쉐이핑 - (60000, 28, 28)을 (60000, 784)로 펼치기
x_train = x_train.reshape(-1, 784)
x_test = x_test.reshape(-1, 784)
# 3. 원-핫 인코딩 - 레이블 [3]을 [0,0,0,1,0,0,0,0,0,0]로 변환
y_train = keras.utils.to_categorical(y_train, 10)
y_test = keras.utils.to_categorical(y_test, 10)
print(f"전처리 후 shape: {x_train.shape}, 레이블: {y_train.shape}")
설명
이것이 하는 일: 위 코드는 MNIST 손글씨 이미지 데이터를 신경망 학습에 적합한 형태로 변환합니다. 첫 번째로, 정규화 단계에서 픽셀 값을 255로 나눠 0~1 범위로 만듭니다.
왜 255로 나눌까요? 이미지 픽셀은 0(검은색)~255(흰색) 값을 가지기 때문입니다.
astype('float32')로 타입을 바꾸는 이유는 정수를 나누면 소수점이 잘리기 때문에 먼저 실수로 변환합니다. 이 간단한 처리만으로도 학습 속도가 2~3배 빨라집니다.
그 다음으로, 리쉐이핑에서 reshape(-1, 784)를 사용합니다. -1은 "자동으로 계산해줘"라는 의미로, 60000개 샘플이 있으면 자동으로 (60000, 784)가 됩니다.
28×28=784이므로 2차원 이미지를 1차원으로 펼친 것입니다. 왜 펼칠까요?
앞에서 만든 Dense 레이어는 1차원 입력만 받기 때문입니다. CNN을 사용한다면 펼치지 않고 (28, 28, 1) 형태로 유지합니다.
마지막으로, 원-핫 인코딩은 레이블 3을 [0,0,0,1,0,0,0,0,0,0] 형태로 바꿉니다. 왜 이렇게 바꿀까요?
신경망의 출력이 10개의 확률값이므로, 정답도 같은 형태여야 손실을 계산할 수 있기 때문입니다. to_categorical(y, 10)에서 10은 총 클래스 개수입니다.
여러분이 이 전처리 과정을 거치면 모델이 빠르고 정확하게 학습합니다. 특히 정규화를 빼먹으면 학습이 전혀 안 되거나 발산하는 경우가 많으니 절대 생략하지 마세요.
실전 팁
💡 이미지 데이터는 보통 255로 나눠 정규화하지만, 때로는 평균을 빼고 표준편차로 나누는 표준화(Standardization)가 더 좋을 수 있습니다. 실험해보세요.
💡 reshape할 때 -1을 사용하면 실수를 줄일 수 있습니다. 예: reshape(-1, 28, 28, 1) - 첫 차원은 자동 계산
💡 데이터 증강(Data Augmentation)도 전처리의 일종입니다. 이미지를 회전, 이동, 확대하여 학습 데이터를 늘리면 성능이 크게 향상됩니다.
💡 전처리 파이프라인을 함수로 만들어두면 훈련/테스트 데이터에 동일하게 적용할 수 있어 실수를 방지할 수 있습니다.
💡 검증 데이터(validation data)를 분리할 때는 train_test_split() 함수를 사용하거나, fit에서 validation_split=0.2 옵션을 사용하세요.
4. 모델_컴파일
시작하며
여러분이 모델 구조를 다 만들었는데 "이제 뭘 해야 하지?"라고 멈칫한 적 있나요? 모델은 만들었지만 어떻게 학습시켜야 할지, 어떤 설정을 해야 할지 막막합니다.
이런 상황은 모델과 학습 과정 사이의 연결 고리를 모르기 때문입니다. 모델 구조만으로는 학습할 수 없고, "어떻게 학습할지"를 알려줘야 합니다.
손실 함수는 무엇을 사용할지, 최적화 알고리즘은 어떤 것으로 할지 등을 정해야 합니다. 바로 이럴 때 필요한 것이 모델 컴파일입니다.
compile() 메서드로 학습에 필요한 모든 설정을 한 번에 지정합니다.
개요
간단히 말해서, 모델 컴파일은 학습 방법을 설정하는 단계로, 손실 함수, 최적화 알고리즘, 평가 지표를 정의합니다. 왜 컴파일이라는 이름일까요?
프로그래밍에서 컴파일은 "실행 준비를 완료한다"는 의미입니다. 마찬가지로 모델을 학습 가능한 상태로 만드는 것입니다.
손실 함수(Loss Function)는 "모델이 얼마나 틀렸는지"를 측정하고, 옵티마이저(Optimizer)는 "어떻게 개선할지"를 결정하며, 메트릭(Metrics)은 "성능을 어떻게 평가할지"를 정합니다. 기존에는 이런 설정들을 일일이 코드로 구현해야 했다면, 이제는 compile()에 문자열로 지정하기만 하면 됩니다.
모델 컴파일의 핵심 요소는 첫째, 손실 함수 - 회귀는 MSE, 이진 분류는 binary_crossentropy, 다중 분류는 categorical_crossentropy, 둘째, 옵티마이저 - Adam이 가장 무난하고 효과적, 셋째, 메트릭 - 분류는 accuracy, 회귀는 MAE 등을 사용합니다. 이러한 설정들이 모델의 학습 성능과 속도를 결정합니다.
코드 예제
from tensorflow import keras
# 앞에서 만든 모델 사용
model = keras.Sequential([
keras.layers.Input(shape=(784,)),
keras.layers.Dense(128, activation='relu'),
keras.layers.Dropout(0.2),
keras.layers.Dense(10, activation='softmax')
])
# 모델 컴파일 - 학습 준비
model.compile(
# 손실 함수 - 다중 클래스 분류용 (원-핫 인코딩된 레이블)
loss='categorical_crossentropy',
# 옵티마이저 - Adam (학습률 0.001)
optimizer=keras.optimizers.Adam(learning_rate=0.001),
# 평가 지표 - 정확도
metrics=['accuracy']
)
print("모델 컴파일 완료! 이제 학습할 준비가 되었습니다.")
설명
이것이 하는 일: 위 코드는 만들어진 모델에 학습 방법을 설정합니다. 첫 번째로, 손실 함수를 'categorical_crossentropy'로 설정합니다.
이것은 다중 클래스 분류에서 가장 많이 사용되는 손실 함수입니다. 왜 크로스 엔트로피일까요?
예측 확률 분포와 실제 정답 분포의 차이를 효과적으로 측정하기 때문입니다. 만약 레이블이 원-핫 인코딩되지 않고 정수라면 'sparse_categorical_crossentropy'를 사용해야 합니다.
회귀 문제라면 'mse'(평균 제곱 오차)를 사용합니다. 그 다음으로, 옵티마이저는 Adam을 사용합니다.
Adam은 학습률을 자동으로 조절해주는 똑똑한 옵티마이저로, 대부분의 경우 가장 좋은 성능을 보입니다. learning_rate는 한 번에 얼마나 크게 가중치를 업데이트할지 결정합니다.
0.001이 기본값이며, 너무 크면 학습이 불안정하고, 너무 작으면 학습이 느립니다. 더 간단하게 optimizer='adam'처럼 문자열로도 지정할 수 있습니다.
마지막으로, metrics에 'accuracy'를 지정하면 학습 중에 정확도를 확인할 수 있습니다. 손실 함수는 최적화 대상이고, 메트릭은 사람이 이해하기 쉬운 평가 지표입니다.
여러 개를 지정할 수도 있습니다: metrics=['accuracy', 'precision', 'recall'] 여러분이 이 컴파일 과정을 거치면 모델이 학습할 준비가 완전히 끝납니다. 이제 fit() 메서드만 호출하면 학습이 시작됩니다.
실전 팁
💡 손실 함수와 레이블 형태를 맞춰야 합니다. 원-핫 인코딩 → categorical_crossentropy, 정수 레이블 → sparse_categorical_crossentropy
💡 처음에는 기본 Adam 옵티마이저를 사용하고, 성능이 안 나오면 학습률을 조정해보세요. 0.01, 0.001, 0.0001 순으로 실험하는 것이 일반적입니다.
💡 학습 중에 손실은 줄어드는데 정확도가 안 오르면 과적합일 수 있습니다. Dropout을 추가하거나 정규화(L1, L2)를 적용해보세요.
💡 컴파일은 여러 번 할 수 있습니다. 학습 중간에 학습률을 바꾸고 싶으면 다시 컴파일하면 됩니다.
5. 모델_학습
시작하며
여러분이 모델도 만들고 컴파일도 했는데 "이제 진짜 학습은 어떻게 시작하지?"라고 궁금한 적 있나요? 데이터를 넣어서 모델을 훈련시키는 실제 과정이 어떻게 진행되는지 막연합니다.
이런 궁금증은 딥러닝의 핵심인 학습 과정을 아직 경험하지 못했기 때문입니다. 하지만 Keras에서는 단 한 줄, fit() 메서드만 호출하면 모든 학습 과정이 자동으로 진행됩니다.
에포크마다 손실과 정확도가 출력되면서 모델이 점점 똑똑해지는 것을 눈으로 확인할 수 있습니다. 바로 이럴 때 필요한 것이 fit() 메서드입니다.
데이터를 넣고, 에포크 수와 배치 크기를 정하면 학습이 자동으로 진행됩니다.
개요
간단히 말해서, fit() 메서드는 실제로 모델을 학습시키는 함수로, 데이터를 여러 번 반복해서 보여주며 가중치를 업데이트합니다. 왜 fit이라는 이름일까요?
데이터에 모델을 "맞춘다(fit)"는 의미입니다. 에포크(epoch)는 전체 데이터셋을 한 번 다 보는 것을 의미하고, 배치(batch)는 한 번에 처리하는 샘플 개수입니다.
예를 들어 데이터가 1000개이고 배치 크기가 100이면, 1 에포크는 10번의 배치 업데이트로 구성됩니다. 기존에는 반복문을 직접 만들고 경사하강법을 수동으로 구현했다면, 이제는 fit()이 모든 것을 자동으로 처리해줍니다.
fit() 메서드의 핵심 파라미터는 첫째, epochs - 전체 데이터를 몇 번 반복할지 (보통 10100), 둘째, batch_size - 한 번에 몇 개씩 처리할지 (보통 32128), 셋째, validation_data - 검증용 데이터로 과적합 체크입니다. 이러한 설정들이 학습 속도와 최종 성능을 결정합니다.
코드 예제
# 앞에서 전처리한 데이터와 컴파일된 모델 사용
# x_train, y_train은 전처리된 훈련 데이터
# x_test, y_test는 전처리된 테스트 데이터
# 모델 학습 시작
history = model.fit(
x_train, y_train, # 훈련 데이터
epochs=10, # 10번 반복
batch_size=128, # 한 번에 128개씩 처리
validation_split=0.2, # 훈련 데이터의 20%를 검증용으로
verbose=1 # 학습 과정 출력 (1=진행바 표시)
)
# 또는 별도의 검증 데이터 사용
# history = model.fit(
# x_train, y_train,
# epochs=10,
# batch_size=128,
# validation_data=(x_test, y_test) # 테스트 데이터로 검증
# )
print("학습 완료!")
설명
이것이 하는 일: 위 코드는 준비된 데이터로 모델을 실제로 학습시킵니다. 첫 번째로, x_train과 y_train을 넣어주면 모델이 입력과 정답을 보고 패턴을 학습합니다.
epochs=10은 전체 데이터를 10번 반복해서 본다는 뜻입니다. 왜 여러 번 봐야 할까요?
한 번만 보면 충분히 학습되지 않기 때문입니다. 마치 책을 여러 번 읽어야 완전히 이해되는 것과 같습니다.
하지만 너무 많이 반복하면 과적합(overfitting)이 발생할 수 있습니다. 그 다음으로, batch_size=128은 128개씩 묶어서 한 번에 처리한다는 의미입니다.
왜 한 개씩 안 하고 묶어서 할까요? GPU는 병렬 처리에 특화되어 있어서 여러 개를 동시에 처리하는 게 훨씬 빠릅니다.
또한 배치 단위로 평균을 내면 학습이 더 안정적입니다. 배치 크기가 너무 크면 메모리 부족 에러가 날 수 있고, 너무 작으면 학습이 불안정해집니다.
마지막으로, validation_split=0.2는 훈련 데이터의 20%를 검증용으로 분리합니다. 매 에포크마다 훈련 정확도와 검증 정확도를 모두 보여줍니다.
만약 훈련 정확도는 계속 올라가는데 검증 정확도가 떨어지기 시작하면 과적합이 일어나고 있다는 신호입니다. history 객체에는 모든 에포크의 손실과 정확도가 기록되어 나중에 그래프로 그릴 수 있습니다.
여러분이 이 코드를 실행하면 에포크마다 진행 상황이 출력되고, 손실이 줄어들고 정확도가 올라가는 것을 실시간으로 볼 수 있습니다. 보통 10 에포크 정도면 기본적인 학습이 완료됩니다.
실전 팁
💡 학습이 너무 느리면 batch_size를 키워보세요. 64 → 128 → 256으로 늘리면 속도가 빨라집니다. 단, GPU 메모리를 확인하세요.
💡 과적합이 의심되면 epochs를 줄이거나, 검증 손실이 더 이상 개선되지 않을 때 자동으로 멈추는 EarlyStopping 콜백을 사용하세요.
💡 학습 이력(history)을 시각화하면 문제를 쉽게 파악할 수 있습니다: plt.plot(history.history['accuracy'])
💡 GPU를 사용 중이라면 tf.config.list_physical_devices('GPU')로 인식되는지 확인하세요. GPU가 있으면 학습 속도가 10배 이상 빨라집니다.
💡 verbose=0으로 하면 아무것도 출력하지 않고, verbose=2로 하면 에포크당 한 줄만 출력합니다. 대량 실험 시 유용합니다.
6. 모델_평가와_예측
시작하며
여러분이 모델 학습을 끝냈는데 "이 모델이 정말 잘 작동하는지 어떻게 확인하지?"라고 궁금한 적 있나요? 학습 중에 보이는 정확도가 실제 성능을 정확히 반영하는지 확신이 서지 않습니다.
이런 의문은 당연합니다. 학습 데이터로 측정한 성능은 과대평가될 수 있습니다.
모델이 데이터를 '암기'했을 수도 있기 때문입니다. 따라서 학습에 사용하지 않은 새로운 테스트 데이터로 평가해야 진짜 성능을 알 수 있습니다.
바로 이럴 때 필요한 것이 evaluate()와 predict() 메서드입니다. 모델의 실제 성능을 측정하고, 새로운 데이터에 대한 예측을 수행합니다.
개요
간단히 말해서, evaluate()는 모델의 성능을 측정하고, predict()는 실제 예측값을 반환합니다. 왜 두 가지 메서드가 필요할까요?
evaluate()는 정답을 알고 있는 데이터로 손실과 정확도를 계산하여 모델을 평가합니다. 반면 predict()는 정답이 없는 새로운 데이터에 대해 모델의 예측만 얻습니다.
실무에서는 predict()로 실제 서비스에 적용하고, evaluate()로 주기적으로 성능을 모니터링합니다. 기존에는 반복문으로 일일이 예측하고 정확도를 계산했다면, 이제는 한 줄로 모든 평가와 예측이 가능합니다.
핵심 메서드의 특징은 첫째, evaluate() - 손실과 메트릭을 한 번에 계산, 둘째, predict() - 확률값 또는 예측 클래스 반환, 셋째, 배치 처리 - 대량 데이터도 효율적으로 처리입니다. 이러한 기능들이 모델의 실전 활용을 가능하게 합니다.
코드 예제
import numpy as np
# 1. 모델 평가 - 테스트 데이터로 성능 측정
test_loss, test_accuracy = model.evaluate(x_test, y_test, verbose=0)
print(f"테스트 손실: {test_loss:.4f}")
print(f"테스트 정확도: {test_accuracy:.4f} ({test_accuracy*100:.2f}%)")
# 2. 예측 - 확률값 얻기
predictions = model.predict(x_test[:5]) # 처음 5개만 예측
print(f"\n예측 확률 (첫 번째 샘플):\n{predictions[0]}")
# 3. 클래스 번호로 변환 - 가장 높은 확률의 인덱스
predicted_classes = np.argmax(predictions, axis=1)
true_classes = np.argmax(y_test[:5], axis=1)
# 4. 결과 출력
for i in range(5):
print(f"샘플 {i}: 예측={predicted_classes[i]}, 실제={true_classes[i]}")
설명
이것이 하는 일: 위 코드는 학습된 모델의 성능을 평가하고 실제 예측을 수행합니다. 첫 번째로, evaluate()는 테스트 데이터를 넣으면 손실과 정확도를 계산해줍니다.
이것이 모델의 진짜 성능입니다. 학습 중에 본 validation_accuracy가 90%였는데 test_accuracy가 70%라면 과적합이 일어난 것입니다.
verbose=0으로 설정하면 진행 바 없이 결과만 반환합니다. 반환값은 [손실, 메트릭1, 메트릭2, ...] 형태로, compile 시 지정한 순서대로 나옵니다.
그 다음으로, predict()는 각 클래스에 대한 확률을 반환합니다. 10개 클래스라면 [0.05, 0.02, 0.8, ...] 처럼 10개의 확률값이 나옵니다.
합이 1이 되도록 softmax로 변환된 값입니다. x_test[:5]는 처음 5개만 예측하라는 뜻으로, 전체를 예측하려면 x_test만 넣으면 됩니다.
예측은 학습보다 훨씬 빠르게 진행됩니다. 마지막으로, np.argmax(predictions, axis=1)로 가장 높은 확률의 인덱스를 찾습니다.
axis=1은 각 행에서 최댓값을 찾으라는 의미입니다. 예를 들어 [0.05, 0.02, 0.8, ...]에서 2번 인덱스가 0.8로 가장 높으므로 2를 반환합니다.
이것이 모델이 예측한 클래스입니다. true_classes와 비교하여 맞았는지 확인할 수 있습니다.
여러분이 이 코드를 사용하면 모델이 실제로 얼마나 잘 작동하는지 정확히 알 수 있고, 어떤 샘플을 틀리는지 확인하여 모델을 개선할 수 있습니다.
실전 팁
💡 혼동 행렬(Confusion Matrix)을 그려보면 어떤 클래스를 자주 헷갈리는지 한눈에 볼 수 있습니다: sklearn.metrics.confusion_matrix(true, pred)
💡 predict()는 batch_size를 지정할 수 있습니다: predict(x, batch_size=256). 대량 데이터 예측 시 메모리 관리에 유용합니다.
💡 단일 샘플을 예측할 때도 배치 형태로 만들어야 합니다: model.predict(np.expand_dims(single_sample, 0))
💡 예측 시간을 측정하면 실시간 서비스 가능 여부를 판단할 수 있습니다. time.time()으로 전후 시간을 재보세요.
💡 테스트 정확도가 90% 이상이어도 실제 서비스에서는 성능이 떨어질 수 있습니다. 실제 사용자 데이터로 주기적으로 재평가하세요.
7. 콜백_함수
시작하며
여러분이 모델을 학습시키는데 100 에포크 중 50 에포크에서 이미 최고 성능에 도달했는데도 계속 학습하느라 시간을 낭비한 적 있나요? 또는 학습 중간에 가장 좋았던 모델을 놓쳐버려서 나중에 후회한 경험이 있나요?
이런 문제는 학습 과정을 유연하게 제어하지 못해서 발생합니다. 학습을 시작하면 끝날 때까지 기다려야 하고, 중간에 개입할 방법이 없습니다.
시간과 자원이 낭비되고, 최적의 모델을 얻지 못할 수 있습니다. 바로 이럴 때 필요한 것이 콜백(Callback) 함수입니다.
학습 중간중간에 자동으로 실행되어 모델을 저장하거나, 조기 종료하거나, 학습률을 조정하는 등 똑똑한 제어가 가능합니다.
개요
간단히 말해서, 콜백은 학습 과정 중 특정 시점에 자동으로 실행되는 함수로, 학습을 더 효율적이고 똑똑하게 만들어줍니다. 왜 콜백이 필요할까요?
학습은 몇 시간씩 걸릴 수 있는데, 사람이 계속 지켜볼 수는 없습니다. 콜백을 설정해두면 자동으로 최고 성능의 모델을 저장하고, 더 이상 개선이 없으면 학습을 멈추고, 학습이 정체되면 학습률을 낮추는 등의 작업을 자동으로 수행합니다.
마치 자동차의 자동 변속기처럼 상황에 맞게 알아서 조절해줍니다. 기존에는 학습이 끝날 때까지 기다리고 수동으로 확인했다면, 이제는 콜백이 자동으로 최적의 결정을 내려줍니다.
주요 콜백의 종류는 첫째, ModelCheckpoint - 최고 성능 모델 자동 저장, 둘째, EarlyStopping - 개선 없으면 조기 종료, 셋째, ReduceLROnPlateau - 정체 시 학습률 감소입니다. 이러한 콜백들이 학습 시간을 30~50% 단축하고 더 좋은 모델을 얻게 해줍니다.
코드 예제
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau
# 콜백 설정
callbacks = [
# 1. 최고 성능 모델 저장
ModelCheckpoint(
'best_model.h5', # 저장할 파일명
monitor='val_accuracy', # 검증 정확도 관찰
save_best_only=True, # 최고 성능만 저장
mode='max', # 최댓값을 최고로 인정
verbose=1 # 저장 시 메시지 출력
),
# 2. 조기 종료 - 5 에포크 동안 개선 없으면 중단
EarlyStopping(
monitor='val_loss', # 검증 손실 관찰
patience=5, # 5 에포크 참을성
restore_best_weights=True, # 최고 성능 가중치로 복원
verbose=1
),
# 3. 학습률 감소 - 3 에포크 정체 시 학습률 절반으로
ReduceLROnPlateau(
monitor='val_loss',
factor=0.5, # 절반으로 감소
patience=3,
min_lr=1e-7, # 최소 학습률
verbose=1
)
]
# 콜백과 함께 학습
history = model.fit(
x_train, y_train,
epochs=100,
validation_split=0.2,
callbacks=callbacks # 콜백 적용
)
설명
이것이 하는 일: 위 코드는 학습 과정을 자동으로 최적화하는 세 가지 콜백을 설정합니다. 첫 번째로, ModelCheckpoint는 매 에포크마다 검증 정확도(val_accuracy)를 확인하고, 이전보다 좋아지면 모델을 'best_model.h5' 파일로 저장합니다.
save_best_only=True 덕분에 최고 성능일 때만 저장되므로, 나중에 이 파일을 로드하면 가장 좋았던 모델을 얻을 수 있습니다. 왜 중요할까요?
학습 후반부에 과적합으로 성능이 떨어질 수 있는데, 이 콜백이 있으면 과적합 전 최고의 순간을 포착할 수 있습니다. 그 다음으로, EarlyStopping은 검증 손실(val_loss)이 5 에포크 동안 개선되지 않으면 학습을 자동으로 중단합니다.
예를 들어 100 에포크로 설정했지만 30 에포크에서 이미 최적이라면, 35 에포크에서 자동으로 멈춥니다. restore_best_weights=True가 있으면 마지막 가중치가 아닌 최고 성능 시점의 가중치로 되돌립니다.
이것이 시간과 전기를 절약하고 과적합을 방지합니다. 마지막으로, ReduceLROnPlateau는 학습이 정체되면 학습률을 줄입니다.
처음에는 큰 학습률로 빠르게 학습하다가, 나중에는 작은 학습률로 미세 조정하는 효과가 있습니다. 검증 손실이 3 에포크 동안 개선되지 않으면 학습률을 절반(factor=0.5)으로 줄입니다.
이렇게 하면 더 정확한 최적점을 찾을 수 있습니다. 여러분이 이 콜백들을 사용하면 학습을 24시간 돌려놓고 자리를 비워도 안심할 수 있습니다.
자동으로 최적의 결정을 내리고, 불필요한 시간 낭비를 막아줍니다.
실전 팁
💡 EarlyStopping의 patience는 데이터 크기에 따라 조절하세요. 작은 데이터셋은 35, 큰 데이터셋은 1020이 적절합니다.
💡 monitor를 'val_loss'로 할지 'val_accuracy'로 할지는 문제에 따라 다릅니다. 일반적으로 손실이 더 안정적인 지표입니다.
💡 TensorBoard 콜백을 추가하면 학습 과정을 웹 브라우저에서 실시간 그래프로 볼 수 있습니다: keras.callbacks.TensorBoard(log_dir='./logs')
💡 커스텀 콜백을 만들어 특정 조건에서 이메일을 보내거나, 슬랙 메시지를 보내는 등 원하는 동작을 추가할 수 있습니다.
💡 여러 콜백을 동시에 사용할 때는 리스트로 묶어 callbacks 파라미터에 전달하면 됩니다.
8. 모델_저장과_로드
시작하며
여러분이 몇 시간 걸려 학습시킨 모델을 다시 사용하려는데 처음부터 다시 학습해야 한다면 얼마나 답답할까요? 또는 학습한 모델을 실제 서비스에 배포하려는데 어떻게 파일로 저장하고 불러올지 막막한 적 있나요?
이런 문제는 모델 저장과 로드 방법을 모르기 때문입니다. 학습은 시간과 자원이 많이 드는 작업이므로, 한 번 학습한 모델을 저장해두고 필요할 때마다 불러와 사용하는 것이 필수입니다.
특히 실제 서비스에서는 학습 환경과 배포 환경이 다르기 때문에 모델 파일 저장이 필수적입니다. 바로 이럴 때 필요한 것이 save()와 load_model() 메서드입니다.
학습된 모델을 파일로 저장하고, 언제든 다시 불러와 사용할 수 있습니다.
개요
간단히 말해서, save()는 학습된 모델 전체를 파일로 저장하고, load_model()은 저장된 파일에서 모델을 복원합니다. 왜 저장이 중요할까요?
첫째, 학습에는 시간이 오래 걸리지만 저장/로드는 몇 초면 됩니다. 둘째, 다른 사람과 모델을 공유할 수 있습니다.
셋째, 버전 관리가 가능해집니다(v1.h5, v2.h5 등). 넷째, 실제 서비스 배포 시 필수입니다.
Keras는 두 가지 형식을 지원하는데, HDF5 형식(.h5)과 TensorFlow SavedModel 형식입니다. 기존에는 가중치만 따로 저장하고 모델 구조를 코드로 다시 만들어야 했다면, 이제는 한 번에 모든 것(구조, 가중치, 옵티마이저 상태)을 저장하고 불러올 수 있습니다.
모델 저장의 핵심 요소는 첫째, 전체 모델 저장 - 구조와 가중치 모두 포함, 둘째, 가중치만 저장 - 구조는 코드로 재현, 셋째, 체크포인트 - 학습 중간 상태 저장입니다. 이러한 방법들이 유연한 모델 관리를 가능하게 합니다.
코드 예제
from tensorflow import keras
# 1. 학습된 모델 전체 저장 (권장)
model.save('my_model.h5') # HDF5 형식
# 또는
model.save('my_model') # SavedModel 형식 (디렉토리로 저장)
print("모델 저장 완료!")
# 2. 저장된 모델 불러오기
loaded_model = keras.models.load_model('my_model.h5')
print("모델 로드 완료!")
# 3. 불러온 모델로 예측 가능
predictions = loaded_model.predict(x_test[:5])
print(f"예측 결과: {predictions}")
# 4. 가중치만 저장/로드 (모델 구조는 코드로 재현)
model.save_weights('weights_only.h5')
# 새 모델에 가중치 로드
# new_model = create_model() # 같은 구조의 모델 생성
# new_model.load_weights('weights_only.h5')
# 5. JSON으로 모델 구조 저장 (가중치 제외)
model_json = model.to_json()
with open('model_structure.json', 'w') as f:
f.write(model_json)
설명
이것이 하는 일: 위 코드는 학습된 모델을 저장하고 나중에 다시 불러오는 방법을 보여줍니다. 첫 번째로, model.save('my_model.h5')는 모델의 모든 것을 파일에 저장합니다.
여기에는 레이어 구조, 가중치 값, 옵티마이저 상태, 심지어 compile 설정까지 포함됩니다. .h5 확장자는 HDF5 형식을 의미하며, 단일 파일로 저장되어 관리가 쉽습니다.
확장자 없이 저장하면 TensorFlow SavedModel 형식으로 디렉토리가 생성됩니다. SavedModel 형식은 TensorFlow Serving 등 배포 환경에서 더 호환성이 좋습니다.
그 다음으로, keras.models.load_model()로 저장된 파일을 불러오면 학습 직후와 완전히 동일한 상태의 모델을 얻습니다. 다시 compile할 필요도 없고, 바로 predict()나 evaluate()를 호출할 수 있습니다.
만약 추가 학습을 하고 싶다면 fit()도 바로 호출 가능합니다. 마치 저장 시점으로 시간을 되돌린 것처럼 완벽하게 복원됩니다.
마지막으로, 가중치만 저장하는 save_weights()는 파일 크기가 작다는 장점이 있지만, 모델 구조를 코드로 다시 만들어야 하는 번거로움이 있습니다. 보통 전이 학습(Transfer Learning)에서 사전 학습된 가중치를 불러올 때 사용합니다.
to_json()은 모델 구조만 JSON 파일로 저장하는데, 가중치는 포함되지 않으므로 별도로 save_weights()와 함께 사용해야 합니다. 여러분이 이 저장/로드 기능을 활용하면 학습을 한 번만 하고 계속 재사용할 수 있습니다.
또한 여러 버전의 모델을 저장해두고 성능을 비교할 수 있습니다.
실전 팁
💡 실제 서비스에서는 모델 파일과 함께 전처리 파라미터(평균, 표준편차 등)도 저장해야 합니다. pickle을 사용하면 편리합니다.
💡 큰 모델은 파일 크기가 수백 MB~수 GB가 될 수 있습니다. 버전 관리 시스템(Git)에는 올리지 말고 별도로 관리하세요.
💡 커스텀 레이어나 손실 함수를 사용했다면 load_model 시 custom_objects 파라미터로 전달해야 합니다: load_model('model.h5', custom_objects={'MyLayer': MyLayer})
💡 모델 저장 시 파일명에 날짜나 정확도를 포함하면 관리가 쉽습니다: model.save(f'model_{accuracy:.4f}_{date}.h5')
💡 클라우드 환경에서는 S3, GCS 등에 모델을 저장하고 필요할 때 다운로드하는 방식으로 사용합니다.
댓글 (0)
함께 보면 좋은 카드 뉴스
데이터 증강과 정규화 완벽 가이드
머신러닝 모델의 성능을 극대화하는 핵심 기법인 데이터 증강과 정규화에 대해 알아봅니다. 실무에서 바로 활용할 수 있는 다양한 기법과 실전 예제를 통해 과적합을 방지하고 모델 성능을 향상시키는 방법을 배웁니다.
ResNet과 Skip Connection 완벽 가이드
딥러닝 모델이 깊어질수록 성능이 떨어지는 문제를 해결한 혁신적인 기법, ResNet과 Skip Connection을 초급자도 이해할 수 있도록 쉽게 설명합니다. 실제 구현 코드와 함께 배워보세요.
CNN 아키텍처 완벽 가이드 LeNet AlexNet VGGNet
컴퓨터 비전의 기초가 되는 세 가지 핵심 CNN 아키텍처를 배웁니다. 손글씨 인식부터 이미지 분류까지, 딥러닝의 발전 과정을 따라가며 각 모델의 구조와 특징을 실습 코드와 함께 이해합니다.
CNN 기초 Convolution과 Pooling 완벽 가이드
CNN의 핵심인 Convolution과 Pooling을 초급자도 쉽게 이해할 수 있도록 설명합니다. 이미지 인식의 원리부터 실제 코드 구현까지, 실무에서 바로 활용 가능한 내용을 담았습니다.
PyTorch Dataset과 DataLoader 완벽 가이드
딥러닝 모델을 학습시킬 때 데이터를 효율적으로 다루는 방법을 배웁니다. PyTorch의 Dataset과 DataLoader를 사용하여 대용량 데이터를 메모리 효율적으로 처리하고, 배치 처리와 셔플링을 자동화하는 방법을 실무 예제와 함께 알아봅니다.