2차시: 텐서플로우 2.x 활용 이미지 분류 기초

AI 맛보기 2주차: 2020. 07. 14. 20:00 ~ 22:00 (120분)

  1. 도구 불러오기 및 버전 확인
  2. 학습 데이터 다운로드: MNIST Fashion
  3. 학습 데이터 살펴보기: 차원, 미리보기
  4. 학습 데이터 전처리 (정규화)
  5. 학습 모델 준비
  6. 학습
  7. 학습 결과 테스트
  8. 확률 모델
  9. 예측이란?
  10. 모델 개선

참고자료

1. 도구 불러오기 및 버전 확인


In [ ]:
# 도구 준비
import os
import shutil

import tensorflow as tf # 텐서플로우
import matplotlib.pyplot as plt # 시각화 도구
%matplotlib inline
import matplotlib.font_manager as fm
import numpy as np

In [ ]:
print(f'Tensorflow 버전을 확인합니다: {tf.__version__}')

In [ ]:
# 시각화 한글 설정
fonts = fm.findSystemFonts()
nanum_path = None
for font in fonts:
    if font.endswith('NanumGothic.ttf'):
        nanum_path = font
        break
if nanum_path == None:
    print(f'나눔 폰트를 설치해야 합니다!')
    print(f'!apt install -qq -y fonts-nanum*')
else:
    print(f'나눔 폰트 경로: {nanum_path}')
    nanum_prop = fm.FontProperties(fname=nanum_path)

2. 학습 데이터 다운로드: MNIST Fashion


In [ ]:
# 데이터 다운로드
# dataset_path = 'C:\Users\<your_username>\.keras\datasets' # Windows
dataset_path = os.path.abspath(os.path.expanduser('~/.keras/datasets/')) # Linux
if os.path.exists(dataset_path):
    shutil.rmtree(dataset_path)
(_train_images, train_labels), (_test_images, test_labels) = tf.keras.datasets.fashion_mnist.load_data()

In [ ]:
print(f'학습에 사용할 이미지는 {len(_train_images)}개 입니다.')
print(f'학습한 후 테스트(검증)에 사용할 이미지는 {len(_test_images)}개 입니다.')

In [ ]:
train_labels[:10]

In [ ]:
class_names = ['티셔츠', '바지', '스웨터', '드레스', '코트',
               '샌들', '셔츠', '운동화', '가방', '부츠']
print(f'데이터의 레이블은 {len(class_names)}개 이며, 데이터셋에 포함되어 있지 않으므로 설명서에서 확인해야 합니다.')
print('레이블 번호와 레이블: ')
for i in range(0, len(class_names)):
    print(f'{i}: {class_names[i]}')

3. 학습 데이터 살펴보기: 차원, 미리보기


In [ ]:
print(f'학습 이미지 형태: {_train_images.shape}')
print(f'학습 레이블 형태: {train_labels.shape}')

In [ ]:
print(f'테스트 이미지 형태: {_test_images.shape}')
print(f'테스트 레이블 형태: {test_labels.shape}')

In [ ]:
fig1 = plt.figure(figsize=(6, 6))
ax = fig1.add_subplot()
axm = ax.imshow(_train_images[0])
fig1.colorbar(axm)
fig1.suptitle('학습용 예제 이미지', fontproperties=nanum_prop, fontsize=24)
ax.set_title(f'레이블: {class_names[train_labels[0]]}', fontproperties=nanum_prop, fontsize=16)
ax.grid(False)

4. 학습 데이터 전처리 (정규화)


In [ ]:
print('인공 신경망은 주로 -1.0 ~ 1.0 사이의 값을 받습니다.')
print('따라서 이미지를 255로 나누어줍니다.')
train_images = _train_images / 255.0
test_images = _test_images / 255.0

In [ ]:
fig2 = plt.figure(figsize=(6, 6))
ax = fig2.add_subplot()
axm = ax.imshow(train_images[0])
fig2.colorbar(axm)
fig2.suptitle('학습용 예제 이미지 (정규화)', fontproperties=nanum_prop, fontsize=24)
ax.set_title(f'레이블: {class_names[train_labels[0]]}', fontproperties=nanum_prop, fontsize=16)
ax.grid(False)

In [ ]:
fig3 = plt.figure(figsize=(12, 12))
fig3.set_facecolor('white')
for i in range(25):
    ax = fig3.add_subplot(5, 5, i+1)
    ax.imshow(train_images[i], cmap=plt.cm.binary)
    ax.set_xticks([])
    ax.set_yticks([])
    ax.set_title(class_names[train_labels[i]], fontproperties=nanum_prop)

