7주차 16장 이미지 인식의 꽃 컨벌루션 신경망(CNN)

김영기·2024년 1월 8일
0

손 글씨를 인식해보자

1. 이미지를 인식하는 원리

MNIST 데이터는 텐서플로의 케라스 API를 이용해 불러오기 ㄱㄴ

from tensorflow.keras.datasets import mnist

학습에 사용될 부분: X_train, y_train
테스트에 사용될 부분: X_test, y_test

(X_train, y_train), (X_test,y_test) = mnist.load_data()
print("학습셋 이미지 수 : %d개" % (X_train.shape[0]))
print("테스트셋 이미지 수: %d개" % (X_test.shape[0]))

실행결과는
학습셋 이미지 수: 60000개
테스트셋 이미지 수:10000개

맷플롯립 라이브러리를 불러오고 이미지 1개를 출력해서 분석해보자
import matplotlib.pyplot as plt
plt.imshow(X_train[0], cmap = 'Greys')
plt.show()

784개의 픽셀 이미지이고 밝기에 따라 등급을 나눔

for x in X_train[0]:
for i in x:
sys.stdout.write("%-3s"%i)
sys.stdout.write('\n')

28*28=784개의 속성을 이용해 0~9까지의 클래스중 1개를 고르는 문제
2차원 배열을 1차원 배열로 바꾸기 위해 reshape함수 사용

X_train = X_train.reshape(X_train.shape[0],784)

케라스는 데이터를 0~1사이 값으로 변환 후 구동할 때 최적의 성능을 가짐
정규화 데이터의 폭이 클 때 적절한 정도로 바꾸는 과정

X_train = X_train.astype('float64')
X_train = X_train / 255

X_test = X_test.reshape(X_test.shape[0], 784).astype('float64') / 255

print("class : %d" % (y_train[0]))

결과로 5가 출력되는 것을 볼 수 있다..!

딥러닝의 분류문제를 해결하기 위해서는 원-핫 인코딩 방식을 적용해야함
우리가 열어 본 이미지 클래스는 5 = [0,0,0,0,0,1,0,0,0,0](원-핫 인코딩)

이를 가능하게 해주는 것이 np_utils.to_categorical()함수
to_categorical(클래스, 클래스의 개수)

y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)

print(y_train[0])

실행결과
[0,0,0,0,0,1,0,0,0,0]

실습 MNIST 손글씨 인식하기: 데이터 전처리

from tensorflow.keras.datasets import mnist
from tensorflow.keras.utils import to_categorical

import matplotlib.pyplot as plt
import sys

#MNIST 데이터셋을 불러와 학습셋과 테스트셋으로 저장
(X_train, y_train), (X_test, y_test) = mnist.load_data()

print("학습셋 이미지 수 : %d개" % (X_train.shape[0]))
print("테스트셋 이미지 수: %d개" % (X_test.shape[0]))

plt.imshow(X_train[0], cmap = 'Greys')
plt.show()

for x in X_train[0]:
for i in x:
sys.stdout.write("%-3s"%i)
sys.stdout.write('\n')

X_train = X_train.reshape(X_train.shape[0],784)
X_train = X_train.astype('float64')
X_train = X_train / 255
X_test = X_test.reshape(X_test.shape[0], 784).astype('float64') / 255

print("class : %d" % (y_train[0]))

y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)

print(y_train[0])

2.딥러닝 기본 프레임 만들기

6만개의 학습셋과 1만개의 테스트셋을 불러와
속성 값을 지닌 X ,클래스 값을 지닌 y로 구분하는 작업을 정리

from tensorflow.keras.datasets import mnist

#MNIST 데이터셋을 불러와 학습셋과 테스트셋으로 저장
(X_train, y_train), (X_test, y_test) = mnist.load_data()

X_train = X_train.reshape(X_train.shape[0],784).astype('float64') / 255
X_test = X_test.reshape(X_test.shape[0], 784).astype('float64') / 255

y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)

