기계학습
케라스
이미지 분석
#
Find similar titles
- 최초 작성자
- 최근 업데이트
Structured data
- Category
- Programming
Table of Contents
TensorFlow Tutorial #
텐서플로우(TensorFlow)를 설치한 후 기계학습과 텐서플로우의 기본적인 내용을 연습하는 목적으로 진행하는 튜토리얼이다. 이번 튜토리얼에서는 대량의 이미지를 종류별로 분석하는 방법을 소개하며, 참고로 사용하는 이미지는 아래와 같은 이미지들이다.
(출처 : solarisailab.com)
Minist #
이전에 손글씨를 분석 및 훈련하는 MNIST 튜토리얼이 있다. 본 튜토리얼을 진행하기 전에 MNIST 튜토리얼을 진행하면 기본적인 원리를 이해할 수 있다.
Import Datasets #
우선 설치된 케라스에서 이미지 데이터(datasets)와 필요한 라이브러리(numpy, np_util)를 불러온 후, datasets를 train과 test 변수에 나누어 담는다.
import numpy as np
from keras import datasets
from keras.utils import np_utils
(train_X, train_Y), (test_X, test_Y) = datasets.cifar10.load_data()
그리고 어떤 파일로 구성되어 있는지 확인해본다.
print("type: {}, len: {}, ".format(type(train_X), len(train_X)) )
print("type: {}, len: {}, ".format(type(test_X), len(test_X)) )
- train_X, Y : 5만 개의 ndarray(숫자 배열)
- test_X, Y : 1만 개의 ndarray(숫자 배열)
- train은 훈련용, test는 훈련한 모델을 테스트 목적으로 사용
Pring Images #
어떤 데이터 형태인지 확인 했으니 데이터가 어떤 이미지인지 확인해본다. 그림을 그리기 위해 Matplotlib를 볼러온다.
import matplotlib.pyplot as plt
그리고 이미지 몇 개를 출력해본다.
fig = plt.figure()
plt.subplots_adjust(left=0.1, right=2, top=1.3, bottom=0.1)
for i in range(9):
i += 1
num = '25' + str(i)
num = int(num)
ax = fig.add_subplot(num)
plt.title("train_X[{}] / train_Y[{}]: {}".format(i, i, train_Y[i]) )
plt.imshow(train_X[i])
plt.show()
이미지 출력 결과 다양한 종류의 이미지가 있음을 알 수 있다.
Data Check #
train 데이터에 있는 이미지가 세부적으로 어떤 구조로 되어 있는지 확인한다.
print(train_X.shape)
print(train_Y.shape)
- 출력결과 : (50000, 32, 32, 3) / (50000, 1)
- train_X: 5만 개의 32x32x3의 3차원 배열 / train_Y: 5만 개의 1차원 배열
- 50000, 32, 32, 3 : 32(가로) x 32(세로) x 3(RGB색상)으로 구성된 이미지가 5만 개가 있다는 의미
train_Y는 1차원 숫자 배열로 이루어져 있는데 이미지 종류의 번호를 의미하며 어떤 수들이 있는지 출력해서 확인해본다.
import numpy as np
np.unique(train_Y)
- unique : 중복값을 생략한 값을 출력
- 출력결과 : array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8)
- 0부터 9까지의 숫자로 이루어져 있으며 각 숫자는 특정 종류를 의미
Define Function #
이미지를 기계학습으로 훈련할 수 있도록 데이터를 변환하는 작업을 진행하기 위해 케라스에서 인식할 수 있는 데이터 양식으로 맞추어야 한다. 데이터 전처리를 위해 해당 함수를 만든다.
# 함수형으로 만들어 재사용이 가능하도록 제작
def prepare_classification_data(train_data, test_data):
train_X, train_Y = train_data
test_X, test_Y = test_data
#One-hot Encoding
train_Y = np_utils.to_categorical(train_Y)
test_Y = np_utils.to_categorical(test_Y)
# Reshaping Input Data
m, W, H, C = train_X.shape
train_X = train_X.reshape(-1, W*H*C)
test_X = test_X.reshape(-1, W*H*C)
#Normalization
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler().fit(test_X)
train_X = scaler.transform(train_X)
test_X = scaler.transform(test_X)
return (train_X, train_Y), (test_X, test_Y)
- One-hot Encoding : 이미지 종류를 나타내는 번호에 해당하는 인덱스만 1로 만들고 나머지는 0으로 만듦
- to_categorical : One-hot-encoding으로 만들어주는 함수
- Reshaping Input Data : 3차원 데이터를 1차원으로 변환
- reshape : 데이터의 차원을 변환, 여기서는 3차원을 1차원으로 변환
- reshape 이전에는 32x32x3의 3차원이었지만 이후에는 3072의 1차원 배열
- Normalization : 데이터 정규화 작업
- StandardScaler : 데이터를 0부터 1 사이의 값으로 매칭
- transform : 정규화된 데이터를 변환, 변환된 값을 출력해보면 최소값은 -1.7 최대값은 2.4 정도가 나옴
만든 메소드를 통해 이미지 데이터들을 정규화시켜준다.
train_data, test_data = datasets.cifar10.load_data()
(train_X, train_Y), (test_X, test_Y) = \
prepare_classification_data(train_data, test_data)
- prepare_classification_data(train_data, test_data) : 위에 만든 함수에 train_data, test_data를 입력하여 정규화된 데이터를 출력
정규화 된 데이터를 출력해서 확인한다.
train_X[0], train_Y[0]
- 출력결과 : array([-0.97553309, -1.01870231, -0.87145718, ..., -0.05492909, -0.5482677 , -0.6598775 ]), array([0., 0., 0., 0., 0., 0., 1., 0., 0., 0.]))
- 앞의 배열은 train_X, 뒤의 배열은 train_Y이며 각각 1차원 배열로 변환된 것을 확인 가능
Neural Class #
이제 변환한 데이터를 훈련시킬 신경망 모델을 만들 준비를 한다. 우선 필요한 라이브러리를 불러온다.
from keras.models import Sequential
from keras.layers import Dense
그리고 DNN이라는 이름의 훈련 클래스를 만든다.
class DNN(Sequential):
def __init__(self, input_size, output_size, *num_hidden_nodes):
super().__init__()
num_nodes = (*num_hidden_nodes, output_size)
for idx, num_node in enumerate(num_nodes):
activation = 'relu'
if idx == 0:
self.add(Dense(num_node,
activation=activation,
input_shape=(input_size,)))
else:
if idx == len(num_nodes) - 1:
activation = 'softmax'
self.add(Dense(output_size, activation=activation))
self.compile(loss = 'categorical_crossentropy',
optimizer = 'adam',
metrics = ['accuracy'])
- init : init은 초기화를 의미하며 DNN 클래스 실행 시 해당 내용이 실행
- num_nodes : 신경망의 노드(연결고리)를 명시
- relu : Rectified Liner Unit 정류한 선형유닛, 0 이하의 값은 0으로 처리, 미분 계산이 간단
- softmax : 뉴런의 활성함수로 주로 사용. 학습 결과에서 상과 벌의 개념이 확실
- adam : Adagrad와 RMSProp의 장점을 합침, 안정적으로 최적화 가능
Training #
위의 신경망 모델을 통해 정규화된 이미지 데이터들을 훈련시킨다.
mode = DNN(train_X.shape[1], train_Y.shape[1], 256)
hitory = model2.fit(train_X, train_Y, epochs=10,
batch_size=100, validation_split=0.2)
- epochs=10 : 총 10번 훈련시킴
- batch_size=100 : 한번 훈련 시 100개의 데이터를 사용
- 출력 결과
- Train on 40000 samples, validate on 10000 samples
- Epoch 1/10
- 40000/40000 [==============================] - 16s 404us/step - loss: 2.1015 - acc: 0.3792 - val_loss: 1.8382 - val_acc: 0.4132
- ....
- 최종적으로 정확도 0.6473가 나옴
Evaluate #
훈련 시킨 모델을 테스트 이미지를 가지로 평가해본다.
model.evaluate(test_X, test_Y)
- model : 위에서 훈련시킨 모델을 사용
- evaluate : 테스트 데이터를 가지고 모델을 평가
- 출력 결과 : 10000/10000 [==============================] - 2s 234us/step
Loss Datas #
훈련시킨 결과 중 잘못 예측한 이미지들을 확인하기 위해 분류한다.
target_Y = np.argmax(test_Y, axis=1)
match = predicted_Y == target_Y
wrong_label = np.where(match==False)
plt.show(test_X[wrong_label[0]].reshape(32, 32, 3))
- argmax : 원래 이미지 종류의 숫자를 1차원 배열로 생성
- match : 원래 이미지 종류와 예측 이미지 종류가 맞는지 아닌지 결과를 저장
- 출력 결과 : array([ True, True, False, False, False, True, True, True, True, True])
- wrong_label : match 중에서 False(예측이 틀린 이미지)만 분류
- reshape(32, 32, 3) : 1차원으로 정규화된 값을 원래의 32x32x3의 3차원으로 변환
Check Matching #
원래의 이미지 종류를 불러오기 위해 datasets을 새로 불러와 새로운 변수(test2_origin_Y)에 담는다.
(train_X, train_Y), (test_origin_X, test2_origin_Y) = \
datasets.cifar10.load_data()
- test2_origin_Y : 원래의 이미지의 종류를 의미하는 숫자가 입력
훈련시킨 이미지를 종류에 따라 분류해준다.
from collections import defaultdict
def classify_by_label(target_Y, predicted_Y):
n_classes = len(np.unique(target_Y))
index_for_classes = [defaultdict(list) for _ in \
range(n_classes)]
for idx, (target_y, predicted_y) in \
enumerate(zip(target_Y, predicted_Y)):
if target_y == predicted_y:
key = 'correct'
else:
key = 'wrong'
index_for_classes[target_y][key].append(idx)
return index_for_classes
- n_classes : 이미지 종류의 유니크한 값들만 추출
- defaultdict : 이미지 종류만큼의 데이터를 생성
- target_Y, predicted_Y : 각각 실제 값과 예상 값을 의미
- ket_count : corret는 예측이 맞은 것, wrong은 예측이 틀린 것을 의미
Result #
우선 예측이 맞은 이미지를 모아서 출력하기 위해 matplotlib를 불러와서 이미지를 그려준다.
# 맞은 것들을 출력.
fig = plt.figure()
plt.subplots_adjust(left=0.1, right=2.2, top=1.5, bottom=0.1)
i = 0
for image_idx in index_for_classes[3]['correct'][:9]:
i += 1
num = int('25' + str(i))
ax = fig.add_subplot(num)
plt.title("test_X[{}] / test_Y[{}]: {}"
.format(image_idx, image_idx, test2_origin_Y[image_idx]))
plt.imshow(test_X[image_idx].reshape(32,32,3).sum(axis=2))
plt.show()
- subplots_adjust : 각 그래프 간의 간격을 설정
index_for_classes[3]['correct'][:9]
: 예측이 맞은 3번 종류의 이미지를 9개를 선택- plt.title : 이미지의 타이틀을 설정
- plt.imshow : 이미지를 화면에 그림
- plt.show(): 이미지 출력
출력된 이미지를 확인해보니 3번 종류는 고양이를 의미한다고 알 수 있다. 이번에는 반대로 틀린 이미지들(고양이 이미지지만 다른 종류로 예상한 이미지들)을 출력해 본다.
# 틀린 것들을 출력.
fig = plt.figure()
plt.subplots_adjust(left=0.1, right=2.2, top=1.5, bottom=0.1)
i = 0
for image_idx in index_for_classes[3]['wrong'][:9]:
i += 1
num = int('25' + str(i))
ax = fig.add_subplot(num)
plt.title("{} / predicted: {} / label: {}".format(
image_idx,
predicted_Y[image_idx],
test2_origin_Y[image_idx]
))
plt.imshow(test_X[image_idx].reshape(32,32,3).sum(axis=2))
plt.show()
이상으로 이미지 분석 튜토리얼을 마무리한다.
Suggested Pages #
- 0.025 Overfitting
- 0.025 비지도학습
- 0.025 Classification
- 0.025 Unsupervised learining
- 0.025 Rainforced learning
- 0.025 Optimization
- 0.025 강화학습
- 0.025 Supervised learning
- More suggestions...