딥러닝

[딥러닝] 손글씨 이미지 데이터 분류

퓨어맨 2022. 7. 18. 12:48
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# keras에서 지원하는 딥러닝 학습용 손글씨 데이터셋 임포트(국립표준기술원(NIST)의 데이터셋을 수정(Modified)해서 만든 데이터 셋)
from tensorflow.keras.datasets import mnist

data = mnist.load_data()

len(data)

# 데이터가 3차원 배열로 크게는 train, test로 나뉘어져 있고
# 각 train, test 안에 문제와 정답 데이터로 한번 더 나뉘어져 있는 구조
2

 

 

print(len(data[0]))      # train
print(len(data[1]))      # test
print(len(data[0][0]))   # X_train
print(len(data[0][1]))   # y_train
print(len(data[1][0]))   # X_test
print(len(data[1][1]))   # y_test
2
2
60000
60000
10000
10000

 

 

X_train = data[0][0]
y_train = data[0][1]
X_test = data[1][0]
y_test = data[1][1]

# 이미지라는 2차원 데이터를 다루기 때문에 shape의 형태는 3칸이 나오게 됨
# (데이터의 수, 가로픽셀 수, 세로픽셀 수)
print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)
(60000, 28, 28)
(60000,)
(10000, 28, 28)
(10000,)

 

plt.imshow(X_train[59999], cmap='gray');
# imshow : 이미지 데이터를 그림으로 출력해주는 명령
# cmap = 'gray' : 이미지를 흑백으로 출력시켜주는 명령

 

# subplots : 여러개의 그래프를 하나의 공간에 표시해주는 함수
# f : 전체 그래프를 조절하는 변수
# axes : 내부 그래프를 조절하는 변수
f, axes = plt.subplots(2,2) # 가로2개, 세로2개씩 내부 그래프를 표시

# 전체 그래프의 사이즈 설정
f.set_size_inches(8,8)

# 인덱싱으로 내부 그래프에 접근
axes[0][0].imshow(X_train[59999], cmap='gray')
axes[0][1].imshow(X_train[59998], cmap='gray')
axes[1][0].imshow(X_train[59997], cmap='gray')
axes[1][1].imshow(X_train[59996], cmap='gray')

plt.show

 

다중분류 문제에는 정답 데이터를 원핫인코딩 시켜줘야 한다

  • pd.get_dummies : pandas에서 지원해주는 원핫인코딩 명령
  • to_categorical : keras에서 지원해주는 원핫인코딩 명령

- 원핫인코딩을 시켜주는 이유

scikit-learn에서 제공하는 머신러닝 알고리즘은 문자열 값을 입력 값으로 허락하지 않기 때문에 모든 문자열 값들을 숫자형으로 인코딩하는 전처리 작업(Preprocessing) 후에 머신러닝 모델에 학습을 시켜야 한다.

 

from tensorflow.keras.utils import to_categorical

y_train_one_hot = to_categorical(y_train)
y_test_one_hot = to_categorical(y_test)

print(y_train_one_hot.shape)
print(y_test_one_hot.shape)
(60000, 10)
(10000, 10)

 

 

  • 신경망에는 2차원인 이미지데이터를 한번에 넣을 수가 없기 때문에 데이터의 차원을 1차원으로 변경시켜줘야 한다.
# -1의 의미 : 60000을 제외한 나머지 값들을 전부 곱해서 일렬로 펴줌
X_train = X_train.reshape(60000, -1)
X_test = X_test.reshape(10000, -1)

X_train.shape
(60000, 784)

 

 

신경망 구조 설계

  • 입력되는 특성 수 : 784
  • 출력층 활성화함수 : softmax
  • 출력층 뉴런 개수 : 10
  • 손실함수(loss) : categorical_crossentropy
  • 최적화함수 : Adam
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense

model = Sequential()

# 입력층 + 중간층 (X_train의 특성 개수를 입력)
model.add(Dense(500, input_dim=784, activation='relu'))

# 중간층
model.add(Dense(400, activation='relu'))
model.add(Dense(200, activation='relu'))

# 출력층 뉴런의 개수는 원핫인코딩 된 컬럼 개수
model.add(Dense(10, activation='softmax'))