딥러닝을 실행하고자 프레임을 설정한다.

model = Sequential()
model.add(Dense(512, input_dim=784, activation = 'relu'))
model.add(Dense(10, activation='softmax'))

입력 값이 784개, 은닉층이 512개 출력이 10개인 모델
활성화 함수로 은닉층에서는 'relu', 출력층에서는 softmax

model.compile(loss='categorical_crossentropy', optimizer = 'adam',metrics =['accuracy'])
오차 함수로 categorical_crossentropy 최적화 함수로 adam

모델의 최적화 단계, 학습 자동중단
from tensorflow.keras.callbacks import ModelCheckpoint, Earlystopping

#모델의 최적화를 위한 설정 구간
modelpath = "./MNIST_MLP.hdf5"
checkpointer = ModelCheckpoint(filepath=modelpath, monitor = 'val_loss', verbpse=1, save_best_only = True)
early_stoppping_callback = EarlyStopping(monitor='val_loss',patience=10)

10번 이상 모델 성능이 향상되지 않으면 자동으로 학습을 중단한다.

실습 MNIST 인식: 기본 프레임

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
from tensorflow.keras.datasets import mnist
from tensorflow.keras.utils import to_categorical
import matplotlib.pyplot as plt
import numpy as np
import os
#MNIST 데이터를 불러온다.
(X_train, y_train), (X_test, y_test) = mnist.load_data()
#차원 변환 후, 테스트셋과 학습셋으로 나눈다.
X_train = X_train.reshape(X_train.shape[0], 784).astype('float32') / 255
X_test = X_test.reshape(X_test.shape[0], 784).astype('float32') / 255
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)
#모델 구조를 설정한다.
model = Sequential()
model.add(Dense(512, input_dim=784, activation='relu'))
model.add(Dense(10, activation='softmax'))
model.summary()
#모델 실행 환경을 설정한다.
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
#모델 최적화를 위한 설정 구간.
modelpath = "./MNIST_MLP.hdf5"
checkpointer = ModelCheckpoint(filepath=modelpath, monitor='val_loss', verbose=1, save_best_only=True)
early_stopping_callback = EarlyStopping(monitor='val_loss', patience=10)
#모델을 실행한다.
history = model.fit(X_train, y_train, validation_split=0.25, epochs=30, batch_size=
200, verbose=0, callbacks=[early_stopping_callback, checkpointer])
#테스트 정확도를 출력한다.
print("\n Test Accuracy: %.4f" % (model.evaluate(X_test, y_test)[1]))
#검증셋과 학습셋의 오차를 저장한다.
y_vloss = history.history['val_loss']
y_loss = history.history['loss']
#그래프로 표현.
x_len = np.arange(len(y_loss))
plt.plot(x_len, y_vloss, marker='.', c="red", label='Testset_loss')
plt.plot(x_len, y_loss, marker='.', c="blue", label='Trainset_loss')
#그래프에 그리드를 주고 레이블을 표시.
plt.legend(loc='upper right')
plt.grid()
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()


23번 실행하고 정확도는 0.9815

프로젝트에 맞추어 옵션을 추가하고 어떤 층을 추가하느냐에 따라 성능이 좋아짐.

3.컨벌루션 신경망(CNN)

컨벌루션 신경망(CNN) :입력된 이미지에서 다시 한 번 특징을 추출하기 위해 커널(슬라이딩 윈도)를 도입하는 기법

입력받은 이미지의 값에 커널을 곱하고 합해서 컨벌루션 층을 만든다.
커널을 여러 개 만들경우 여러 개의 컨볼루션 층이 만들어진다.

케라스에서 컨벌루션 층을 추가하는 함수는 Conv2D()입니다. 컨벌루션 층을 적용해 MNIST 손글씨 인식률을 높여보자.
model.add(Conv2d(32, kernel_size=(3,3), input_shape=(28, 28, 1), activation='relu'))

