[머신러닝] 이미지분류 - MNIST

Yungsang Hwang·2022년 5월 17일
0

파이썬 머신러닝

목록 보기
5/7

🥊MNIST 수화 알파벳 데이터셋을 활용하여 이미지 분류 예측모델 만들기

📌주요 달성 과제(이거는 복붙이 아니라 할 줄 알아야 한다!!!)

  1. 학습데이터 x_train 이미지 10개를 출력하는 코드 작성하기
  2. One-hot Encoding 전의 y_train data shape, 후의 y_train data shape 출력하기
  3. 실습한 모델의 구조를 출력하는 코드를 작성하기
  4. 모델 학습할 때 저장된 history로 부터 validation 데이터 정확도를 확인하는 코드를 작성하기. history에 저장된 accuracy 관련 키를 확인하고 리스트로 출력
  5. x축을 각각 epoch로 y축을 training loss, validation loss를 plot으로 그리는 코드를 작성

📌추가 과제

Dropout Layer를 다음 모델 summary 구조로 추가해보기

📌OS 임포트

Kaggle 데이터셋을 가져올 수 있는 환경 설정
Kaggle mypage에서 API 코드 받아오기

import os
os.environ['KAGGLE_USERNAME'] = 'yungsanghwang' # username
os.environ['KAGGLE_KEY'] = 'e57b686e5ced5139126b8cd598b7a958' # key

📌Kaggle 데이터셋 다운로드

Kaggle에서 제공하는 데이터셋을 로컬로 다운로드 하지 않고 API Code를 가져와서 로드하기

Kaggle 데이터셋 압축풀기

!kaggle datasets download -d datamunge/sign-language-mnist

!unzip -q sign-language-mnist

📌패키지 로드

라이브러리 임포트

👁‍🗨tensorflow

  1. keras?
  2. keras.models - Model - 모델설계 라이브러리
  3. keras.layers - Input, Dense - 레이어 라이브러리
  4. keras.optimizers - Adam, SGD : 옵티마이저(값 최소화) 라이브러리

👁‍🗨numpy

  1. numpy?
    모델 학습에 필요한 값은 numpy array 형식으로 선언되어 있어야 작동한다.
    자료를 numpy.array로 변환해줄 라이브러리

👁‍🗨pandas

  1. pandas?
    csv(comma seperated values) 공백으로 나눠져 있는 데이터를 파이썬 환경에서 가시화 해주는 라이브러리

👁‍🗨matplotlib

  1. matplotlib?
    추세가 있는 데이터를 그래프로 만들어 도식화해주는 라이브러리

👁‍🗨sklearn

  1. sklearn?

  2. model_selection - train_test_split
    데이터셋을 train set/validation set 으로 나눠주는 라이브러리

  3. preprocessing - StandardScaler

  4. preprocessing - OneHotEncoder
    출력 값을 컴퓨터가 읽기 편하도록 행렬 형식으로 변환하는 라이브러리. 인덱스 값과 일치하는 매트릭스로 바꿔줌

from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Dense
from tensorflow.keras.optimizers import Adam, SGD
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import OneHotEncoder

📌Pandas를 활용한 csv 데이터 표 보여주기

🚩이 데이터를 어떻게 읽어야 하나?

28*28 크기의 알파벳 사진을 일렬로 나열해 들어있는 픽셀 값을 표시한 것이다.
label은 알파벳에서 어떤 글자에 해당하는지 알려주는 필드

🚩이 데이터를 보고 알아야 할 것은?

일렬로 정렬된 픽셀의 색 값을 통해서 어떤 알파벳인지를 예측해야 하는 모델을 만들어야 한다!
🧐따라서 x값은 색 값, y값은 라벨값이라고 판단하기!

train_df = pd.read_csv('sign_mnist_train.csv')

train_df.head()

test_df = pd.read_csv('sign_mnist_test.csv')

test_df.head()

카운트플롯으로 데이터 도식 확인하기

이 데이터는 뭐하는 건데?

출력값인 라벨값을 기준으로 데이터가 얼마나 들어있는지 확인 할 수 있다.

이 데이터는 왜 보는걸까?

하나의 라벨에는 얼마만큼의 데이터가 들어있으며 대강의 수치를 파악하는데 사용한다고 생각한다

plt.figure(figsize=(16, 10))
sns.countplot(train_df['label'])
plt.show()

📌 학습/테스트 데이터셋 셋업

🚩각 데이터셋에 들어갈 x, y값 선언

x값

입력값 x는 28*28크기 픽셀에 들어있는 색값이 필요하다
라벨 + 색값이 들어있는 train/test table에서 label을 제거한다

y값

출력값 y는 사진의 색값을 모두 취합해 무슨 알파벳인지 알려주기 위한 라벨값이 필요하다
라벨 + 색값이 들어있는 train/test table에서 label만을 가져온다

🚩csv 파일 -> numpy array 선언

데이터 학습 모델을 만들기 위해서는 입출력 값을 numpy array 형태로 만들어줘야 한다.
float32비트 형태로 만드는 작업 또한 필요하다