model.summary()
Model: "sequential_6"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_23 (Dense)            (None, 500)               392500    
                                                                 
 dense_24 (Dense)            (None, 400)               200400    
                                                                 
 dense_25 (Dense)            (None, 200)               80200     
                                                                 
 dense_26 (Dense)            (None, 10)                2010      
                                                                 
=================================================================
Total params: 675,110
Trainable params: 675,110
Non-trainable params: 0
_________________________________________________________________

 

 

# 학습 및 평가방법 설정
# categorical_crossentropy : 다중분류에 사용하는 손실함수
model.compile(loss='categorical_crossentropy',
              optimizer='Adam',   # 최적화함수 : 최근에 가장 많이 사용되는 일반적으로 성능이 좋은 최적화함
              metrics=['acc']    # metrics : 평가방법을 설정(분류문제이기 때문에 정확도를 넣어줌)
              )

# 학습
h = model.fit(X_train, y_train_one_hot, epochs=30 , verbose=1)
# verbose : 학습 결과의 출력 형태를 설정하는 명령(0: 출력 x, 1: bar형태(디폴트값), 2:bar가 없는 형태)

plt.figure(figsize=(15,5))

plt.plot(h.history['acc'], label='acc')

plt.legend()
plt.show()

 

 

- 학습중 과대적합을 확인하기 위해 train데이터에서 검증데이터셋을 분리해서 학습시 같이 출력해보기

from sklearn.model_selection import train_test_split

X_train, X_val, y_train_one_hot, y_val_one_hot = train_test_split(X_train,
                                                                  y_train_one_hot,
                                                                  random_state=3
                                                                  )
                                                                  
print(X_train.shape)
print(X_val.shape)              # 검증용 문제
print(y_train_one_hot.shape)
print(y_val_one_hot.shape)      # 검증용 정답
(45000, 784)
(15000, 784)
(45000, 10)
(15000, 10)

 

model1 = Sequential()

# 입력층 + 중간층 (X_train의 특성 개수를 입력)
model1.add(Dense(500, input_dim=784, activation='relu'))

# 중간층
model1.add(Dense(400, activation='relu'))
model1.add(Dense(200, activation='relu'))

# 출력층 뉴런의 개수는 원핫인코딩 된 컬럼 개수
model1.add(Dense(10, activation='softmax'))

model1.summary()
Model: "sequential_8"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_31 (Dense)            (None, 500)               392500    
                                                                 
 dense_32 (Dense)            (None, 400)               200400    
                                                                 
 dense_33 (Dense)            (None, 200)               80200     
                                                                 
 dense_34 (Dense)            (None, 10)                2010      
                                                                 
=================================================================
Total params: 675,110
Trainable params: 675,110
Non-trainable params: 0
_________________________________________________________________

 

 

# 학습 및 평가방법 설정
# categorical_crossentropy : 다중분류에 사용하는 손실함수
model1.compile(loss='categorical_crossentropy',
              optimizer='Adam',   # 최적화함수 : 최근에 가장 많이 사용되는 일반적으로 성능이 좋은 최적화함
              metrics=['acc']    # metrics : 평가방법을 설정(분류문제이기 때문에 정확도를 넣어줌)
              )
              
# 학습
h1 = model1.fit(X_train, y_train_one_hot, 
                epochs=30 , 
                verbose=1,
                # 검증용 데이터셋을 추가해주는 명령
                validation_data=(X_val, y_val_one_hot)
                )
# verbose : 학습 결과의 출력 형태를 설정하는 명령(0: 출력 x, 1: bar형태(디폴트값), 2:bar가 없는 형태)

plt.figure(figsize=(15,5))

# train 데이터
plt.plot(h1.history['acc'],
         label='acc',
         c = 'blue',
         marker = '.'
         )

# val 데이터
plt.plot(h1.history['val_acc'],
         label='val_acc',
         c = 'red',
         marker='.'
         )

plt.xlabel("epochs")
plt.ylabel("accuracy")

plt.legend()
plt.show()

 

model1.evaluate(X_test, y_test_one_hot)
313/313 [==============================] - 1s 3ms/step - loss: 0.2567 - acc: 0.9751
[0.256673663854599, 0.9750999808311462]