파이썬

Keras를 사용한 이미지 분류 #2 (TensorFlow 텐서플로우 이미지 분류 신경망 모델)

sheepone 2021. 7. 29. 11:20
반응형

2차 진행

패션 MNIST 데이터셋 70000중
트레인 이미지 60001개 테스트 이미지 10000개로 이미지 분류 수행
1차에서 불량난 스니커즈 이미지 25번을 추가하여 검출해 내는지
테스트 수행

 

마지막 이미지에 스니커즈 사진 확인

 

 

추가한 스니커즈 검사 확인

 

 

난제

epochs 횟수를 늘려서 재작업을 여러번 진행하면 모델 생성 시간은 늘어나지만 기존 모델 분류성능이 좋아진다.

하지만 새로운 영상에 대한 인식이 떨어지는 과대적합 현상이 생긴다.

 

* 과대적합은 머신러닝 모델이 훈련 데이터보다 새로운 데이터에서 성능이 낮아지는 현상

 

# tensorflow와 tf.keras를 임포트합니다
from PIL.Image import NONE
from numpy.lib.function_base import append
import tensorflow as tf
from tensorflow import keras

# 헬퍼(helper) 라이브러리를 임포트합니다
import numpy as np
import matplotlib.pyplot as plt

print(tf.__version__) #2.5.0

fashion_mnist = keras.datasets.fashion_mnist #패션 MNIST 데이터셋 임포트하기 이미지 해상도 28x28

#train_images와 train_labels 배열은 모델 학습에 사용되는 훈련 세트입니다.
#test_images와 test_labels 배열은 모델 테스트에 사용되는 테스트 세트입니다.
(train_images1, train_labels1), (test_images, test_labels) = fashion_mnist.load_data()


test3 = test_images[12].reshape(1,28,28)
train_images = np.vstack((train_images1, test3))
train_labels = np.append(train_labels1, np.array(test_labels[12]))

#Label 레이블 0~9 
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

#데이터 전처리
plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
plt.show()               

#신경망 모델에 주입하기 전에 이 값의 범위를 0~1 사이로 조정
train_images = train_images / 255.0 #(0 ~ 255) / 255 = (0 ~ 1)
test_images = test_images / 255.0

#훈련 세트에서 처음 25개 이미지와 그 아래 클래스 이름을 출력해 보죠. 
#데이터 포맷이 올바른지 확인하고 네트워크 구성과 훈련할 준비를 마칩니다.
plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    if i == 24 :
        plt.imshow(train_images[60000], cmap=plt.cm.binary)
        plt.xlabel(class_names[train_labels[60000]])
    else :
        plt.imshow(train_images[i], cmap=plt.cm.binary)
        plt.xlabel(class_names[train_labels[i]])
    
plt.show()

'''
이 네트워크의 첫 번째 층인 tf.keras.layers.Flatten은 2차원 배열(28 x 28 픽셀)의 
이미지 포맷을 28 * 28 = 784 픽셀의 1차원 배열로 변환합니다. 
이 층은 이미지에 있는 픽셀의 행을 펼쳐서 일렬로 늘립니다. 
이 층에는 학습되는 가중치가 없고 데이터를 변환하기만 합니다.

픽셀을 펼친 후에는 두 개의 tf.keras.layers.Dense 층이 연속되어 연결됩니다. 
이 층을 밀집 연결(densely-connected) 또는 완전 연결(fully-connected) 층이라고 부릅니다. 
첫 번째 Dense 층은 128개의 노드(또는 뉴런)를 가집니다. 
두 번째 (마지막) 층은 10개의 노드의 소프트맥스(softmax) 층입니다. 
이 층은 10개의 확률을 반환하고 반환된 값의 전체 합은 1입니다. 
각 노드는 현재 이미지가 10개 클래스 중 하나에 속할 확률을 출력합니다.
'''

model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(128, activation='relu'),
    keras.layers.Dense(10, activation='softmax')
])

'''
모델 컴파일
모델을 훈련하기 전에 필요한 몇 가지 설정이 모델 컴파일 단계에서 추가됩니다:

손실 함수(Loss function)-훈련 하는 동안 모델의 오차를 측정합니다. 
모델의 학습이 올바른 방향으로 향하도록 이 함수를 최소화해야 합니다.
옵티마이저(Optimizer)-데이터와 손실 함수를 바탕으로 모델의 업데이트 방법을 결정합니다.
지표(Metrics)-훈련 단계와 테스트 단계를 모니터링하기 위해 사용합니다. 
다음 예에서는 올바르게 분류된 이미지의 비율인 정확도를 사용합니다.
'''
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

'''
모델 훈련
신경망 모델을 훈련하는 단계는 다음과 같습니다:

훈련 데이터를 모델에 주입합니다-이 예에서는 train_images와 train_labels 배열입니다.
모델이 이미지와 레이블을 매핑하는 방법을 배웁니다.
테스트 세트에 대한 모델의 예측을 만듭니다-이 예에서는 test_images 배열입니다. 
이 예측이 test_labels 배열의 레이블과 맞는지 확인합니다.
훈련을 시작하기 위해 model.fit 메서드를 호출하면 모델이 훈련 데이터를 학습합니다:
'''
#hist = model.fit(train_images, train_labels, epochs=5)   