🚩x, y_train shape 출력하기

x_train.shape

28*28 사진의 색값을 일렬로 정렬한 784개의 열(column)
784개의 열로 구성된 데이터가 27455개의 행(row)이 있음

y_train.shape

사진의 이름을 가리키는 라벨값을 1개의 열(column)
1개의 열로 구성된 데이터가 7172개의 행(row)이 있음

train_df = train_df.astype(np.float32)
x_train = train_df.drop(columns=['label'], axis=1).values
y_train = train_df[['label']].values

test_df = test_df.astype(np.float32)
x_test = test_df.drop(columns=['label'], axis=1).values
y_test = test_df[['label']].values

print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)

📌이미지가 잘 나오는지 그냥 한번 출력해보기

🚩인덱스

몇 번째 이미지 인지 하드로 코딩한 것. 범위 안의 숫자라면 별로 몇 번째 숫자라도 상관없음

🚩plt

👁‍🗨plt.title : 출력 값이 뭔지 이미지 위에 띄워줌

사용하는 값은 y_train

👁‍🗨plt.imshow() : 이미지를 사이즈를 지정해서 보여줌

사용하는 값은 x_train, reshape(size,size)

👁‍🗨plt.show() : 글쎄..? 지정한 plt 값만 지워주던데

index = 1
plt.title(str(y_train[index]))
plt.imshow(x_train[index].reshape((28, 28)), cmap='gray')
plt.show()

🔥 문제 1번.

학습데이터 x_train 이미지 10개를 출력하는 코드 작성하기

for i in range(10):
plt.title(str(y_train[i]))
plt.imshow(x_train[i].reshape((28, 28)), cmap='gray')
plt.show()

🤔 서브플롯을 사용하여 간단하게 이미지보기

plt.subplots를 사용하면 이미지를 정렬하여 작은 화면으로 간단하게 확인할 수 있다!

using subplots

f, ax = plt.subplots(2,5)
f.set_size_inches(10, 10)
k = 0
for i in range(2):
for j in range(5):
ax[i,j].imshow(x_train[k].reshape(28, 28) , cmap = "gray")
k += 1
plt.tight_layout()

🔥 문제2번.

One-hot Encoding 전의 y_train data shape, 후의 y_train data shape 출력하기

📌찍어볼 데이터

y_train.shape (One-hot Encoding 전)

y_train[0].shape

y_train[0]

y_tarin.shape (One-hot Encoding 후)

y_train[0].shape

y_train[0]

🧐 라벨 값의 크기가 하나기 때문에 1

print(y_train.shape)

🧐 라벨 값의 크기가 하나기 때문에 1

print( y_train[0].shape )

🧐 어떤 알파벳인지 라벨의 진짜 값을 보여줌

print( y_train[0])

📌One-hot Encoding

그게 뭔데요

컴퓨터가 값을 잘 알아먹을 수 있도록 행렬의 형태로 인코딩 하는 전처리

실제 라벨의 값이 3이라면 [0.0.0.1.0.0.0.0.0.0...] 이런 식으로 변환해준다!

하는 방법은요

바뀌어야 하는 값은 출력값 y다!
y_train과 y_test 모두 원-핫 인코딩으로 변경해준다
🚩맨뒤에 .toarray() 꼭 넣어주기

encoder = OneHotEncoder()
y_train = encoder.fit_transform(y_train).toarray()
y_test = encoder.fit_transform(y_test).toarray()

🧐 x값의 크기가 24 이기 때문에 1부터 24가 될 수 있도록 y값의 크기가 24의 행렬만큼 커졌다!

print(y_train.shape)

🧐 x값의 크기가 24 이기 때문에 1부터 24가 될 수 있도록 y값의 크기가 24의 행렬만큼 커졌다!

print(y_train[0].shape)

🧐아까 라벨 값이 3이라고 했으니까 그에 맞게 바뀌어진 모습이다!

print(y_train[0])

🤹‍♀️ 255로 나눠주는 이유는?

📌 정규화

정규화를 위해서는 각 데이터들을 해당 데이터 셋이 가질 수 있는 값의 범위로 나눠주면 된다.

X_train의 경우 한 픽셀이 0~255사이의 값을 가질 수 있으므로 255로 나눠준다.

출처 : https://hyjykelly.tistory.com/16

x_train = x_train / 255.
x_test = x_test / 255.

🧐 x데이터는 28*28 크기의 값을 갖는다

print(x_test[0].shape)

🧐 x데이터는 모델에 넣어주기 위해 np.array 형식의 값을 갖고 있다.

print(type(x_test[0]))

🧐 x데이터는 모델에 넣어주기 위해 32비트 실수 형식의 값을 갖고 있다.

32비트 실수 : [0.15648954956...]

print(x_test[0].dtype)

📌모델 1번 구성

두 개의 모델을 만들어 학습하기 1번.

🚩인풋 레이어

