관리 메뉴

DeseoDeSeo

[Deep Learning] ex02_손글씨 데이터 분류(다중 분류) 본문

Deep Learning

[Deep Learning] ex02_손글씨 데이터 분류(다중 분류)

deseodeseo 2023. 9. 21. 17:34

 

⛧[출력형태에 따른 unit의 개수 ]⛧

- 회귀: units = 1

- 이진분류 : units = 1

- 다중분류 : units = 클래스의 개수

 

 

⛧[출력 형태에 따른 활성화함수의 종류 ]⛧

- 회귀: linear() ➜ linear값이 dafault항등함수, y=x의 선형 모델을 사용. 선형모델이 예측한 데이터를 그대로 출력. 기본값이라서 적어주지 않ㅎ아도 괜찮다.

-이진분류 : sigmoid ➜ 0~1사이의 확률값으로 출력 받기 위함.

- 다중분류 : softmax ➜ 클래스의 개수만큼 확률값을 출력 ➜ 각각의 확률값의 총합이 1이 되도록 출력.

 

 

➤ 목표

  • 손글씨 데이터를 분류하는 딥러닝 모델을 설계해보자!
  • 다중분류 딥러닝 모델링을 연습해보자

 

기본라이브러리 불러오기
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

 

데이터로딩
☑ keras에서 제공해주는 손글씨 데이터 불러오기
 문제 데이터와 정답 데이터가 나뉘어 제공하고 있음
 훈련용, 테스트용 데이터도 나뉘어 제공.
from tensorflow.keras.datasets import mnist
(X_train, y_train),(X_test,y_test) = mnist.load_data()

 

데이터 크기 확인
print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)
# 훈련용 데이터 6만장, 테스트 데이터 1만장
# 28*28 픽셀
# 픽셀 : 사진의 정보를 가지고 있는 단위(작은 사각형 하나가 1픽셀 )

사진 데이터 확인
#흑백사진
#0~255 검정색의 정도를 숫자로 가진다.
plt.imshow(X_train[1000], cmap='gray')

정답 데이터 확인
np.unique(y_train)

MLP멀티 퍼셉트론 모델링

  • 입력층의 구조, 출력층의 구조 고려
  • 학습 능력을 위한 중간층의 깊이 고려
  • loss, optimizer설정

 

 딥러닝 라이브러리 불러오기
# Dense : 퍼셉트론을 묶음으로 표현하는 클래스
# inputlayer : 입력층을 설정
# Flatten : 2차원의 사진 데이터를 1차원으로 표현하기 위한 클래스.
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, InputLayer, Flatten
# 1. 신경망 설계
# 뼈대
digit_model = Sequential()
# 입력층
digit_model.add(InputLayer (input_shape = (28,28))) # 28*28 의 차원 데이터
# 중간층 (은닉층)
digit_model.add(Flatten()) # 2차원의 사진데이터를 1차원으로 변경 (선형모델을 위한 작업)
digit_model.add(Dense(units = 16, activation = 'sigmoid'))
digit_model.add(Dense(units = 8, activation = 'sigmoid'))
# 출력층
digit_model.add(Dense(units = 10 , activation = 'softmax'))
# 다중분류는 클래스의 개수만큼 선형모델이 필요하다
#softmax: 입력받은 값을 정규화하여 출력값의 총합을 1로 만들어주는 함수.
# 활성화함수: softmax (클래스개수만큼 확률값이 출력 -> 총합 1로 만들어주는 함수)

 

 
2.모델 학습 및 평가 방법 설정
digit_model.compile(loss='categorical_crossentropy',optimizer='SGD', metrics=['accuracy'])
# loss: 오차, 실제값과 예측값의 차이
# 회귀 : mean_squared_error
# 이진분류 : binary_crossentropy
# 다중분류 : categotrocal_crossentropy
정답 데이터의 형태 확인
실제 결과값( 클래스 중 하나를 출력 ➜ 범주형 )
y_train

