[Tensorflow] 이미지 분류
TensorFlow 및 기타 라이브러리 가져오기
import matplotlib.pyplot as plt
import numpy as np
import os
import PIL
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential
데이터 세트 다운로드
import pathlib
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file('flower_photos', origin=dataset_url, untar=True)
data_dir = pathlib.Path(data_dir)
roses 디렉토리의 이미지 확인
roses = list(data_dir.glob('roses/*'))
PIL.Image.open(str(roses[0]))
데이터 세트 만들기
모델 개발할 때 validation split 사용. Training에 이미지의 80%, Validation에 이미지의 20% 사용
# training에 사용할 이미지 분할
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="training",
seed=123,
image_size=(img_height, img_width),
batch_size=batch_size)
# validation에 사용할 이미지 분할
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="validation",
seed=123,
image_size=(img_height, img_width),
batch_size=batch_size)
# 클래스 이름 확인
class_names = train_ds.class_names
print(class_names)
데이터 시각화
다음 코드 실행으로 훈련 데이터세트의 처음 9개 이미지 확인
3x3으로 출력됨
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 10))
for images, labels in train_ds.take(1):
for i in range(9):
ax = plt.subplot(3, 3, i + 1)
plt.imshow(images[i].numpy().astype("uint8"))
plt.title(class_names[labels[i]])
plt.axis("off")
성능을 높이도록 데이터세트 구성
버퍼링된 프리페치를 사용하여 I/O를 차단하지 않고 디스크에서 데이터 생성. 데이터를 로드할 때 두 가지 중요한 메서드 사용
- Dataset.cache() : 첫 epoch 동안 디스크에서 이미지를 로드한 후 이미지를 메모리에 유지. 이렇게 하면 모델을 훈련하는 동안 데이터세트가 병목 상태가 되지 않음. 데이터세트가 너무 커서 메모리에 맞지 않는 경우, 이 메서드를 사용하여 성능이 높은 온디스크 캐시 생성할 수 있음
- Dataset.prefetch() : 훈련 중에 데이터 전처리 및 모델 실행과 겹침
AUTOTUNE = tf.data.experimental.AUTOTUNE
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
모델 만들기
다음 모델은 3개의 convolution block으로 구성, 그 위에 relu activation function에 의해 활성화되는 128개의 unit이 있는 fully connected layer.
num_classes = 5
model = Sequential([
layers.experimental.preprocessing.Rescaling(1./255, input_shape=(img_height, img_width, 3)), # 데이터 표준화
layers.Conv2D(16, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(32, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(64, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dense(num_classes)
])
모델 컴파일
여기서는 optimizers.Adam 옵티마이저, losses.SparseCategoricalCrossentropy 손실함수 선택
각 훈련 epoch에 대한 training 및 val accuracy를 보려면 metrices 인수를 전달
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
모델 요약
생성한 네트워크의 모든 레이어 확인
모델 훈련
epochs=10
history = model.fit(
train_ds,
validation_data=val_ds,
epochs=epochs
)
훈련 결과 시각화
training set, validation set에 대한 loss와 accuracy plot 생성
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss=history.history['loss']
val_loss=history.history['val_loss']
epochs_range = range(epochs)
plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
Overfitting (과대적합)
training set의 노이즈나 원치 않는 detail 까지 학습하는 현상. 모델이 새 dataset에서 일반화하는데 어려움이 발생.
Training 과정에서 overfitting을 막는 방법
→ 여기서는 data augmentation, dropout을 살펴봄.
Data augmentation
기존 예제에서 추가 training data를 생성
Keras preprocessing layer 사용, 이 레이어는 모델 내에 포함 가능
data_augmentation = keras.Sequential(
[
layers.experimental.preprocessing.RandomFlip("horizontal",
input_shape=(img_height,
img_width,
3)),
layers.experimental.preprocessing.RandomRotation(0.1),
layers.experimental.preprocessing.RandomZoom(0.1),
]
)
augment된 예제 시각화
동일한 이미지에 data augmentation 여러 번 적용하여 증강된 예제 시각화
plt.figure(figsize=(10, 10))
for images, _ in train_ds.take(1):
for i in range(9):
augmented_images = data_augmentation(images)
ax = plt.subplot(3, 3, i + 1)
plt.imshow(augmented_images[0].numpy().astype("uint8"))
plt.axis("off")
Dropout
dropout을 0.2로 입력하면 output unit의 20%를 임의 제거
다음은 layers.Dropout을 사용하여 새로운 신경망 생성한 것
model = Sequential([
data_augmentation,
layers.experimental.preprocessing.Rescaling(1./255),
layers.Conv2D(16, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(32, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Conv2D(64, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
layers.Dropout(0.2), # dropout layer
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dense(num_classes)
])
새로운 데이터로 예측
모델을 사용하여 훈련 또는 검증 세트에 포함되지 않은 이미지 분류
⚠️ data augmentation 및 dropout layer는 predict 시에 비활성화
sunflower_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/592px-Red_sunflower.jpg"
sunflower_path = tf.keras.utils.get_file('Red_sunflower', origin=sunflower_url)
img = keras.preprocessing.image.load_img(
sunflower_path, target_size=(img_height, img_width)
)
img_array = keras.preprocessing.image.img_to_array(img)
img_array = tf.expand_dims(img_array, 0) # Create a batch
predictions = model.predict(img_array)
score = tf.nn.softmax(predictions[0])
print(
"This image most likely belongs to {} with a {:.2f} percent confidence."
.format(class_names[np.argmax(score)], 100 * np.max(score))
)