입력된 인자를 보자
1. 커널을 몇 개 적용할지 정한다. 여기서는 32
2. Kernel_size: 커널의 크기 (행, 렬) 여기서는 3X3
3. input_shape: input_shape=(행, 열, 색상 또는 흑백) 형식 색상 3, 흑백 1
4.activation: 사용할 활성화 함수를 정의

컨벌루션 층을 하나 더 추가
model.add(Conv2D(64, (3,3), activation='relu'))

4. 맥스 풀링, 드롭아웃, 플래튼

컨벌루션 층을 통해 이미지 특징을 도출해도 그 결과가 여전히 크고 복잡하면 이를 다시 축소해야함.

이 과정을 풀링 or 서브 샘플링이라고 한다.

정해진 구역에서 최댓값을 뽑아내는 맥스 풀링
평균값을 뽑아내는 평균 풀링 등이 있다.

맥스 풀링

이미지가 있을 때, 맥스 풀링을 적용, 그후 각 구역에서 가장 큰 값 추출
MaxPooling2D()함수를 사용

model.add(MaxPooling2D(pool_size=(2,2)))
Pool_size는 풀링 창의 크기를 정하는 것 (2,2)는 가로 2 세로 2

드롭아웃

은닉층에 배치된 노드 중 일부를 임의로 꺼 주는 것

예를 들어 25%의 노드를 끄려면
model.add(Dropout(0.25))

이러한 과정을 지나고 다시 Dense()함수를 이용해 만들어진 기본 층에 연결

맥스풀링과 컨볼루션 층은 이미지를 2차원 배열인 채 다루기 때문에 이를 1차원 배열로 바꾸어 주어야 활성화 함수가 있는 층에사 사용가능

플래튼

Flatten()함수를 사용해 2차원 배열을 1차원으로 바꿔야 한다.
model.add(Flatten())

5.컨벌루션 신경망 실행하기

실습,MNIST 손 글씨 인식, CNN

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
from tensorflow.keras.datasets import mnist
from tensorflow.keras.utils import to_categorical
import matplotlib.pyplot as plt
import numpy as np
#데이터를 불러옵니다.
(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_train = X_train.reshape(X_train.shape[0], 28, 28, 1).astype('float32') / 255
X_test = X_test.reshape(X_test.shape[0], 28, 28, 1).astype('float32') / 255
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
#컨볼루션 신경망의 설정
model = Sequential()
model.add(Conv2D(32, kernel_size=(3,3), input_shape=(28,28,1), activation='relu'))
model.add(Conv2D(64, (3,3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))
#모델의 실행 옵션을 설정합니다.
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
#모델 최적화를 위한 설정 구간입니다.
modelpath = "./MNIST_CNN.hdf5"
checkpointer = ModelCheckpoint(filepath=modelpath, monitor='val_loss', verbose=1, save_best_only=True)
early_stopping_callback = EarlyStopping(monitor='val_loss', patience=10)
#모델을 실행합니다.
history = model.fit(X_train, y_train, validation_split=0.25, epochs=30, batch_size=
200, verbose=0, callbacks=[early_stopping_callback, checkpointer])
#테스트 정확도를 출력합니다.
print("\n Test Accuracy: %.4f" % (model.evaluate(X_test, y_test)[1]))
#검증셋과 학습셋의 오차를 저장합니다.
y_vloss = history.history['val_loss']
y_loss = history.history['loss']
#그래프로 표현해 봅니다.
x_len = np.arange(len(y_loss))
plt.plot(x_len, y_vloss, marker='.', c="red", label='Testset_loss')
plt.plot(x_len, y_loss, marker='.', c="blue", label='Trainset_loss')
#그래프에 그리드를 주고 레이블을 표시하겠습니다.
plt.legend(loc='upper right')
plt.grid()
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

데이터를 정확하게 맞추지는 못했는데 이는 데이터 안에 0~9까지의 숫자가 아닌 다른 그림이 있었기 때문

profile
안녕하세요

0개의 댓글