#batch_size(배치사이즈)
#배치사이즈는 몇 개의 관측치에 대한 예측을 하고, 레이블 값과 비교를 하는지를 설정하는 파라미터입니다. 위의 예시에서 배치사이즈가 100이면 전체 데이터에 대해 모두 예측한 뒤 실제 레이블 값과 비교한 후 가중치 갱신을 합니다. 배치사이즈가 10이면 10개 데이터에 대해 예측한 뒤 실제 레이블 값과 비교하며 가중치 갱신도 10번 발생합니다.
#배치사이즈가 100인 경우, 어떤 한 유형에 대한 예측이 틀리면 이후 비슷한 유형에 대한 예측도 틀릴 수 있습니다. 하지만 배치사이즈가 10인 경우에는, 데이터 10개마다 실제 레이블 값과 비교하기 때문에, 처음에 틀리게 예측하더라도 가중치 업데이트를 하면서 뒤에는 맞추게 될 확률이 높습니다.
#배치사이즈가 클수록 많은 데이터를 저장해두어야 하므로 용량이 커야합니다. 반면, 배치사이즈가 작으면 학습은 촘촘하게 되겠지만 계속 레이블과 비교하고, 가중치를 업데이트하는 과정을 거치면서 시간이 오래 걸립니다.
#epochs 전체 데이터셋을 몇번 반복할 것인지 설정     
#너무 많이 반복학습을 하면 학습셋에 대해 성능은 올라가지만 관측되지 못한 테스트셋에 대한 성능이 떨어지는 오버피팅(overfitting)이 발생하게 됩니다. 때문에, 오버피팅이 일어날 것 같으면 학습을 종료합니다.(early stopping)
hist = model.fit(train_images,train_labels,epochs=100,batch_size=NONE, validation_data=(test_images,test_labels))

#%matplotlib inline
import matplotlib.pyplot as plt
fig, loss_ax = plt.subplots()
acc_ax = loss_ax.twinx()
loss_ax.plot(hist.history['loss'],'y',label='train loss')
loss_ax.plot(hist.history['val_loss'],'r',label='val loss')
acc_ax.plot(hist.history['accuracy'],'b',label='train acc') #acc 로 하면 에러남요.
acc_ax.plot(hist.history['val_accuracy'],'g',label='val acc') #val_acc 로 하면 에러남요.
loss_ax.set_xlabel('epoch')
loss_ax.set_ylabel('loss')
acc_ax.set_ylabel('accuracy')
loss_ax.legend(loc='upper left')
acc_ax.legend(loc='lower left')
plt.show()

#정확도 평가
#그다음 테스트 세트에서 모델의 성능을 비교합니다:
test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)

print('\n테스트 정확도:', test_acc)
# 테스트 세트의 정확도가 훈련 세트의 정확도보다 조금 낮습니다. 훈련 세트의 정확도와 테스트 세트의 정확도 사이의 차이는 
# 과대적합(overfitting) 때문입니다. 
# 과대적합은 머신러닝 모델이 훈련 데이터보다 새로운 데이터에서 성능이 낮아지는 현상을 말합니다.

'''
예측 만들기
'''
predictions = model.predict(test_images)
np.argmax(predictions[0])

def one_test(self):
    # 테스트 세트에서 이미지 하나를 선택합니다
    img = self.test_images[0]
    print(img.shape)
    # 이미지 하나만 사용할 때도 배치에 추가합니다
    img = (np.expand_dims(img, 0))
    print(img.shape)
    predictions_single = self.model.predict(img)
    print(predictions_single)
    self.plot_value_array(0, predictions_single, self.test_labels)
    _ = plt.xticks(range(10), self.class_names, rotation=45)
    np.argmax(predictions_single[0])
        
def plot_image(i, predictions_array, true_label, img):
    predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]
    plt.grid(False)
    plt.xticks([])
    plt.yticks([])

    plt.imshow(img, cmap=plt.cm.binary)

    predicted_label = np.argmax(predictions_array)
    if predicted_label == true_label:
        color = 'blue'
    else:
        color = 'red'

    plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
                                100*np.max(predictions_array),
                                class_names[true_label]),
                                color=color)

def plot_value_array(i, predictions_array, true_label):
  predictions_array, true_label = predictions_array[i], true_label[i]
  plt.grid(False)
  plt.xticks([])
  plt.yticks([])
  thisplot = plt.bar(range(10), predictions_array, color="#777777")
  plt.ylim([0, 1])
  predicted_label = np.argmax(predictions_array)

  thisplot[predicted_label].set_color('red')
  thisplot[true_label].set_color('blue')

'''
i = 0
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions,  test_labels)
plt.show()
'''
# 처음 X 개의 테스트 이미지와 예측 레이블, 진짜 레이블을 출력합니다
# 올바른 예측은 파랑색으로 잘못된 예측은 빨강색으로 나타냅니다
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
  plt.subplot(num_rows, 2*num_cols, 2*i+1)
  plot_image(i, predictions, test_labels, test_images)
  plt.subplot(num_rows, 2*num_cols, 2*i+2)
  plot_value_array(i, predictions, test_labels)
plt.show()

# 마지막으로 훈련된 모델을 사용하여 한 이미지에 대한 예측을 만듭니다.
# 테스트 세트에서 이미지 하나를 선택합니다
img = test_images[0]

print(img.shape)

# 이미지 하나만 사용할 때도 배치에 추가합니다
img = (np.expand_dims(img,0))

print(img.shape)

predictions_single = model.predict(img)

print(predictions_single)

plot_value_array(0, predictions_single, test_labels)
_ = plt.xticks(range(10), class_names, rotation=45)

np.argmax(predictions_single[0])
반응형