In [ ]:
fig4 = plt.figure(figsize=(12, 12/5*2))
fig4.set_facecolor('white')
for i in range(10):
    ax = fig4.add_subplot(2, 5, i+1)
    for j in range(10000, len(train_images)):
        if train_labels[j] == i:
            break
    ax.imshow(train_images[j], cmap=plt.cm.binary)
    ax.set_xticks([])
    ax.set_yticks([])
    ax.set_title(f'[{train_labels[j]}] {class_names[train_labels[j]]}', 
                 fontproperties=nanum_prop, fontsize=12)

5. 학습 모델 준비


In [ ]:
print('모델 생성')
model = tf.keras.Sequential([
    tf.keras.layers.Flatten(input_shape=(train_images.shape[1:])),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10)
])
model.summary()

In [ ]:
print('모델 컴파일')
model.compile(optimizer=tf.keras.optimizers.Adam(),
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

6. 학습


In [ ]:
epochs = 10
model.fit(train_images, train_labels, 
          epochs=epochs)

7. 학습 결과 테스트


In [ ]:
print(f'{len(test_images)}개 이미지로 테스트합니다.')
test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)
print()
print(f'테스트 이미지 정확도: {test_acc}')

In [ ]:
print(f'테스트 이미지 0번 예측:\n{model.predict(test_images[100:101])}')
print(f'실제 레이블: {test_labels[100]}')

In [ ]:
fig5 = plt.figure(figsize=(6, 6))
ax = fig5.add_subplot()
axm = ax.imshow(test_images[0])
fig5.colorbar(axm)
fig5.suptitle('테스트 이미지', fontproperties=nanum_prop, fontsize=24)
ax.set_title(f'레이블: {class_names[test_labels[0]]}', fontproperties=nanum_prop, fontsize=16)
ax.grid(False)

8. 확률 모델


In [ ]:
print('확률 모델')
probability_model = tf.keras.Sequential([model, 
                                         tf.keras.layers.Softmax()])
probability_model.summary()

In [ ]:
predictions = probability_model.predict(test_images)
print(f'테스트 이미지 0번 예측:\n{predictions[0]}')
print(f'실제 레이블: {test_labels[0]}')

In [ ]:
print(f'예측 레이블은 확률 중 최대 확률을 선택합니다.')
print(f'테스트 이미지 0번의 최대 확률 레이블: {np.argmax(predictions[0])}')

9. 예측이란?


In [ ]:
# 이미지 함수 정의
def draw_image(ax, prob, image, true_label):
    ax.grid(False)
    axm = ax.imshow(image, cmap=plt.cm.binary)
    ax.set_xticks([])
    ax.set_yticks([])
    predicted_label = np.argmax(prob)
    if true_label == predicted_label:
        color = 'blue'
    else:
        color = 'red'
    predicted_name = class_names[predicted_label]
    true_name = class_names[true_label]
    label = f'{predicted_name} {np.max(prob)*100:3.0f}% ({true_name})'
    ax.set_title(f'{label}', fontproperties=nanum_prop, color=color)
    
def draw_bar(ax, prob, true_label):
    ax.grid(False)
    ax.set_xticks(range(10))
    ax.set_yticks(np.arange(0, 1.2, 0.2))
    bar = ax.bar(range(10), prob, color='gray')
    ax.set_ylim((0, 1))
    predicted_label = np.argmax(prob)
    bar[predicted_label].set_color('red')
    bar[true_label].set_color('blue')

In [ ]:
for i in range(len(test_images)):
    if test_labels[i] == np.argmax(predictions[i]):
        break
fig6 = plt.figure(figsize=(6, 3))
ax = fig6.add_subplot(1, 2, 1)
draw_image(ax, predictions[i], test_images[i], test_labels[i])
ax = fig6.add_subplot(1, 2, 2)
draw_bar(ax, predictions[i], test_labels[i])

In [ ]:
for i in range(len(test_images)):
    if test_labels[i] != np.argmax(predictions[i]):
        break
fig7 = plt.figure(figsize=(6, 3))
ax = fig7.add_subplot(1, 2, 1)
draw_image(ax, predictions[i], test_images[i], test_labels[i])
ax = fig7.add_subplot(1, 2, 2)
draw_bar(ax, predictions[i], test_labels[i])

In [ ]:
base = 5000
rows = 1 * 5
cols = 2 * 3
fig8 = plt.figure(figsize=(2.5*cols, 2.5*rows))
fig8.set_facecolor('white')
for i in range(0, rows*cols, 2):
    ax = fig8.add_subplot(rows, cols, i+1)
    draw_image(ax, predictions[base+i], test_images[base+i], test_labels[base+i])
    ax = fig8.add_subplot(rows, cols, i+2)
    draw_bar(ax, predictions[base+i], test_labels[base+i])

10. 모델 개선


In [ ]:
model = tf.keras.Sequential([
    tf.keras.layers.Flatten(input_shape=train_images.shape[1:]),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10)
])
model.summary()