위에서 x_test[0].shape를 찍어본 이유는 여기에 크기를 넣기 위해서!
28*28 사진의 784 픽셀 색 값 만큼 가지고 있다.

🚩히든 레이어

학습을 위해 무수히 학습하는 중간 층
덴스 레이어의 크기는 사실 정해져 있는 것은 아닌데 4배수로 256,512 이런식으로 많이 사용함

1번 히든레이어. Dense 1024, activation=relu, (input)

2번 히든레이어. Dense 512, activation=relu, (hidden)

3번 히든레이어. Dense 256, activation=relu, (hidden)

🤹‍♀️ 이게 왜 있는건데?

중간 층에서 학습을 담당한다. 인풋 -> 1번 히든 -> 2번 히든 -> 3번 히든 -> 출력
레이어가 줄어들면서 값을 추려준다고 생각하면 좋다!

🚩출력 레이어

덴스 레이어 24는 원-핫 인코딩을 통해서 늘어난 shape 크기 값을 의미한다!
activation=softmax 는 다항논리회귀로 이미지 분류에 사용한다

📌모델 설정

이렇게 설정할 레이어를 다 만들어주고, 케라스 모델을 활용하여 인풋과 아웃풋을 넣어준다

📌모델 컴파일

마지막으로 다 넣고 교과서를 찍어낼 준비를 한다!
손실에 softmax를 썼다면 categorical_crossentropy를 넣고, 옵티마이저와 애큐러시 속성을 넣고 컴파일한다

👨‍🏭옵티마이저(최소화)

컴파일할 모델의 가설, 손실함수의 값을 최적화된 값으로 가기 위해서는 함수의 최소화지점으로 가야한다.
러닝레이트, 다가가는 발걸음의 크기를 조절해 가면서 다가가야 튕겨나가거나 왔다갔다하는 오버슈팅을 피할 수 있다

input = Input(shape=(784,))
hidden = Dense(1024, activation='relu')(input)
hidden = Dense(512, activation='relu')(hidden)
hidden = Dense(256, activation='relu')(hidden)
output = Dense(24, activation='relu')(hidden)

model1 = Model(inputs=input, outputs=output)

model1.compile(loss='categorical_crossentropy', optimizer=Adam(learning_rate=0.001), metrics=['acc'])

🙄 이게 뭔데? : 784(인풋 레이어의 크기) * 1024(완전연결 레이어의 크기)

print(784*1024)

🔥문제 3번.

컴파일한 모델이 어떻게 생겼는지 요약으로 보자!

🚩구성

  1. 레이어 타입(인풋, 히든, 출력)
  2. 아웃풋 쉐이프(배치사이즈, 레이어 크기)
  3. 파라미터

model1.summary()

🙄 이게뭔데? : 각 덴스레이어에서 학습할 파라미터의 값 약 140 여 만개

print(803840 + 524800 +131328 + 6168)

🙄 이게뭔데? : 무슨 모델인데 모델이 뭐야? 알려주려고 function 모델로 변경???

func_model = Model(inputs=input, outputs=output, name='FuncModel')

🙄 이게뭔데? : 플롯_모델 라이브러리를 임포트 해서 모델의 생김새를 이미지로 한 눈에 볼 수 있게 만들 준비!

from tensorflow.keras.utils import plot_model

🙄 이게뭔데? : 모델을 넣어 이미지로 보여주기!

plot_model(func_model, show_shapes=True, show_layer_names=True, to_file='model.png')

📌모델 2번 구성

🚩레이어 구성

👁‍🗨인풋 레이어

모델1과 동일 -> Dense 256

👁‍🗨히든 레이어

기존 레이어에서 드롭아웃 추가

🙄 드롭아웃?

https://keras.io/api/layers/regularization_layers/dropout/

각 단계에서 입력 단위를 무작위로 0으로 설정해서 과적합을 방지. -> 사공이 너무 많아서 산으로 가는 것을 막아줌


✍사용법

히든 레이어 마지막에 hidden 변수에 Dropout(rate=)(hidden)을 담아서 사용함
rate=0.5 삭제할 입력 단위 비율 50%

👁‍🗨아웃풋 레이어

모델 1과 동일 -> Dense 24, softmax

👁‍🗨모델 선언

모델 1과 동일 -> 변수만 2로 다르게 넣어주기

👁‍🗨모델 컴파일

모델 1과 동일 -> loss=categorical_crossentropy, Adam lr=0.001 metrics=['acc']

input = Input(shape=(784,))
hidden = Dense(256, activation='relu')(input)
hidden = Dense(512, activation='relu')(hidden)
hidden = Dense(1024, activation='relu')(hidden)
hidden = Dense(512, activation='relu')(hidden)
hidden = Dense(256, activation='relu')(hidden)
hidden = Dropout(rate=0.5)(hidden)
output = Dense(24, activation='softmax')(hidden)

model2 = Model(inputs=input, outputs=output)

model2.compile(loss='categorical_crossentropy', optimizer=Adam(learning_rate=0.001), metrics=['acc'])

profile
하루종일 몽상가

0개의 댓글