⛤ 문제발생! ⛤ 
오류확인 ➜ 정답 데이터의 shape가 일치하지 않음
(shape가 다르면 비교X)

# 모델링 :1개와 10개는 비교 불가능임,
➤ 2가지 해결 방법
[방법1]: 정답 데이터를 확률로 변경
[방법2] : loss함수를 변경 ] ➜ keras에서 지원하는 자동으로 정답데이터를 알아서 확률로 계산해주는 방법
[방법1. 정답 데이터를 확률값으로 변경하기]
# 모델의 예측값은 확률값으로 출력/ 정답 데이터는 범주형 데이터비교(loss) 불가
# 우리가 직접 담은 정담 데이터를 범주형에서 확률값으로 변경.

 

from tensorflow.keras.utils import to_categorical
# 범주형 데이터를 확률값으로 변경
# one hot인코딩 하듯이 함.
one_hot_y_train= to_categorical(y_train)

[방법2.loss함수를 'sparse_categoric_croosenthropt'라고 변경
평가를 할때 알아서 확률값으로 계산
스스로 내부에서 범주값을 확값으로 변경하는 작업을 수행 후 loss값 계산
digit_model.compile(loss='sparse_categorical_crossentropy', optimizer='SGD', metrics=['accuracy'])

 

학습 결과 시각화
 loss
val_loss
plt.figure(figsize=(15,5))
plt.plot(h1.history['loss'], label='train_loss')
plt.plot(h1.history['val_loss'], label='test_loss')
plt.legend()
plt.show()
4. 모델 예측 및 평가
digit_model.evaluate(X_test, y_test)

 

직접 작성한 손글씨 숫자 test해보기
 파이썬에서 이미지를 처리하는 라이브러리
import PIL.Image as pimg
img=pimg.open('/content/drive/MyDrive/Colab Notebooks/DeepLearning/data/손글씨/0.png').convert('L')
plt.imshow(img,cmap='gray')

이미지는 그림판에서 픽셀 28*28 설정 후, 검은색 바탕색 + 흰색 글씨 작성 후 PNG파일로 저장함.

전처리
# 이미지 타입을 배열로 반환
img=np.array(img)
img.shape

2차원 ➜ 1차원
test_img=img.reshape(1,28,28,1)
test_img.astype('float32')/255
test_img.shape

 예측
digit_model.predict(test_img)

오차역전파

  • 순전파: 입력 데이터를 입력층에서부터 출력층까지 정방향으로 이동하면서 출력 값을 예측하는 과정(예측, 추론)
  • 역전파:출력층에서 발생한 에러를 입력층 쪽으로 전파시키면서 최적의 결과를 학습해 나가는 과정(학습)

        ➜  relu 사용함.

 

# 1. 신경망 설계
# 뼈대
digit_model=Sequential()
# 입력층
digit_model.add(InputLayer(input_shape=(28,28)))  # 28*28의 차원 데이터
# 중간층(은닉층)
digit_model.add(Flatten()) #2차원의 사진 데이터를 1차원으로 변경(선형모델을 위한 작업)
digit_model.add(Dense(units=16, activation='relu'))
digit_model.add(Dense(units=8, activation = 'relu'))
digit_model.add(Dense(units=32, activation = 'relu'))
digit_model.add(Dense(units=16, activation = 'relu'))
digit_model.add(Dense(units=8, activation = 'relu'))
# 출력층
# 분류
# 다중분류에서는 클래스의 개수만큼 선형모델이 필요함.
# 클래스의 개수 = unit의 개수
digit_model.add(Dense(units= 10, activation='softmax'))
# 활성화함수는 softmax를 사용한다.(클래스개수만큼 확률값이 출력 ➜ 총합을 1로 만들어주는 함수! )
# softmax: 입력받은 값을 정규화하여 출력값의 총합을 1로 만들어주는 함수.