3. 이미지 분류 · 04 이미지 증식
이미지 증식(shift)

숫자 이미지를 살짝 움직여도 같은 숫자라는 성질을 이용해서 데이터를 늘려보기

무엇을 배울까요?

  • MNIST를 불러오고 학습/테스트로 나누는 흐름
  • shift로 이미지를 상/하/좌/우로 살짝 움직여 데이터 늘리기
  • 증식된 데이터로 간단한 모델(KNN) 성능을 빠르게 확인하기

이해하기 쉬운 예시

  • 숫자 '3' 이미지를 학습했다고 해볼게요. 실제 사진은 조금 위로/아래로/왼쪽/오른쪽으로 삐뚤게 찍히기도 해요. 그래도 사람 눈에는 같은 3이죠. 그래서 이미지를 살짝 이동(shift)시켜서 데이터를 늘리면 모델이 더 튼튼해져요.
01

압축 풀기(데이터 준비)

이 섹션에서 하는 일

데이터가 zip으로 묶여 있으면 먼저 풀어서 쓸 준비를 해요.

코드
import zipfile# zip 파일을 다루는 도구예요
with zipfile.ZipFile('c:/data/mnist/dataset.zip') as zip_ref:# mnist 데이터 zip을 열어요
zip_ref.extractall('c:/data/mnist/')# 지정한 폴더로 전부 풀어요
예상 출력
(출력 없음)
02

MNIST 불러오기(fetch_openml)

이 섹션에서 하는 일

여기서는 MNIST를 가져와서 X(이미지)와 y(정답)를 준비해요.

코드
from sklearn.datasets import fetch_openml# 공개 데이터셋을 쉽게 가져오는 도구예요
mnist = fetch_openml('mnist_784', version=1, data_home='c:/data/mnist', as_frame=False)
# MNIST를 불러와요
mnist.data[:5]# 데이터가 들어왔는지 살짝 확인해요
예상 출력
(출력 없음 또는 일부 데이터가 보임)
03

X, y 만들기 + 모양 확인

이 섹션에서 하는 일

X는 이미지(784 길이), y는 정답(0~9)이에요. 모양(shape)을 먼저 확인해요.

코드
import numpy as np# 배열 계산을 할 거라 numpy를 써요
X, y = mnist["data"], mnist["target"]# 입력(X)과 정답(y)을 꺼내요
y = y.astype(np.int64)# 정답을 숫자형으로 바꿔요
print(X.shape, y.shape)# 전체 개수가 맞는지 확인해요
예상 출력
(70000, 784) (70000,)  (예시)
04

이미지 한 장 보기

이 섹션에서 하는 일

숫자 하나를 실제로 그려보면, 우리가 다루는 게 어떤 데이터인지 감이 와요.

코드
import matplotlib.pyplot as plt# 이미지를 그릴 도구예요
plt.imshow(X[0].reshape(28, 28))# 784를 28x28로 다시 펴서 보여줘요
plt.show()# 화면에 보여줘요
예상 출력
숫자 이미지 1장이 출력됨
05

학습/테스트 나누기 + 섞기

이 섹션에서 하는 일

학습용(앞 60000장)과 테스트용(뒤 10000장)으로 나누고, 학습 데이터는 섞어서 편향을 줄여요.

코드
X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]
# 6만/1만으로 나눠요
shuffle_index = np.random.permutation(60000)# 0~59999를 랜덤 순서로 섞어요
X_train, y_train = X_train[shuffle_index], y_train[shuffle_index]# 그 순서대로 학습 데이터를 섞어요
예상 출력
(출력 없음)
06

shift로 데이터 늘리기 + 간단 분류(KNN)

이 섹션에서 하는 일

이미지를 상/하/좌/우로 살짝 움직여서 데이터 양을 늘리고, KNN으로 간단히 성능을 확인해요.

코드
from scipy.ndimage import shift# 이미지를 이동시키는 도구예요
def shift_image(image, dx, dy):# dx, dy만큼 이동하는 함수를 만들어요
image = image.reshape((28, 28))# 784를 28x28로 바꿔요
shifted_image = shift(image, [dy, dx])# (dy, dx)만큼 이동시켜요
return shifted_image.reshape([-1])# 다시 784 형태로 돌려줘요
image = X_train[70]# 예시 이미지 하나를 잡아요
shifted_image_down = shift_image(image, 0, 5)# 아래로 5칸 이동
shifted_image_left = shift_image(image, -5, 0)# 왼쪽으로 5칸 이동
plt.figure(figsize=(12, 3))# 3장을 한 줄로 보여줄게요
plt.subplot(131); plt.title('Original', fontsize=14); plt.imshow(image.reshape(28, 28), cmap='Greys')
# 원본
plt.subplot(132); plt.title('Shifted down', fontsize=14); plt.imshow(shifted_image_down.reshape(28, 28), cmap='Greys')
# 아래
plt.subplot(133); plt.title('Shifted left', fontsize=14); plt.imshow(shifted_image_left.reshape(28, 28), cmap='Greys')
# 왼쪽
plt.show()# 화면에 표시
# 오래 걸림: 아래는 원본 6만 + 이동 24만 = 총 30만을 만드는 과정이에요
X_train_augmented = [image for image in X_train]# 원본을 먼저 넣어요
y_train_augmented = [label for label in y_train]# 정답도 같이 넣어요
for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1)):# 네 방향 이동을 돌려요
for image, label in zip(X_train, y_train):# 이미지/정답을 같이 순회해요
X_train_augmented.append(shift_image(image, dx, dy))# 이동된 이미지를 추가해요
y_train_augmented.append(label)# 정답은 그대로 추가해요
X_train_augmented = np.array(X_train_augmented)# 리스트를 배열로 바꿔요
y_train_augmented = np.array(y_train_augmented)# 정답도 배열로 바꿔요
shuffle_idx = np.random.permutation(len(X_train_augmented))# 전체를 한 번 더 섞어요
X_train_augmented = X_train_augmented[shuffle_idx]# 섞인 순서로 적용
y_train_augmented = y_train_augmented[shuffle_idx]# 섞인 순서로 적용
from sklearn.neighbors import KNeighborsClassifier# 가까운 이웃으로 분류하는 모델(KNN)
knn_clf = KNeighborsClassifier(n_neighbors=1)# 가장 가까운 1개 이웃을 써요
knn_clf.fit(X_train_augmented[:1000], y_train_augmented[:1000])# 예시는 빠르게 1000개만 학습해요
from sklearn.metrics import accuracy_score# 정확도 계산 도구
y_pred = knn_clf.predict(X_test[:1000])# 테스트 1000개 예측
accuracy_score(y_test[:1000], y_pred[:1000])# 정확도 계산
예상 출력
정확도 숫자(0~1 사이)가 출력됨(예: 0.92)
plot

핵심 한 줄