이미지 로딩 중...
AI Generated
2025. 11. 23. · 2 Views
CNN으로 이미지 분류하기 실전 가이드
실제 이미지 데이터로 CNN 모델을 구축하고 학습시키는 방법을 단계별로 배워봅니다. 데이터 전처리부터 모델 평가까지 실무에 바로 적용 가능한 완전한 가이드입니다.
목차
- 이미지 데이터 불러오기와 전처리
- CNN 모델 구조 설계하기
- 모델 컴파일과 학습 설정
- 데이터 증강으로 성능 높이기
- 모델 학습 실행하기
- 모델 평가와 테스트
- 사전 학습된 모델 활용 (Transfer Learning)
- 실시간 예측과 배포
1. 이미지 데이터 불러오기와 전처리
시작하며
여러분이 개와 고양이 사진을 구분하는 AI를 만들고 싶을 때, 가장 먼저 어떻게 시작해야 할지 막막한 적 있나요? 수천 장의 이미지 파일이 폴더에 흩어져 있고, 어떻게 컴퓨터가 이해할 수 있는 형태로 바꿔야 할지 고민되셨을 겁니다.
이런 문제는 실제 이미지 분류 프로젝트를 시작할 때 가장 먼저 마주치는 벽입니다. 이미지는 사람 눈에는 단순히 귀여운 고양이 사진이지만, 컴퓨터에게는 숫자들의 배열일 뿐이죠.
이 숫자들을 적절히 준비하지 않으면 AI 모델이 제대로 학습할 수 없습니다. 바로 이럴 때 필요한 것이 이미지 데이터 전처리입니다.
이미지를 모델이 학습할 수 있는 형태로 변환하고, 크기를 맞추고, 픽셀 값을 정규화하는 과정을 통해 학습의 기초를 다질 수 있습니다.
개요
간단히 말해서, 이미지 데이터 전처리는 사진을 숫자 배열로 바꾸고 AI가 잘 배울 수 있도록 준비하는 과정입니다. 왜 이 과정이 필요한지 실무 관점에서 생각해볼까요?
사진마다 크기가 다르거나, 색상 범위가 다르면 AI는 혼란스러워합니다. 예를 들어, 어떤 사진은 1024x768 크기인데 다른 사진은 640x480이라면, 이를 통일된 형태로 맞춰줘야 모델이 일관되게 학습할 수 있습니다.
전통적인 방법으로는 일일이 이미지 편집 프로그램으로 크기를 조정했다면, 이제는 코드 몇 줄로 수천 장을 자동으로 처리할 수 있습니다. 이 개념의 핵심 특징은 크게 세 가지입니다: 크기 통일(모든 이미지를 같은 크기로), 정규화(픽셀 값을 0-1 사이로), 그리고 배치 처리(여러 이미지를 한꺼번에).
이러한 특징들이 모델 학습 속도와 정확도에 직접적인 영향을 미치기 때문에 매우 중요합니다.
코드 예제
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# 이미지 데이터 전처리 설정
datagen = ImageDataGenerator(
rescale=1./255, # 픽셀 값을 0-1 사이로 정규화
validation_split=0.2 # 20%는 검증용으로 분리
)
# 훈련 데이터 불러오기
train_generator = datagen.flow_from_directory(
'data/images', # 이미지가 있는 폴더
target_size=(224, 224), # 모든 이미지를 224x224로 통일
batch_size=32, # 한 번에 32개씩 처리
class_mode='categorical', # 다중 클래스 분류
subset='training' # 훈련용 데이터
)
설명
이것이 하는 일: 폴더에 저장된 수많은 이미지 파일들을 자동으로 읽어서, CNN 모델이 학습할 수 있는 형태로 변환하는 작업을 수행합니다. 첫 번째로, ImageDataGenerator를 만들 때 rescale=1./255를 설정합니다.
왜 이렇게 하냐고요? 원본 이미지의 픽셀 값은 0부터 255 사이의 숫자인데, 이를 255로 나누면 0부터 1 사이의 작은 숫자가 됩니다.
이렇게 하면 모델이 훨씬 빠르고 안정적으로 학습할 수 있어요. validation_split=0.2는 전체 데이터 중 20%를 검증용으로 따로 떼어놓는다는 의미입니다.
그 다음으로, flow_from_directory를 실행하면서 실제 이미지들을 불러옵니다. target_size=(224, 224)는 모든 이미지를 가로 224픽셀, 세로 224픽셀로 자동 조정한다는 뜻이죠.
원본이 아무리 크거나 작아도 모두 같은 크기로 맞춰집니다. batch_size=32는 한 번에 32장씩 묶어서 처리한다는 의미인데, 이렇게 하면 메모리를 효율적으로 사용할 수 있습니다.
마지막으로, class_mode='categorical'은 고양이, 강아지, 새 같은 여러 카테고리 중 하나로 분류한다는 설정입니다. 폴더 구조만 잘 만들어두면 자동으로 라벨링까지 해주는 게 정말 편리하죠.
여러분이 이 코드를 사용하면 수천 장의 이미지를 일일이 손으로 처리할 필요 없이 자동으로 전처리할 수 있습니다. 실무에서는 시간 절약은 물론이고, 사람이 실수할 여지가 없어져서 데이터 품질도 높아집니다.
게다가 새로운 이미지가 추가되어도 코드는 그대로 사용할 수 있어 유지보수가 쉽습니다.
실전 팁
💡 폴더 구조를 'data/images/cat/', 'data/images/dog/' 형태로 만들면 자동으로 라벨이 지정됩니다. 폴더 이름이 곧 클래스 이름이 되는 거죠.
💡 target_size는 모델 구조에 맞춰야 합니다. VGG16이나 ResNet 같은 유명 모델들은 224x224를 주로 사용하니 이 크기를 기본으로 하세요.
💡 메모리 부족 에러가 나면 batch_size를 16이나 8로 줄여보세요. GPU 메모리에 맞춰 조정하는 게 중요합니다.
💡 실제 학습 전에 train_generator.next()로 데이터 한 배치를 확인해보세요. 이미지가 제대로 로드되는지 미리 체크할 수 있습니다.
💡 데이터 증강(rotation_range, zoom_range 등)은 나중에 추가하세요. 처음엔 기본 전처리만으로 시작하는 게 디버깅하기 쉽습니다.
2. CNN 모델 구조 설계하기
시작하며
여러분이 이미지 분류 모델을 만들려고 할 때, "어떤 레이어를 몇 개나 쌓아야 하지?"라는 의문이 드셨을 겁니다. 너무 단순하면 정확도가 낮고, 너무 복잡하면 학습이 느리고 과적합될 수 있으니까요.
이런 문제는 CNN 설계의 핵심 고민입니다. 합성곱 레이어, 풀링 레이어, 완전연결 레이어를 어떤 순서로 배치하느냐에 따라 모델의 성능이 크게 달라집니다.
처음 시작하는 분들은 어디서부터 손대야 할지 막막하게 느껴지죠. 바로 이럴 때 필요한 것이 검증된 CNN 기본 구조입니다.
간단하지만 효과적인 패턴을 따라가면서, 나중에 여러분의 문제에 맞게 조금씩 수정해나갈 수 있습니다.
개요
간단히 말해서, CNN 모델 구조는 이미지에서 특징을 추출하는 레이어들과 분류를 담당하는 레이어들을 순서대로 쌓아 올린 것입니다. 왜 이런 구조가 필요한지 생각해볼까요?
사람이 사진을 볼 때도 먼저 선, 모서리 같은 단순한 특징을 보고, 그 다음 눈, 코, 귀 같은 복잡한 특징을 인식하고, 최종적으로 "이건 고양이야!"라고 판단하잖아요. CNN도 똑같은 방식으로 작동합니다.
예를 들어, 의료 영상에서 종양을 찾거나, 제품 불량을 검사하는 경우에 이런 단계적 특징 추출이 매우 유용합니다. 전통적인 방법으로는 사람이 직접 특징을 정의했다면, CNN은 데이터로부터 자동으로 최적의 특징을 배웁니다.
이 개념의 핵심 특징은 세 가지입니다: 합성곱 레이어(이미지의 패턴 감지), 풀링 레이어(중요한 특징만 남기고 크기 축소), Dense 레이어(최종 분류 결정). 이러한 레이어들이 협력해서 복잡한 이미지 인식을 가능하게 만듭니다.
각 레이어의 역할을 이해하면 모델을 원하는 대로 커스터마이징할 수 있게 됩니다.
코드 예제
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
# CNN 모델 생성
model = Sequential([
# 첫 번째 합성곱 블록: 기본 특징 추출
Conv2D(32, (3, 3), activation='relu', input_shape=(224, 224, 3)),
MaxPooling2D(2, 2),
# 두 번째 합성곱 블록: 복잡한 특징 추출
Conv2D(64, (3, 3), activation='relu'),
MaxPooling2D(2, 2),
# 세 번째 합성곱 블록: 더 추상적인 특징
Conv2D(128, (3, 3), activation='relu'),
MaxPooling2D(2, 2),
# 분류를 위한 완전연결 레이어
Flatten(), # 2D 특징 맵을 1D로 펼침
Dense(512, activation='relu'), # 특징 조합
Dropout(0.5), # 과적합 방지
Dense(10, activation='softmax') # 10개 클래스 분류
])
설명
이것이 하는 일: 이미지를 입력받아서 여러 단계의 필터를 거쳐 특징을 추출하고, 최종적으로 어떤 카테고리에 속하는지 판단하는 신경망을 만듭니다. 첫 번째로, Conv2D(32, (3, 3))는 32개의 3x3 필터를 사용해서 이미지의 기본적인 패턴(선, 모서리 등)을 찾아냅니다.
input_shape=(224, 224, 3)은 가로 224, 세로 224 픽셀의 컬러(RGB 3채널) 이미지를 받는다는 뜻이죠. activation='relu'는 음수 값을 0으로 만들어 학습을 더 효율적으로 만듭니다.
그 다음 MaxPooling2D(2, 2)는 2x2 영역에서 가장 큰 값만 남기고 나머지를 버려서 이미지 크기를 절반으로 줄입니다. 두 번째와 세 번째 합성곱 블록에서는 필터 개수를 64개, 128개로 늘려갑니다.
왜 늘리냐고요? 앞쪽 레이어는 단순한 특징을, 뒤쪽 레이어는 복잡한 특징을 학습하기 때문에 더 많은 필터가 필요합니다.
예를 들어 처음엔 "직선"을 감지하다가, 나중엔 "눈 모양" 같은 복잡한 패턴을 인식하게 되는 거죠. 마지막으로, Flatten()으로 2차원 특징 맵을 1차원 배열로 펼친 다음, Dense(512)로 이 특징들을 조합합니다.
Dropout(0.5)는 학습할 때 랜덤하게 50%의 뉴런을 꺼서 모델이 특정 패턴에만 의존하지 않도록 만듭니다. 마지막 Dense(10, activation='softmax')는 10개의 클래스별 확률을 계산해서 가장 높은 확률의 클래스를 최종 답으로 내놓습니다.
여러분이 이 모델을 사용하면 이미지 분류의 기본을 탄탄히 다질 수 있습니다. 실무에서는 이 구조를 베이스로 데이터셋에 맞게 레이어를 추가하거나 필터 개수를 조정하면 됩니다.
처음부터 복잡한 구조를 만들기보다, 이렇게 간단한 모델로 시작해서 점차 개선하는 게 좋은 접근법입니다.
실전 팁
💡 필터 개수는 보통 32 → 64 → 128처럼 2배씩 늘립니다. 이 패턴이 대부분의 문제에서 잘 작동합니다.
💡 과적합이 심하면 Dropout 비율을 0.5에서 0.6이나 0.7로 올려보세요. 반대로 학습이 잘 안 되면 0.3으로 낮추세요.
💡 model.summary()로 레이어별 파라미터 개수를 확인하세요. 전체 파라미터가 수백만 개를 넘으면 학습이 느려지니 주의하세요.
💡 클래스가 2개뿐이면 마지막 Dense를 Dense(1, activation='sigmoid')로 바꾸세요. 이진 분류에 더 적합합니다.
💡 BatchNormalization 레이어를 Conv2D 뒤에 추가하면 학습 속도가 빨라집니다. 나중에 모델이 안정되면 시도해보세요.
3. 모델 컴파일과 학습 설정
시작하며
여러분이 모델 구조를 다 만들었는데, "이제 어떻게 학습시키지?"라고 막막해하신 적 있나요? 옵티마이저, 손실 함수, 학습률 같은 용어들이 난무하는데 뭘 선택해야 할지 혼란스러우셨을 겁니다.
이런 문제는 실제로 많은 초보자들이 겪는 어려움입니다. 모델을 잘 만들어도 학습 설정을 잘못하면 절대 좋은 결과를 얻을 수 없습니다.
학습률이 너무 크면 최적점을 지나쳐버리고, 너무 작으면 학습이 너무 느려서 며칠이 걸릴 수도 있죠. 바로 이럴 때 필요한 것이 모델 컴파일입니다.
어떤 방식으로 오차를 계산하고, 어떤 알고리즘으로 가중치를 업데이트할지, 어떤 지표로 성능을 측정할지 결정하는 중요한 단계입니다.
개요
간단히 말해서, 모델 컴파일은 학습의 규칙을 정하는 것입니다. 마치 게임의 난이도와 룰을 설정하는 것과 비슷하죠.
왜 이 과정이 필요한지 실무 관점에서 생각해볼까요? 같은 모델이라도 옵티마이저를 Adam으로 쓰느냐 SGD로 쓰느냐에 따라 정확도가 10% 이상 차이날 수 있습니다.
예를 들어, 의료 영상 분류처럼 정확도가 생명과 직결되는 프로젝트에서는 이런 설정 하나하나가 정말 중요합니다. 전통적인 방법으로는 수동으로 미분을 계산하고 가중치를 업데이트했다면, 이제는 compile() 한 줄로 최신 최적화 알고리즘을 적용할 수 있습니다.
이 개념의 핵심 특징은 세 가지입니다: 옵티마이저(가중치 업데이트 방법), 손실 함수(오차 계산 방법), 메트릭(성능 측정 지표). 이 세 가지를 적절히 조합하면 모델이 효율적으로 학습하면서도 원하는 목표를 달성할 수 있습니다.
특히 옵티마이저 선택은 학습 속도와 최종 성능에 직접적인 영향을 미칩니다.
코드 예제
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
# 모델 컴파일: 학습 방식 설정
model.compile(
optimizer=Adam(learning_rate=0.001), # Adam 옵티마이저, 학습률 0.001
loss='categorical_crossentropy', # 다중 클래스 분류용 손실 함수
metrics=['accuracy'] # 정확도 측정
)
# 조기 종료: 성능 개선이 없으면 학습 중단
early_stop = EarlyStopping(
monitor='val_loss', # 검증 손실 관찰
patience=5, # 5번 연속 개선 없으면 중단
restore_best_weights=True # 가장 좋았던 가중치로 복원
)
# 최적 모델 저장
checkpoint = ModelCheckpoint(
'best_model.h5', # 저장할 파일명
monitor='val_accuracy', # 검증 정확도 기준
save_best_only=True # 가장 좋은 모델만 저장
)
설명
이것이 하는 일: 모델이 학습할 때 사용할 알고리즘과 규칙을 지정하고, 학습 중 발생할 수 있는 문제를 자동으로 관리하는 장치를 설정합니다. 첫 번째로, Adam 옵티마이저는 가장 인기 있는 선택입니다.
왜냐하면 학습률을 자동으로 조정해주기 때문이죠. learning_rate=0.001은 한 번 학습할 때 가중치를 얼마나 크게 바꿀지 결정하는데, 0.001은 안전하면서도 적당한 속도로 학습하는 값입니다.
categorical_crossentropy는 여러 클래스 중 하나를 선택하는 문제에서 사용하는 손실 함수로, 예측이 틀릴수록 큰 벌점을 줍니다. 그 다음으로, EarlyStopping은 정말 똑똑한 기능입니다.
학습하다 보면 어느 순간부터 훈련 데이터에만 과하게 맞춰지고 새로운 데이터에 대한 성능은 떨어지는 과적합이 발생하는데요. monitor='val_loss'는 검증 데이터의 손실을 계속 지켜보다가, patience=5로 설정했으니 5번의 에포크 동안 개선이 없으면 자동으로 학습을 멈춥니다.
restore_best_weights=True 덕분에 학습을 멈출 때 가장 성능이 좋았던 시점의 가중치로 되돌려줍니다. 마지막으로, ModelCheckpoint는 학습 과정에서 최고 성능의 모델을 자동으로 저장합니다.
val_accuracy를 기준으로 삼아서 검증 정확도가 이전 최고 기록을 갱신할 때마다 'best_model.h5' 파일에 저장하죠. save_best_only=True 덕분에 성능이 나쁜 모델은 저장하지 않아 디스크 공간도 절약됩니다.
여러분이 이 설정을 사용하면 학습 중간에 컴퓨터가 꺼지거나 문제가 생겨도 최적의 모델을 안전하게 보관할 수 있습니다. 실무에서는 학습에 몇 시간씩 걸리는 경우가 많은데, 이런 안전장치 없이 학습하다가 마지막에 실패하면 모든 시간이 날아가버립니다.
또한 과적합을 자동으로 감지해서 멈춰주니 밤새 학습시켜놓고 아침에 와서 확인하는 식의 작업도 안심하고 할 수 있습니다.
실전 팁
💡 처음 학습할 때는 learning_rate를 0.001로 시작하세요. 학습이 너무 느리면 0.01로, 너무 불안정하면 0.0001로 조정하세요.
💡 이진 분류(고양이 vs 강아지)면 loss를 'binary_crossentropy'로 바꾸고 마지막 레이어도 sigmoid로 변경해야 합니다.
💡 EarlyStopping의 patience는 데이터셋 크기에 따라 조정하세요. 데이터가 적으면 3, 많으면 10 정도가 적당합니다.
💡 학습 중 val_loss가 계속 올라가는데 train_loss는 내려가면 과적합입니다. Dropout을 늘리거나 데이터 증강을 추가하세요.
💡 metrics에 ['accuracy', 'AUC']처럼 여러 지표를 넣으면 다양한 각도로 성능을 확인할 수 있습니다.
4. 데이터 증강으로 성능 높이기
시작하며
여러분이 고양이 사진 100장으로 모델을 학습시켰는데 정확도가 60%밖에 안 나왔다면, "데이터가 부족한가?"라는 생각이 들 겁니다. 하지만 새로운 사진을 수천 장 모으는 건 시간도 오래 걸리고 비용도 많이 들죠.
이런 문제는 실제 프로젝트에서 가장 흔하게 마주치는 벽입니다. 특히 의료 영상이나 희귀한 제품 불량 같은 경우는 데이터를 구하는 것 자체가 거의 불가능한 경우도 많습니다.
적은 데이터로는 모델이 실제 다양한 상황을 제대로 배울 수 없어서 새로운 이미지가 들어오면 잘못 판단하게 됩니다. 바로 이럴 때 필요한 것이 데이터 증강입니다.
기존 이미지를 회전하고, 확대하고, 뒤집어서 마치 새로운 이미지인 것처럼 만들어 모델이 더 다양한 상황을 경험하게 만들 수 있습니다.
개요
간단히 말해서, 데이터 증강은 한 장의 이미지를 여러 가지 방법으로 변형시켜 학습 데이터를 인위적으로 늘리는 기법입니다. 왜 이 기법이 필요한지 실무 관점에서 생각해볼까요?
고양이 사진이 항상 정면만 보고 있을 수는 없잖아요. 실제로는 옆을 보거나, 뒤집혀 있거나, 일부분만 보이는 경우도 많습니다.
예를 들어, 자율주행차의 표지판 인식 시스템은 비가 오거나, 밤이거나, 표지판이 기울어져 있어도 인식해야 하는데, 데이터 증강으로 이런 다양한 상황을 시뮬레이션할 수 있습니다. 전통적인 방법으로는 사람이 직접 포토샵으로 이미지를 변형했다면, 이제는 코드가 자동으로 무한히 다양한 변형을 만들어냅니다.
이 개념의 핵심 특징은 세 가지입니다: 기하학적 변형(회전, 이동, 확대), 색상 변형(밝기, 대비 조정), 랜덤성(매번 다른 변형 적용). 이러한 특징들이 모델을 실제 환경에 더 강건하게 만들어줍니다.
특히 랜덤성 덕분에 같은 이미지도 매번 조금씩 다르게 보여서 모델이 특정 패턴에 과하게 의존하지 않게 됩니다.
코드 예제
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# 강력한 데이터 증강 설정
train_datagen = ImageDataGenerator(
rescale=1./255, # 정규화는 기본
rotation_range=40, # 최대 40도 회전
width_shift_range=0.2, # 가로로 20% 이동
height_shift_range=0.2, # 세로로 20% 이동
shear_range=0.2, # 전단 변환 (이미지 기울이기)
zoom_range=0.2, # 20% 확대/축소
horizontal_flip=True, # 좌우 반전
fill_mode='nearest', # 빈 공간은 가장 가까운 픽셀로 채움
validation_split=0.2
)
# 검증 데이터는 증강하지 않음 (실제 성능 측정용)
val_datagen = ImageDataGenerator(
rescale=1./255,
validation_split=0.2
)
train_gen = train_datagen.flow_from_directory(
'data/images', target_size=(224, 224), batch_size=32,
class_mode='categorical', subset='training'
)
설명
이것이 하는 일: 매 에포크마다 원본 이미지를 랜덤하게 변형시켜서 모델이 같은 이미지라도 매번 조금씩 다르게 보도록 만들고, 이를 통해 실제 환경의 다양성을 학습하게 합니다. 첫 번째로, rotation_range=40은 이미지를 -40도에서 +40도 사이에서 랜덤하게 회전시킵니다.
고양이가 고개를 갸우뚱하는 것처럼 보이는 사진도 생기는 거죠. width_shift_range=0.2와 height_shift_range=0.2는 이미지를 좌우 또는 상하로 전체 크기의 20%까지 이동시킵니다.
마치 사진을 찍을 때 카메라를 조금 옆으로 옮긴 것 같은 효과입니다. 이렇게 하면 모델이 피사체가 정중앙에 없어도 인식할 수 있게 됩니다.
그 다음으로, shear_range=0.2는 이미지를 평행사변형처럼 비스듬하게 만들고, zoom_range=0.2는 20% 확대하거나 축소합니다. 실제로 카메라가 피사체에 가까이 가거나 멀어지는 상황을 시뮬레이션하는 거죠.
horizontal_flip=True는 특히 강력한데, 좌우를 완전히 뒤집어서 마치 거울에 비친 것 같은 이미지를 만듭니다. 고양이가 왼쪽을 보는 사진을 오른쪽을 보는 것처럼 바꾸는 거예요.
마지막으로, fill_mode='nearest'는 변형 과정에서 생긴 빈 공간을 어떻게 채울지 정하는 건데, 'nearest'는 가장 가까운 픽셀의 색을 복사해서 자연스럽게 채웁니다. 중요한 점은 검증 데이터는 절대 증강하지 않는다는 것입니다.
검증 데이터는 실제 성능을 측정하는 용도니까 원본 그대로 사용해야 정확한 평가가 가능합니다. 여러분이 데이터 증강을 사용하면 100장의 이미지로도 수천 가지 변형을 만들어낼 수 있습니다.
실무에서는 이 기법 하나로 정확도가 10-20% 향상되는 경우가 흔합니다. 특히 데이터가 부족한 프로젝트에서는 필수적인 테크닉이죠.
게다가 모델이 회전이나 이동에 강건해지니 실제 환경에서도 훨씬 안정적으로 작동합니다.
실전 팁
💡 vertical_flip은 신중하게 사용하세요. 고양이는 상하 반전해도 되지만, 숫자나 글자는 상하 반전하면 안 됩니다.
💡 rotation_range는 데이터 특성에 맞춰 조정하세요. 얼굴 인식은 10-20도면 충분하지만, 위성 사진은 180도까지도 가능합니다.
💡 증강이 너무 심하면 원본 이미지의 특징이 사라집니다. 처음엔 보수적으로 시작해서 점차 늘려가세요.
💡 fit() 전에 증강된 샘플 몇 개를 plt.imshow()로 확인해보세요. 이상하게 왜곡된 이미지가 나오면 설정을 줄여야 합니다.
💡 brightness_range=[0.8, 1.2]를 추가하면 조명 변화에도 강건한 모델을 만들 수 있습니다.
5. 모델 학습 실행하기
시작하며
여러분이 모든 준비를 마치고 드디어 "학습 시작!" 버튼을 누르려는데, "몇 에포크를 돌려야 하지? 진행 상황은 어떻게 확인하지?"라는 궁금증이 생기셨을 겁니다.
그냥 학습을 시작했다가 과적합되거나 학습이 덜 된 모델을 얻게 되는 실수를 할 수도 있죠. 이런 문제는 학습 과정을 제대로 모니터링하지 않아서 발생합니다.
학습률이 적절한지, 손실이 줄어들고 있는지, 검증 성능은 어떤지 실시간으로 확인하지 않으면 문제가 생겨도 알 수 없습니다. 몇 시간씩 학습시켜놓고 나서야 잘못됐다는 걸 깨닫는 건 정말 시간 낭비죠.
바로 이럴 때 필요한 것이 체계적인 학습 실행과 모니터링입니다. fit() 메서드로 학습을 시작하고, 콜백으로 진행 상황을 추적하며, 히스토리를 저장해서 나중에 분석할 수 있게 만드는 겁니다.
개요
간단히 말해서, 모델 학습 실행은 준비된 데이터를 모델에 반복적으로 주입하면서 가중치를 최적화하고, 그 과정을 기록하는 것입니다. 왜 이 과정을 신중하게 설정해야 하는지 실무 관점에서 생각해볼까요?
에포크가 너무 적으면 모델이 덜 학습되고, 너무 많으면 과적합됩니다. 예를 들어, 제품 불량 검사 시스템을 만드는데 학습을 대충 하면 불량품을 정상으로 판단하거나 그 반대의 치명적인 실수가 발생할 수 있습니다.
전통적인 방법으로는 손으로 반복문을 작성하고 일일이 가중치를 업데이트했다면, 이제는 fit() 한 줄로 전체 학습 루프를 자동화할 수 있습니다. 이 개념의 핵심 특징은 세 가지입니다: 에포크 설정(전체 데이터를 몇 번 반복), 배치 처리(메모리 효율적 학습), 콜백 활용(자동 모니터링과 제어).
이러한 요소들이 조화롭게 작동하면 안정적이고 효율적인 학습이 가능합니다. 특히 콜백 덕분에 사람이 계속 지켜보지 않아도 자동으로 최적의 시점에 학습을 멈추고 모델을 저장합니다.
코드 예제
# 모델 학습 실행
history = model.fit(
train_gen, # 훈련 데이터 제너레이터
epochs=50, # 최대 50번 반복
validation_data=val_gen, # 검증 데이터
callbacks=[early_stop, checkpoint], # 조기 종료와 모델 저장
verbose=1 # 진행 상황 출력
)
# 학습 결과 시각화
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 4))
# 정확도 그래프
plt.subplot(1, 2, 1)
plt.plot(history.history['accuracy'], label='Train Accuracy')
plt.plot(history.history['val_accuracy'], label='Val Accuracy')
plt.title('Model Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
# 손실 그래프
plt.subplot(1, 2, 2)
plt.plot(history.history['loss'], label='Train Loss')
plt.plot(history.history['val_loss'], label='Val Loss')
plt.title('Model Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.savefig('training_history.png')
설명
이것이 하는 일: 준비된 데이터 제너레이터를 사용해서 모델을 학습시키고, 매 에포크마다 훈련과 검증 성능을 기록하며, 최적의 시점에 자동으로 멈추고 결과를 시각화합니다. 첫 번째로, model.fit()에 train_gen을 넘기면 자동으로 배치 단위로 데이터를 불러와서 학습합니다.
epochs=50은 전체 훈련 데이터를 최대 50번 반복한다는 뜻인데, 실제로는 EarlyStopping 콜백이 더 일찍 멈출 수 있습니다. validation_data=val_gen으로 매 에포크가 끝날 때마다 검증 데이터로 성능을 측정하죠.
callbacks=[early_stop, checkpoint]는 앞서 만든 조기 종료와 모델 저장 기능을 활성화합니다. 그 다음으로, 학습이 끝나면 history 객체에 모든 과정이 기록됩니다.
history.history['accuracy']는 매 에포크의 훈련 정확도 리스트이고, history.history['val_accuracy']는 검증 정확도 리스트입니다. 이 둘을 그래프로 그리면 학습이 잘 되고 있는지 한눈에 볼 수 있습니다.
마지막으로, matplotlib으로 두 개의 서브플롯을 만듭니다. 왼쪽 그래프는 정확도를 보여주는데, 훈련 정확도는 계속 올라가는데 검증 정확도가 내려간다면 과적합의 신호입니다.
오른쪽 그래프는 손실을 보여주는데, 손실이 안정적으로 줄어들면 학습이 잘 되고 있다는 뜻입니다. plt.savefig()로 그래프를 이미지 파일로 저장해두면 나중에 보고서를 작성하거나 팀원과 공유할 때 유용합니다.
여러분이 이 코드를 사용하면 학습 과정을 완전히 자동화하고 결과를 체계적으로 분석할 수 있습니다. 실무에서는 학습에 몇 시간씩 걸리는데, verbose=1 덕분에 진행 상황을 실시간으로 확인하면서 문제가 있으면 즉시 중단할 수 있습니다.
또한 그래프를 보면 모델이 언제 과적합되기 시작했는지, 더 학습이 필요한지 명확히 판단할 수 있어서 다음 실험에 바로 적용할 수 있습니다.
실전 팁
💡 처음엔 epochs를 작게(5-10) 설정해서 빠르게 테스트하세요. 문제가 없으면 그때 늘리세요.
💡 학습 중 Ctrl+C로 중단해도 checkpoint 덕분에 최적 모델은 보존됩니다. 언제든 안심하고 멈출 수 있어요.
💡 validation_data 대신 validation_split=0.2를 써도 되지만, 제너레이터를 쓸 때는 별도로 만드는 게 더 안전합니다.
💡 학습이 너무 느리면 steps_per_epoch를 설정해서 일부 데이터만 사용할 수 있습니다. 실험 단계에서 유용합니다.
💡 그래프에서 훈련 손실과 검증 손실의 간격이 벌어지면 Dropout이나 L2 정규화를 추가하세요.
6. 모델 평가와 테스트
시작하며
여러분이 학습을 끝내고 "정확도 90%다!"라고 기뻐했는데, 실제 현장에 배포했더니 60%밖에 안 나왔다면 정말 당황스러우실 겁니다. "학습할 때는 잘 됐는데 왜 실전에서는 안 되지?"라는 의문이 들죠.
이런 문제는 훈련 데이터와 검증 데이터로만 평가하고, 완전히 새로운 테스트 데이터로 확인하지 않아서 발생합니다. 모델이 훈련 데이터를 외워버렸거나, 검증 데이터에도 간접적으로 과적합되었을 수 있습니다.
실제 성능을 제대로 파악하지 못한 채 배포하면 큰 문제가 생길 수 있죠. 바로 이럴 때 필요한 것이 철저한 모델 평가입니다.
학습에 전혀 사용하지 않은 테스트 데이터로 평가하고, Confusion Matrix나 Classification Report로 세밀하게 분석해야 진짜 성능을 알 수 있습니다.
개요
간단히 말해서, 모델 평가는 학습에 사용하지 않은 완전히 새로운 데이터로 모델의 실제 성능을 측정하는 것입니다. 왜 이 과정이 중요한지 실무 관점에서 생각해볼까요?
의료 영상 진단 시스템이 병원 A의 데이터로는 정확도 95%인데, 병원 B의 데이터로는 70%밖에 안 나온다면 실제로 사용할 수 없습니다. 예를 들어, 암 진단 시스템이 특정 암 종류만 잘 찾고 다른 종류는 놓친다면, 전체 정확도가 높아도 의미가 없죠.
전통적인 방법으로는 정확도 하나만 봤다면, 이제는 Precision, Recall, F1-Score 같은 다양한 지표로 세밀하게 분석합니다. 이 개념의 핵심 특징은 세 가지입니다: 독립적인 테스트 셋(학습에 미사용), 다각적인 지표(정확도 외 여러 측정), Confusion Matrix(어떤 클래스를 헷갈리는지 확인).
이러한 분석을 통해 모델의 강점과 약점을 명확히 파악하고, 개선 방향을 찾을 수 있습니다. 특히 클래스별 성능 차이를 발견하면 데이터 불균형 문제를 해결하거나 특정 클래스에 집중할 수 있습니다.
코드 예제
from sklearn.metrics import classification_report, confusion_matrix
import numpy as np
import seaborn as sns
# 테스트 데이터 준비 (증강 없이)
test_datagen = ImageDataGenerator(rescale=1./255)
test_gen = test_datagen.flow_from_directory(
'data/test', # 별도의 테스트 폴더
target_size=(224, 224),
batch_size=32,
class_mode='categorical',
shuffle=False # 순서 유지 (중요!)
)
# 모델 평가
test_loss, test_accuracy = model.evaluate(test_gen)
print(f'Test Accuracy: {test_accuracy:.4f}')
# 예측 수행
predictions = model.predict(test_gen)
predicted_classes = np.argmax(predictions, axis=1)
true_classes = test_gen.classes
# Confusion Matrix 시각화
cm = confusion_matrix(true_classes, predicted_classes)
plt.figure(figsize=(10, 8))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.title('Confusion Matrix')
plt.ylabel('True Label')
plt.xlabel('Predicted Label')
plt.savefig('confusion_matrix.png')
# 상세 리포트
print(classification_report(true_classes, predicted_classes))
설명
이것이 하는 일: 학습에 전혀 사용하지 않은 테스트 데이터로 모델을 평가하고, 단순 정확도를 넘어서 클래스별 성능, 혼동 패턴, 정밀도와 재현율까지 종합적으로 분석합니다. 첫 번째로, 테스트 데이터는 절대 증강하지 않고 rescale만 적용합니다.
shuffle=False가 정말 중요한데, 이걸 True로 하면 예측 결과와 실제 라벨의 순서가 안 맞아서 평가가 엉망이 됩니다. model.evaluate()로 테스트 손실과 정확도를 한 번에 계산하는데, 이게 모델의 실제 성능입니다.
그 다음으로, model.predict()로 모든 테스트 이미지에 대한 예측을 수행합니다. predictions는 클래스별 확률을 담고 있는데, np.argmax()로 가장 확률이 높은 클래스를 추출합니다.
true_classes는 test_gen.classes에서 가져오는데, shuffle=False 덕분에 예측 순서와 정확히 일치합니다. Confusion Matrix는 정말 유용한 도구입니다.
예를 들어 고양이를 강아지로 자주 헷갈린다면, 그 부분의 숫자가 크게 나타납니다. sns.heatmap()으로 시각화하면 어떤 클래스 쌍이 문제인지 한눈에 보입니다.
annot=True는 각 셀에 숫자를 표시하고, fmt='d'는 정수 형식으로 보여줍니다. 마지막으로, classification_report()는 클래스별로 Precision(예측한 것 중 맞은 비율), Recall(실제 정답 중 찾은 비율), F1-Score(두 지표의 조화평균)을 출력합니다.
예를 들어 희귀한 클래스의 Recall이 낮다면 그 클래스의 데이터를 더 모으거나 가중치를 조정해야 합니다. 여러분이 이런 세밀한 평가를 수행하면 모델의 진짜 실력을 정확히 파악할 수 있습니다.
실무에서는 전체 정확도가 높아도 특정 중요한 클래스의 성능이 낮으면 사용할 수 없는 경우가 많습니다. 예를 들어 불량품 검사에서 불량을 정상으로 판단하는 실수는 치명적이니, Confusion Matrix를 보고 그런 오류가 많은지 확인해야 합니다.
이런 분석을 통해 어디를 개선해야 할지 명확히 알 수 있습니다.
실전 팁
💡 테스트 데이터는 전체 데이터의 10-20%로 분리하고, 절대 학습에 사용하지 마세요.
💡 Confusion Matrix에서 대각선(정답)은 크고 나머지(오답)는 작을수록 좋습니다. 특정 패턴이 보이면 그 클래스 쌍을 집중 분석하세요.
💡 클래스 불균형이 있으면 정확도보다 F1-Score가 더 중요합니다. 희귀 클래스의 F1이 낮으면 가중치를 조정하세요.
💡 predictions에는 확률이 들어있으니 np.max(predictions, axis=1)로 모델의 확신도를 확인할 수 있습니다. 확신도가 낮은 샘플들을 따로 분석해보세요.
💡 test_gen.filenames로 틀린 샘플의 파일명을 찾아서 직접 확인해보면 왜 틀렸는지 이해할 수 있습니다.
7. 사전 학습된 모델 활용 (Transfer Learning)
시작하며
여러분이 처음부터 모델을 학습시키는데 며칠이 걸리고 정확도도 70%밖에 안 나온다면, "더 나은 방법은 없을까?"라는 생각이 드실 겁니다. 특히 데이터가 수백 장밖에 없는 상황이라면 더욱 답답하죠.
이런 문제는 데이터가 부족하거나 컴퓨팅 자원이 제한적일 때 자주 발생합니다. 대형 모델을 처음부터 학습시키려면 수천만 장의 이미지와 강력한 GPU가 며칠씩 필요한데, 개인이나 작은 팀이 이런 리소스를 갖추기는 거의 불가능합니다.
바로 이럴 때 필요한 것이 Transfer Learning입니다. 구글이나 페이스북 같은 대기업이 이미 수백만 장의 이미지로 학습시킨 모델을 가져와서, 여러분의 데이터에 맞게 마지막 부분만 재학습시키는 겁니다.
마치 영어를 이미 잘하는 사람이 스페인어를 배울 때 문법은 새로 배우되 언어 감각은 활용하는 것과 비슷하죠.
개요
간단히 말해서, Transfer Learning은 ImageNet 같은 거대한 데이터셋으로 미리 학습된 모델의 지식을 가져와서 여러분의 문제에 적용하는 기법입니다. 왜 이 기법이 혁명적인지 실무 관점에서 생각해볼까요?
VGG16이나 ResNet50 같은 모델은 이미 선, 모서리, 질감, 패턴 같은 기본적인 시각 개념을 완벽히 학습했습니다. 예를 들어, 희귀한 식물 종을 분류하는 프로젝트에서도 이런 기본 시각 지식은 그대로 유용하니까, 굳이 처음부터 배울 필요가 없습니다.
전통적인 방법으로는 작은 데이터로 작은 모델을 학습했다면, 이제는 작은 데이터로도 거대하고 강력한 모델을 활용할 수 있습니다. 이 개념의 핵심 특징은 세 가지입니다: 사전 학습된 가중치(검증된 지식), 특징 추출(하위 레이어 동결), Fine-tuning(상위 레이어만 재학습).
이러한 전략을 통해 학습 시간을 10분의 1로 줄이고, 정확도는 10-20% 높일 수 있습니다. 특히 데이터가 적을 때 효과가 극대화됩니다.
코드 예제
from tensorflow.keras.applications import VGG16
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
# ImageNet으로 사전 학습된 VGG16 불러오기
base_model = VGG16(
weights='imagenet', # ImageNet 가중치 사용
include_top=False, # 마지막 분류 레이어 제외
input_shape=(224, 224, 3)
)
# 사전 학습된 레이어 동결 (학습 안 함)
for layer in base_model.layers:
layer.trainable = False
# 새로운 분류 레이어 추가
x = base_model.output
x = GlobalAveragePooling2D()(x) # 특징 맵 평균화
x = Dense(512, activation='relu')(x) # 새로운 Dense 레이어
x = Dropout(0.5)(x)
predictions = Dense(10, activation='softmax')(x) # 10개 클래스
# 최종 모델 생성
model = Model(inputs=base_model.input, outputs=predictions)
# 컴파일 (새 레이어만 학습됨)
model.compile(
optimizer=Adam(learning_rate=0.0001), # 낮은 학습률
loss='categorical_crossentropy',
metrics=['accuracy']
)
설명
이것이 하는 일: 수백만 장의 이미지로 이미 학습된 모델의 지식을 활용하여, 적은 데이터로도 높은 성능을 달성하고 학습 시간을 대폭 단축합니다. 첫 번째로, VGG16을 불러올 때 weights='imagenet'으로 설정하면 ImageNet 데이터셋(1400만 장, 1000개 클래스)으로 학습된 가중치가 자동으로 다운로드됩니다.
include_top=False는 마지막 분류 레이어를 제외한다는 뜻인데, 왜냐하면 ImageNet은 1000개 클래스인데 여러분은 10개만 필요하니까요. 입력 크기는 224x224로 고정됩니다.
그 다음으로, for layer in base_model.layers: layer.trainable = False로 모든 레이어를 동결합니다. 이렇게 하면 학습할 때 이 레이어들의 가중치는 변하지 않고 그대로 유지됩니다.
왜냐하면 이 레이어들은 이미 선, 모서리, 질감 같은 범용적인 시각 특징을 완벽히 학습했으니까요. 이걸 다시 학습시키면 오히려 성능이 나빠질 수 있습니다.
그 다음, base_model.output을 가져와서 새로운 레이어들을 연결합니다. GlobalAveragePooling2D()는 각 특징 맵의 평균을 구해서 차원을 줄이는데, Flatten()보다 파라미터가 적어 과적합을 방지합니다.
Dense(512)는 추출된 특징들을 조합하고, 마지막 Dense(10)은 여러분의 10개 클래스로 분류합니다. 마지막으로, Adam의 learning_rate를 0.0001로 낮게 설정합니다.
왜냐하면 사전 학습된 가중치를 크게 변경하지 않으면서 새 레이어만 조심스럽게 학습하려는 거죠. 학습률이 너무 높으면 사전 학습된 지식이 손상될 수 있습니다.
여러분이 Transfer Learning을 사용하면 수백 장의 데이터로도 90% 이상의 정확도를 달성할 수 있습니다. 실무에서는 새로운 프로젝트를 시작할 때 거의 항상 Transfer Learning으로 시작합니다.
학습 시간이 며칠에서 몇 시간으로 줄어들고, 적은 데이터로도 안정적인 성능을 얻을 수 있기 때문입니다. 특히 스타트업이나 연구 프로젝트에서 빠르게 프로토타입을 만들 때 필수적인 기법입니다.
실전 팁
💡 VGG16 외에도 ResNet50, InceptionV3, MobileNet 등 다양한 모델이 있습니다. MobileNet은 가볍고 빠르니 모바일 앱용으로 좋습니다.
💡 데이터가 충분하면 나중에 일부 상위 레이어를 unfreeze해서 Fine-tuning할 수 있습니다. base_model.layers[-4:].trainable = True 같은 식으로요.
💡 사전 학습된 모델은 224x224 입력이 필수인 경우가 많습니다. 다른 크기를 쓰면 성능이 떨어지니 주의하세요.
💡 GlobalAveragePooling2D 대신 Flatten을 쓸 수도 있지만, 파라미터가 훨씬 많아져서 과적합 위험이 커집니다.
💡 처음 몇 에포크는 새 레이어만 학습하고, 나중에 일부 레이어를 unfreeze해서 전체를 Fine-tuning하는 2단계 전략이 최고 성능을 냅니다.
8. 실시간 예측과 배포
시작하며
여러분이 완벽한 모델을 만들었는데, "이제 실제로 어떻게 사용하지? 웹이나 앱에서 어떻게 불러오지?"라는 궁금증이 생기셨을 겁니다.
학습만 하고 실제로 쓸 수 없다면 무슨 의미가 있을까요? 이런 문제는 많은 초보자들이 마주치는 마지막 벽입니다.
모델을 저장하고, 새로운 이미지를 전처리하고, 예측을 수행하고, 결과를 해석하는 전체 파이프라인을 구축하지 못하면 실무에서 쓸 수 없는 연습용 코드에 불과합니다. 바로 이럴 때 필요한 것이 모델 저장과 실시간 예측 파이프라인입니다.
학습된 모델을 파일로 저장하고, 언제든 불러와서 새로운 이미지를 분류할 수 있게 만드는 겁니다.
개요
간단히 말해서, 실시간 예측은 학습된 모델을 저장한 뒤, 새로운 이미지가 들어오면 즉시 분류 결과를 반환하는 시스템입니다. 왜 이 과정이 중요한지 실무 관점에서 생각해볼까요?
쇼핑몰의 상품 이미지 자동 분류, 의료 영상 실시간 진단, CCTV 영상의 이상 감지 같은 실제 서비스는 모두 실시간 예측이 필요합니다. 예를 들어, 사용자가 사진을 업로드하면 1초 안에 결과를 보여줘야 하는데, 매번 모델을 새로 학습시킬 수는 없잖아요.
전통적인 방법으로는 모델을 pickle로 저장했다면, 이제는 Keras의 .h5나 SavedModel 형식으로 저장해서 어떤 환경에서도 쉽게 불러올 수 있습니다. 이 개념의 핵심 특징은 세 가지입니다: 모델 직렬화(파일로 저장), 이미지 전처리 파이프라인(일관된 입력 형식), 예측 후처리(사람이 이해할 수 있는 형태로 변환).
이러한 요소들이 완벽히 작동해야 실제 서비스에 통합할 수 있습니다. 특히 전처리가 학습할 때와 똑같아야 정확한 예측이 가능합니다.
코드 예제
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing import image
import numpy as np
# 저장된 모델 불러오기
model = load_model('best_model.h5')
# 클래스 이름 정의 (훈련 시 폴더 순서와 동일)
class_names = ['cat', 'dog', 'bird', 'fish', 'horse',
'deer', 'frog', 'ship', 'car', 'airplane']
def predict_image(img_path):
# 이미지 로드 및 전처리
img = image.load_img(img_path, target_size=(224, 224)) # 크기 조정
img_array = image.img_to_array(img) # NumPy 배열로 변환
img_array = np.expand_dims(img_array, axis=0) # 배치 차원 추가
img_array = img_array / 255.0 # 정규화 (학습 시와 동일)
# 예측 수행
predictions = model.predict(img_array)
predicted_class = np.argmax(predictions[0])
confidence = predictions[0][predicted_class]
# 결과 반환
return {
'class': class_names[predicted_class],
'confidence': float(confidence),
'all_probabilities': {class_names[i]: float(predictions[0][i])
for i in range(len(class_names))}
}
# 사용 예시
result = predict_image('new_image.jpg')
print(f"Prediction: {result['class']} ({result['confidence']*100:.2f}%)")
설명
이것이 하는 일: 학습 과정 없이 저장된 모델만으로 새로운 이미지를 받아서 즉시 분류하고, 결과를 사람이 이해할 수 있는 형태로 반환하는 완전한 예측 파이프라인을 구축합니다. 첫 번째로, load_model('best_model.h5')로 학습된 모델을 메모리에 불러옵니다.
이 파일에는 모델 구조와 가중치가 모두 저장되어 있어서 compile()이나 fit() 없이 바로 예측에 사용할 수 있습니다. class_names는 훈련할 때 폴더 이름의 알파벳 순서와 정확히 일치해야 합니다.
그 다음으로, predict_image() 함수 안에서 이미지 전처리를 수행합니다. image.load_img()로 이미지를 불러오면서 target_size=(224, 224)로 학습할 때와 똑같은 크기로 조정합니다.
img_to_array()로 NumPy 배열로 변환하고, expand_dims()로 (224, 224, 3) 형태에 배치 차원을 추가해서 (1, 224, 224, 3)로 만듭니다. 왜냐하면 모델은 배치 형태로만 입력을 받기 때문이죠.
그리고 /255.0으로 정규화하는데, 이게 학습할 때 rescale=1./255와 정확히 같은 처리입니다. model.predict()를 실행하면 10개 클래스에 대한 확률이 담긴 배열이 반환됩니다.
np.argmax()로 가장 확률이 높은 인덱스를 찾고, 그 인덱스로 class_names에서 실제 클래스 이름을 가져옵니다. confidence는 모델이 얼마나 확신하는지 나타내는 값으로, 0.95면 95% 확신한다는 뜻입니다.
마지막으로, 딕셔너리 형태로 결과를 반환합니다. 'class'는 최종 예측 결과, 'confidence'는 확신도, 'all_probabilities'는 모든 클래스에 대한 확률을 담고 있어서 필요하면 상위 3개 예측을 보여주는 식으로 활용할 수 있습니다.
여러분이 이 코드를 사용하면 Flask나 FastAPI 같은 웹 프레임워크에 바로 통합할 수 있습니다. 실무에서는 이 함수를 API 엔드포인트로 만들어서 모바일 앱이나 웹사이트에서 호출하게 만듭니다.
사용자가 사진을 업로드하면 이 함수가 실행되고, JSON 형태로 결과를 반환해서 화면에 표시하는 식이죠. 전처리를 학습 시와 똑같이 했기 때문에 정확도가 유지되고, 확신도까지 보여줘서 사용자가 결과를 신뢰할 수 있습니다.
실전 팁
💡 모델을 한 번만 불러오고 여러 이미지에 재사용하세요. 매번 load_model()하면 속도가 느려집니다.
💡 confidence가 0.5 이하면 "잘 모르겠음"으로 처리하는 임계값을 설정하세요. 실무에서는 확신도 낮은 예측을 사람이 검토하게 만듭니다.
💡 배치 예측이 필요하면 여러 이미지를 한 번에 쌓아서 model.predict()에 넘기세요. 한 장씩보다 훨씬 빠릅니다.
💡 TensorFlow Serving이나 ONNX로 변환하면 추론 속도를 더 높일 수 있습니다. 프로덕션 환경에서 고려해보세요.
💡 이미지가 학습 때와 다른 도메인이면 성능이 떨어집니다. 예를 들어 실제 사진으로 학습했는데 만화 이미지가 들어오면 오류가 날 수 있으니 주의하세요.
댓글 (0)
함께 보면 좋은 카드 뉴스
범주형 변수 시각화 완벽 가이드 Bar Chart와 Count Plot
데이터 분석에서 가장 기본이 되는 범주형 변수 시각화 방법을 알아봅니다. Matplotlib의 Bar Chart부터 Seaborn의 Count Plot까지, 실무에서 바로 활용할 수 있는 시각화 기법을 배워봅니다.
이변량 분석 완벽 가이드: 변수 간 관계 탐색
두 변수 사이의 관계를 분석하는 이변량 분석의 핵심 개념과 기법을 배웁니다. 상관관계, 산점도, 교차분석 등 데이터 분석의 필수 도구들을 실습과 함께 익혀봅시다.
단변량 분석 분포 시각화 완벽 가이드
데이터 분석의 첫걸음인 단변량 분석과 분포 시각화를 배웁니다. 히스토그램, 박스플롯, 밀도 그래프 등 다양한 시각화 방법을 초보자도 쉽게 이해할 수 있도록 설명합니다.
데이터 타입 변환 및 정규화 완벽 가이드
데이터 분석과 머신러닝에서 가장 기초가 되는 데이터 타입 변환과 정규화 기법을 배워봅니다. 실무에서 자주 마주치는 데이터 전처리 문제를 Python으로 쉽게 해결하는 방법을 알려드립니다.
이상치 탐지 및 처리 완벽 가이드
데이터 속에 숨어있는 이상한 값들을 찾아내고 처리하는 방법을 배워봅니다. 실무에서 자주 마주치는 이상치 문제를 Python으로 해결하는 다양한 기법을 소개합니다.