2. MNIST 이미지를 어느 방향으로든 한 픽셀 이동시킬 수 있는 함수를 만들어보세요. 그런 다음 훈련 세트에 있는 각 이미지에 대해 네 개의 이동된 복사본(방향마다 한 개씩) 을 만들어 훈련 세트에 추가하세요. 마지막으로 이 확장된 데이터셋에서 앞에서 찾은 최선의 모델을 훈련시키고 테스트 세트에서 정확도를 측정해보세요. 모델 성능이 더 높아졌는지 확인해보세요! 인위적으로 훈련 세트를 늘리는 이 기법을 데이터 증식 또는 훈련 세트 확장 이라고 합니다.
#사용할 데이터셋과 모델 임포트
from sklearn.datasets import fetch_openml
from sklearn.model_selection import GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
#넘파이 임포트
import numpy as np
mnist = fetch_openml('mnist_784', version=1, as_frame=False) # as_frame = True 넘파이로 반환
mnist.keys()
#이미지를 동서남북 방향으로 shift 할 scipy 모듈 import
from scipy.ndimage.interpolation import shift
import matplotlib.pyplot as plt
#데이터와 타겟 레이블을 추출
X, y = mnist["data"], mnist["target"]
#데이터 형태 확인
X.shape
# target 레이블 은 문자열이기 때문에 정수로 변환
y = y.astype(np.uint8)
# 59999번 인덱스를 기준으로 훈련 세트와 테스트 세트를 나눔
X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]
#이미지를 reshape 해서 이미지를 dx, dy 만큼 변환한 뒤 원래 형태로 반환하는 함수
def shift_image(image, dx, dy):
image = image.reshape((28,28))
shifted_image = shift(image, [dx, dy], cval = 0)
return shifted_image.reshape([-1])
shift_image 함수에서는 문제에서 요구한 MNIST 이미지를 어떤 방향으로도 이동 시킬 수 있게 만든다. 인자로 이미지, dx, dy 값을 받는다.
함수의 작동은 다음과 같다.
1. image는 일렬로 나열된 784개의 픽셀 값이기 때문에 28, 28 로 reshape 해준다.
2. reshape 한 이미지를 scipy.interpolation 의 shfit 함수를 이용해 이동시킨다.
3. 다시 reshape 를 이용해서 픽셀 값을 일렬로 나열해 준다.
#함수가 잘 작동 하는지 확인하기 위해 이미지를 변형 후 확인해본다.
image = X_train[1000]
shifted_image_right = shift_image(image, 0, 5)
shifted_image_up = shift_image(image, -5, 0)
plt.figure(figsize=(12,3))
plt.subplot(131)
plt.title("Original", fontsize=14)
plt.imshow(image.reshape(28, 28), interpolation="nearest", cmap="Greys")
plt.subplot(132)
plt.title("Shifted right", fontsize=14)
plt.imshow(shifted_image_right.reshape(28, 28), interpolation="nearest", cmap="Greys")
plt.subplot(133)
plt.title("Shifted up", fontsize=14)
plt.imshow(shifted_image_up.reshape(28, 28), interpolation="nearest", cmap="Greys")
plt.show()
1001번째 이미지를 가져와 위에서 만든 shift_image 함수로 오른쪽, 위로 이동시켜 보고 imshow로 나타내 보았다. 이동을 잘 하는 것을 볼 수 있다. 가시성을 위해 5만큼씩 이동을 하였지만, 실제 확장된 데이터에서는 1씩 이동해 원래 데이터셋과 미세하게 다른 데이터셋이 형성됨을 알 수 있다.
#테스트 세트를 새로운 expanded 변수에 복사
X_train_expanded = [image for image in X_train]
y_train_expanded = [label for label in y_train]
새로이 expanded 리스트를 만들어서 원래 테스트 세트의 값들을 복사해 준다.
# for문 사용하여 이미지들을 이동 후 expanded 에 덧붙여준다. 타겟은 변형할 필요 X
for dx, dy in ((0,1), (0,-1), (-1,0), (1,0)):
for image, label in zip(X_train, y_train):
X_train_expanded.append(shift_image(image, dx, dy))
y_train_expanded.append(label)
for문을 사용해서 원래 존재하던 데이터셋의 뒤에 새로이 변환한 이미지들을 append 한다. 이때 zip() 은 내장 함수로 데이터의 짝을 지어 주어 for문에 간편하게 적용하게 해준다. 이미지를 동서남북으로 1씩 이동한 이미지들을 append 하기 때문에 원래 데이터셋의 5배로 데이터가 늘어난다. 따라서 실행시간도 같이 늘어나니 주의.
#최적의 파라미터 값 확인
grid_search.best_params_
#테스트 세트에서의 최고 성적은 대략 97% 의 정확도.
grid_search.best_score_
0.9747666666666668
정확도가 0.3퍼센트 정도 개선되었다. 이제 테스트 세트로 예측을 해보자.,
from sklearn.metrics import accuracy_score
y_pred = grid_search.predict(X_test)
accuracy_score(y_test, y_pred)
0.9763
테스트 세트에서 예측을 해본 결과 0.9714 -> 0.9763 으로 0.5% 정도 개선이 되었다.
한정된 데이터셋을 가지고 있고 추가하기가 어렵다고 가정할 떄 데이터 증식을 통해 모델의 정확도를 더 높일 수 있다는 것을 알아 볼 수 있었다.
https://github.com/chataeg/handson-ML/blob/master/jupyter/examples/Hands_On_ch03_2.ipynb
GitHub - chataeg/handson-ML
Contribute to chataeg/handson-ML development by creating an account on GitHub.
github.com
'프로그래밍 공부 > 핸즈온 머신러닝 2판' 카테고리의 다른 글
[핸즈온 머신러닝 2판] 3장 연습문제 3번 (타이타닉) (0) | 2022.11.10 |
---|---|
[핸즈온 머신러닝 2판] 3장 연습문제 1번 (0) | 2022.10.29 |
[핸즈온 머신러닝 2판] 책의 결과와 실제 실습 결과가 다른 이유 (0) | 2022.10.23 |
[핸즈온 머신러닝 2판] 3장 분류 / 정밀도와 재현율 (0) | 2022.10.23 |
[핸즈온 머신러닝 2판] 2.7 모델 세부 튜닝 (0) | 2022.10.21 |