Silver bullet
Convolutional Neural Network (CNN) 이론 & 구현 실습 본문
Object Detection & Recognition
- 이미지 속에 담긴 사물의 위치와 종류를 알아내는 기술
- 입력 이미지에서 후보 영역을 추출한 후 CNN을 적용하여 해당 영역에 무엇이 있는지 예측

5-1. (Advanced) Keras CNN + BN & DataAugment (99.X%)
MNIST with Keras CNN + BN & DataAugment (99.X%)
import tensorflow as tf
from tensorflow.keras import datasets, utils
from tensorflow.keras import models, layers, activations, initializers, losses, optimizers, metrics
import numpy as np
import pandas as pd
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # https://stackoverflow.com/questions/35911252/disable-tensorflow-debugging-information
1. Prepare train & test data (MNIST)
(train_data, train_label), (test_data, test_label) = datasets.mnist.load_data()
# CNN에서는 [28행 x 28열]을 [1행 x 784열]로 펼쳐주지 않아도 됩니다.
# 다만 이미지의 채널에 해당하는 차원을 마지막 차원으로 새로이 추가해줍니다. (MNIST는 흑백 이미지이므로 채널 수를 1로 지정합니다.)
train_data = train_data.reshape(60000, 28, 28, 1) / 255.0
test_data = test_data.reshape(10000, 28, 28, 1) / 255.0
train_label = utils.to_categorical(train_label) # 0~9 -> one-hot vector
test_label = utils.to_categorical(test_label) # 0~9 -> one-hot vector
* 다만 이미지의 채널에 해당하는 차원을 마지막 차원으로 새로이 추가해줍니다. (MNIST는 흑백 이미지이므로 채널 수를 1로 지정합니다.
2. Build the model & Set the criterion
# 3 steps of Convolutional Neural Network
# 1. Convolution (+ Batch Normalization)
# 2. Activation
# 3. (Max) Pooling
# * Repeat 1~3 for adding more hidden layers.
# 4. Connect the network to a fully-connected network (+ Dropout)
# * This fully-connected network makes the model can result in classification.
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), input_shape=(28, 28, 1))) # Filter의 갯수, Filter의 shape, X data point의 shape (이미지 "1장"에 해당)
model.add(layers.BatchNormalization())
model.add(layers.Activation('relu'))
model.add(layers.Conv2D(32, (3, 3)))
model.add(layers.BatchNormalization())
model.add(layers.Activation('relu'))
model.add(layers.MaxPooling2D(pool_size=(2, 2)))
model.add(layers.Conv2D(64, (3, 3)))
model.add(layers.BatchNormalization())
model.add(layers.Activation('relu'))
model.add(layers.Conv2D(64, (3, 3)))
model.add(layers.BatchNormalization())
model.add(layers.Activation('relu'))
model.add(layers.MaxPooling2D(pool_size=(2, 2)))
# Fully-connected network
model.add(layers.Flatten()) # 전체 차원을 펼쳐줍니다.
model.add(layers.Dense(512))
model.add(layers.BatchNormalization())
model.add(layers.Activation('relu'))
model.add(layers.Dropout(rate=0.3))
model.add(layers.Dense(10, activation='softmax'))
* Activation과 Pooling layer는 순서가 뒤바뀔수도 있다.
stride : 윈도우 슬라이딩 할때 몇 발자국? default = 1
padding : valid는 dimention 줄어듦, same은 zero padding으로 dimention 유지
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 26, 26, 32) 320
_________________________________________________________________
batch_normalization (BatchNo (None, 26, 26, 32) 128
_________________________________________________________________
activation (Activation) (None, 26, 26, 32) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 24, 24, 32) 9248
_________________________________________________________________
batch_normalization_1 (Batch (None, 24, 24, 32) 128
_________________________________________________________________
activation_1 (Activation) (None, 24, 24, 32) 0
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 12, 12, 32) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 10, 10, 64) 18496
_________________________________________________________________
batch_normalization_2 (Batch (None, 10, 10, 64) 256
_________________________________________________________________
activation_2 (Activation) (None, 10, 10, 64) 0
_________________________________________________________________
conv2d_3 (Conv2D) (None, 8, 8, 64) 36928
_________________________________________________________________
batch_normalization_3 (Batch (None, 8, 8, 64) 256
_________________________________________________________________
activation_3 (Activation) (None, 8, 8, 64) 0
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 4, 4, 64) 0
_________________________________________________________________
flatten (Flatten) (None, 1024) 0
_________________________________________________________________
dense (Dense) (None, 512) 524800
_________________________________________________________________
batch_normalization_4 (Batch (None, 512) 2048
_________________________________________________________________
activation_4 (Activation) (None, 512) 0
_________________________________________________________________
dropout (Dropout) (None, 512) 0
_________________________________________________________________
dense_1 (Dense) (None, 10) 5130
=================================================================
Total params: 597,738
Trainable params: 596,330
Non-trainable params: 1,408
_________________________________________________________________
model.compile(optimizer=optimizers.Adam(),
loss=losses.categorical_crossentropy,
metrics=[metrics.categorical_accuracy]) # Precision / Recall / F1-Score 적용하기 @ https://j.mp/3cf3lbi
# model.compile(optimizer='adam',
# loss=losses.categorical_crossentropy,
# metrics=['accuracy'])
3. Train the model
ImageDataGenerator 를 활용하면 (Shift + Tab 참고)
- 다양한 Data augmentation을 적용할 수 있습니다.
- rescale 역시도 사전에 적용하지 않고 이 시점에 적용이 가능합니다. (ex. 1/255)
- flow_from_directory() 메서드를 사용하면 이미지 데이터 폴더로부터 direct하게 데이터를 가져와 training에 활용할 수도 있습니다.
-> 참고 : [ (Appendix) 2. Build, Train, and Visualize CNN models (CNN Basic) ] > [ 4. Use ImageDataGenerator for CNN models (for color-images).ipynb ]
* Train data만 augmentation을 진행하고, test data는 그대로 나둔다.
from tensorflow.keras.preprocessing.image import ImageDataGenerator
gen_train = ImageDataGenerator(rotation_range=8, # Degree range for random rotations.
shear_range=0.3, # Shear Intensity (Shear angle in counter-clockwise direction in degrees)
width_shift_range=0.08, # Fraction of total width
height_shift_range=0.08, # Fraction of total height
zoom_range=0.08) # Range for random zoom ([lower, upper] = [1-zoom_range, 1+zoom_range])
train_generator = gen_train.flow(train_data, train_label, batch_size=64) # flow_from_directory() 활용 가능
gen_test = ImageDataGenerator() # Test data에는 Augmentation을 적용하지 않습니다. (Test Time Augmentation)
test_generator = gen_test.flow(test_data, test_label, batch_size=64)
# history = model.fit(train_data, train_label, batch_size=100, epochs=15, validation_data=(test_data, test_label))
history = model.fit(train_generator,
steps_per_epoch=60000 // 64, # == number of batches
epochs=5,
validation_data=test_generator,
validation_steps=10000 // 64)
Epoch 1/5
937/937 [==============================] - 156s 165ms/step - loss: 0.1239 - categorical_accuracy: 0.9617 - val_loss: 0.1003 - val_categorical_accuracy: 0.9649
Epoch 2/5
937/937 [==============================] - 175s 187ms/step - loss: 0.0540 - categorical_accuracy: 0.9831 - val_loss: 0.0394 - val_categorical_accuracy: 0.9870
Epoch 3/5
937/937 [==============================] - 171s 183ms/step - loss: 0.0463 - categorical_accuracy: 0.9859 - val_loss: 0.0327 - val_categorical_accuracy: 0.9896
Epoch 4/5
937/937 [==============================] - 146s 156ms/step - loss: 0.0391 - categorical_accuracy: 0.9874 - val_loss: 0.0271 - val_categorical_accuracy: 0.9910
Epoch 5/5
937/937 [==============================] - 137s 146ms/step - loss: 0.0355 - categorical_accuracy: 0.9889 - val_loss: 0.0197 - val_categorical_accuracy: 0.9931
history = model.fit(train_generator,
steps_per_epoch=60000 // 64, # == number of batches
epochs=5,
validation_data=test_generator,
validation_steps=10000 // 64, callbacks=[~~~~])
4. Test the model
result = model.evaluate(test_data, test_label, batch_size=100)
print('loss (cross-entropy) :', result[0])
print('test accuracy :', result[1])
100/100 [==============================] - 3s 33ms/step - loss: 0.0197 - categorical_accuracy: 0.9931
loss (cross-entropy) : 0.019689518958330154
test accuracy : 0.9930999875068665
# 모델 예측 결과
np.argmax(model.predict(test_data[:10]), axis=1)
# 실제 정답
np.argmax(test_label[:10], axis=1)
5. Visualize the result
history.history.keys()
val_acc = history.history['val_categorical_accuracy']
acc = history.history['categorical_accuracy']
import numpy as np
import matplotlib.pyplot as plt
x_len = np.arange(len(acc))
plt.plot(x_len, acc, marker='.', c='blue', label="Train-set Acc.")
plt.plot(x_len, val_acc, marker='.', c='red', label="Validation-set Acc.")
plt.legend(loc='lower right')
plt.grid()
plt.xlabel('epoch')
plt.ylabel('Accuracy')
plt.show()
horse-or-human data set 실습 (사람 혹은 말 데이터 실습)
1. Prepare the dataset
import tensorflow as tf
import os
import zipfile
import random
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import matplotlib.image as mpimg
# Downloaded from https://storage.googleapis.com/laurencemoroney-blog.appspot.com/horse-or-human.zip
local_zip = 'data/horse-or-human.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('data/horse-or-human')
zip_ref.close()
# Directory with our training horse pictures
train_horse_dir = os.path.join('data/horse-or-human/horses')
# Directory with our training human pictures
train_human_dir = os.path.join('data/horse-or-human/humans')
# Now, see what the filenames look like in the horses and humans training directories:
train_horse_names = os.listdir(train_horse_dir)
print(train_horse_names[:10])
train_human_names = os.listdir(train_human_dir)
print(train_human_names[:10])
print('total training horse images:', len(os.listdir(train_horse_dir)))
print('total training human images:', len(os.listdir(train_human_dir)))
total training horse images: 500
total training human images: 527
from PIL import Image
# 첫 번째 이미지 파일의 경로
first_horse_image_path = os.path.join(train_horse_dir, train_horse_names[0])
first_human_image_path = os.path.join(train_human_dir, train_human_names[0])
# 이미지 열기 및 크기 확인
with Image.open(first_horse_image_path) as img:
print("Horse image size:", img.size) # (width, height)
with Image.open(first_human_image_path) as img:
print("Human image size:", img.size) # (width, height)
Horse image size: (300, 300)
Human image size: (300, 300)
# 이미지 출력해보기
# Parameters for our graph; we'll output images in a 4x4 configuration
nrows = 4
ncols = 4
# Index for iterating over images
pic_index = 0
# Set up matplotlib fig, and size it to fit 4x4 pics
fig = plt.gcf()
fig.set_size_inches(ncols * 4, nrows * 4)
pic_index += 8
next_horse_pix = [os.path.join(train_horse_dir, fname) for fname in train_horse_names[pic_index-8:pic_index]]
next_human_pix = [os.path.join(train_human_dir, fname) for fname in train_human_names[pic_index-8:pic_index]]
for i, img_path in enumerate(next_horse_pix+next_human_pix):
# Set up subplot; subplot indices start at 1
sp = plt.subplot(nrows, ncols, i + 1)
sp.axis('Off') # Don't show axes (or gridlines)
img = mpimg.imread(img_path)
plt.imshow(img)
plt.show()
2. Build a CNN Model & Train the model with ImageDataGenerator
model = tf.keras.models.Sequential([
# Note the input shape is the desired size of the image 300x300 with 3 bytes color
# This is the first convolution
tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(300, 300, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
# The second convolution
tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# The third convolution
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# The fourth convolution
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# The fifth convolution
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# Flatten the results to feed into a DNN
tf.keras.layers.Flatten(),
# 512 neuron hidden layer
tf.keras.layers.Dense(512, activation='relu'),
# Only 1 output neuron. It will contain a value from 0-1 where 0 for 1 class ('horses') and 1 for the other ('humans')
tf.keras.layers.Dense(1, activation='sigmoid')
])
model.summary()
model.compile(loss='binary_crossentropy',
optimizer=tf.keras.optimizers.RMSprop(learning_rate=0.001),
metrics=['accuracy'])
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# All images will be rescaled by 1./255
train_datagen = ImageDataGenerator(rescale = 1./255)
# Flow training images in batches of 128 using train_datagen generator
train_generator = train_datagen.flow_from_directory(
'data/horse-or-human/', # This is the source directory for training images
target_size=(300, 300),
batch_size=128,
class_mode='binary') # Since we use binary_crossentropy loss, we need binary labels
# Available "class_mode" :
# - "categorical" : 2D one-hot encoded labels
# - "binary" : 1D binary labels
# - "sparse" : 1D integer labels
history = model.fit(
train_generator,
steps_per_epoch=8,
epochs=15,
verbose=1)
Epoch 1/15
8/8 [==============================] - 52s 6s/step - loss: 0.7672 - accuracy: 0.5391
Epoch 2/15
8/8 [==============================] - 59s 7s/step - loss: 0.5921 - accuracy: 0.6367
Epoch 3/15
8/8 [==============================] - 50s 6s/step - loss: 0.5419 - accuracy: 0.8076
Epoch 4/15
8/8 [==============================] - 54s 7s/step - loss: 0.5175 - accuracy: 0.8432
Epoch 5/15
8/8 [==============================] - 57s 7s/step - loss: 0.2351 - accuracy: 0.9229
Epoch 6/15
8/8 [==============================] - 68s 9s/step - loss: 0.0619 - accuracy: 0.9805
Epoch 7/15
8/8 [==============================] - 57s 7s/step - loss: 0.1280 - accuracy: 0.9544
Epoch 8/15
8/8 [==============================] - 56s 7s/step - loss: 0.0747 - accuracy: 0.9700
Epoch 9/15
8/8 [==============================] - 52s 6s/step - loss: 0.2434 - accuracy: 0.9121
Epoch 10/15
8/8 [==============================] - 70s 9s/step - loss: 0.0516 - accuracy: 0.9805
Epoch 11/15
8/8 [==============================] - 56s 7s/step - loss: 0.0127 - accuracy: 0.9989
Epoch 12/15
8/8 [==============================] - 60s 7s/step - loss: 0.0044 - accuracy: 1.0000
Epoch 13/15
8/8 [==============================] - 62s 8s/step - loss: 0.0013 - accuracy: 1.0000
Epoch 14/15
8/8 [==============================] - 82s 10s/step - loss: 0.5828 - accuracy: 0.8821
Epoch 15/15
8/8 [==============================] - 59s 7s/step - loss: 0.0600 - accuracy: 0.9844
3. Predict on an image & visualize the layer and filter
from tensorflow.keras.preprocessing import image
# predicting images
file_name = 'human_1.jpeg'
path = 'data/test/' + file_name
img = image.load_img(path, target_size=(300, 300))
x = image.img_to_array(img)
x = x.reshape(1, 300, 300, 3)
predicted_class = model.predict(x)[0]
print('Predicted class is :', predicted_class)
if predicted_class > 0.5:
print(file_name + " is a human")
else:
print(file_name + " is a horse")
Predicted class is : [1.]
human_1.jpeg is a human
꽃 이미지 데이터 실습
import os
from glob import glob
from PIL import Image
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
# 약 3,700장의 꽃 사진 데이터세트를 사용합니다.
# 아래 데이터 가져오기 그냥 사용합니다.
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)
# 이미지 패스 확인
data_dir
# 이미지 폴더 밑의 폴더 확인
!ls -l /root/.keras/datasets/flower_photos/
# daisy 폴더 안의 이지미 갯수
!ls -l /root/.keras/datasets/flower_photos/daisy | grep jpg | wc -l
# 이미지 패스 지정
daisy_path = '/root/.keras/datasets/flower_photos/daisy/'
dandelion_path = '/root/.keras/datasets/flower_photos/dandelion/'
roses_path = '/root/.keras/datasets/flower_photos/roses/'
sunflowers_path = '/root/.keras/datasets/flower_photos/sunflowers/'
tulips_path = '/root/.keras/datasets/flower_photos/tulips/'
# 이미지 패스의 파말 리스트 만들기
daisy_file = os.listdir(daisy_path)
dandelion_file = os.listdir(dandelion_path)
roses_file = os.listdir(roses_path)
sunflowers_file = os.listdir(sunflowers_path)
tulips_file = os.listdir(tulips_path)
# 위의 파일 리스트에서 2개씩 읽고 이미지 출력하기
for img_file in daisy_file[:2] :
img = Image.open(daisy_path + img_file).resize((224,224))
plt.title(img_file + ' : daisy')
plt.imshow(img)
plt.show()
for img_file in roses_file[:2] :
img = Image.open(roses_path + img_file).resize((224,224))
plt.title(img_file + ' : roses')
plt.imshow(img)
plt.show()
# Class 라벨 정의
class2idx = {'daisy' : 0, 'dandelion' : 1, 'roses' : 2, 'sunflowers' : 3, 'tulips' : 4}
idx2class = {0 : 'daisy', 1 : 'dandelion', 2 : 'roses', 3 : 'sunflowers', 4 : 'tulips'}
# 수작업으로 이미지 리스트와 라벨 리스트 만들기
img_list = []
label_list = []
daisy_file = os.listdir(daisy_path)
for img_file in daisy_file :
img = Image.open(daisy_path + img_file).resize((128,128))
img = np.array(img)/255. # 이미지 스케일링 0과 1 사이의 숫자를 가지게 함
img_list.append(img)
label_list.append(0) # daisy : 0
dandelion_file = os.listdir(dandelion_path)
for img_file in dandelion_file :
img = Image.open(dandelion_path + img_file).resize((128,128))
img = np.array(img)/255. # 이미지 스케일링
img_list.append(img)
label_list.append(1) # dandelion : 1
roses_file = os.listdir(roses_path)
for img_file in roses_file :
img = Image.open(roses_path + img_file).resize((128,128))
img = np.array(img)/255. # 이미지 스케일링
img_list.append(img)
label_list.append(2) # roses : 2
sunflowers_file = os.listdir(sunflowers_path)
for img_file in sunflowers_file :
img = Image.open(sunflowers_path + img_file).resize((128,128))
img = np.array(img)/255. # 이미지 스케일링
img_list.append(img)
label_list.append(3) # sunflowers : 3
tulips_file = os.listdir(tulips_path)
for img_file in tulips_file :
img = Image.open(tulips_path + img_file).resize((128,128))
img = np.array(img)/255. # 이미지 스케일링
img_list.append(img)
label_list.append(4) # tulips : 4
# 이미지 리스트, 라벨 리스트루 numpy array 변경
img_list_arr = np.array(img_list)
label_list_arr = np.array(label_list)
# 이미지 리스트, 라벨 리스트 shape 확인
img_list_arr.shape, label_list_arr.shape
((3670, 128, 128, 3), (3670,))
from sklearn.model_selection import train_test_split
X_train, X_test , y_train, y_test = train_test_split(img_list_arr, label_list_arr, test_size=0.3, stratify=label_list_arr, random_state=41)
X_train.shape, X_test.shape , y_train.shape, y_test.shape
((2569, 128, 128, 3), (1101, 128, 128, 3), (2569,), (1101,))
# Hyperparameter Tunning
num_epochs = 10
batch_size = 32
learning_rate = 0.001
dropout_rate = 0.5
input_shape = (128, 128, 3) # 사이즈 확인
# Sequential 모델 정의
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D
model = Sequential()
model.add(Conv2D(32, kernel_size=(5,5), strides=(1,1), padding='same', activation='relu', input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Conv2D(64,(2,2), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(5, activation='softmax'))
# 모델 컴파일
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate), # Optimization
loss='sparse_categorical_crossentropy', # Loss Function
metrics=['accuracy']) # Metrics / Accuracy
model.summary()
# callback : EarlyStopping, ModelCheckpoint
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
# EarlyStopping
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=5)
# ModelCheckpoint
checkpoint_path = "my_checkpoint.ckpt"
checkpoint = ModelCheckpoint(filepath=checkpoint_path,
save_best_only=True,
monitor='val_loss',
verbose=1)
# num_epochs = 10
# batch_size = 32
# 모델 학습(fit)
history = model.fit(
X_train, y_train ,
validation_data=(X_test, y_test),
epochs=num_epochs,
batch_size=batch_size,
callbacks=[es, checkpoint]
)
Epoch 1/10
81/81 [==============================] - ETA: 0s - loss: 1.5471 - accuracy: 0.3877
Epoch 1: val_loss improved from inf to 1.16877, saving model to my_checkpoint.ckpt
81/81 [==============================] - 10s 62ms/step - loss: 1.5471 - accuracy: 0.3877 - val_loss: 1.1688 - val_accuracy: 0.5431
Epoch 2/10
81/81 [==============================] - ETA: 0s - loss: 1.1085 - accuracy: 0.5543
Epoch 2: val_loss improved from 1.16877 to 1.04875, saving model to my_checkpoint.ckpt
81/81 [==============================] - 3s 40ms/step - loss: 1.1085 - accuracy: 0.5543 - val_loss: 1.0487 - val_accuracy: 0.5858
Epoch 3/10
79/81 [============================>.] - ETA: 0s - loss: 0.9870 - accuracy: 0.6175
Epoch 3: val_loss improved from 1.04875 to 1.00997, saving model to my_checkpoint.ckpt
81/81 [==============================] - 3s 38ms/step - loss: 0.9855 - accuracy: 0.6189 - val_loss: 1.0100 - val_accuracy: 0.6040
Epoch 4/10
79/81 [============================>.] - ETA: 0s - loss: 0.9084 - accuracy: 0.6487
Epoch 4: val_loss improved from 1.00997 to 0.95960, saving model to my_checkpoint.ckpt
81/81 [==============================] - 3s 38ms/step - loss: 0.9073 - accuracy: 0.6493 - val_loss: 0.9596 - val_accuracy: 0.6285
Epoch 5/10
81/81 [==============================] - ETA: 0s - loss: 0.7585 - accuracy: 0.7096
Epoch 5: val_loss improved from 0.95960 to 0.93284, saving model to my_checkpoint.ckpt
81/81 [==============================] - 4s 45ms/step - loss: 0.7585 - accuracy: 0.7096 - val_loss: 0.9328 - val_accuracy: 0.6485
Epoch 6/10
80/81 [============================>.] - ETA: 0s - loss: 0.5596 - accuracy: 0.7957
Epoch 6: val_loss did not improve from 0.93284
81/81 [==============================] - 2s 26ms/step - loss: 0.5600 - accuracy: 0.7960 - val_loss: 0.9781 - val_accuracy: 0.6449
Epoch 7/10
79/81 [============================>.] - ETA: 0s - loss: 0.4546 - accuracy: 0.8366
Epoch 7: val_loss did not improve from 0.93284
81/81 [==============================] - 2s 24ms/step - loss: 0.4571 - accuracy: 0.8361 - val_loss: 1.0370 - val_accuracy: 0.6485
Epoch 8/10
79/81 [============================>.] - ETA: 0s - loss: 0.3492 - accuracy: 0.8774
Epoch 8: val_loss did not improve from 0.93284
81/81 [==============================] - 2s 24ms/step - loss: 0.3510 - accuracy: 0.8762 - val_loss: 1.1204 - val_accuracy: 0.6440
Epoch 9/10
79/81 [============================>.] - ETA: 0s - loss: 0.2656 - accuracy: 0.9082
Epoch 9: val_loss did not improve from 0.93284
81/81 [==============================] - 2s 24ms/step - loss: 0.2686 - accuracy: 0.9074 - val_loss: 1.1296 - val_accuracy: 0.6503
Epoch 10/10
79/81 [============================>.] - ETA: 0s - loss: 0.2022 - accuracy: 0.9296
Epoch 10: val_loss did not improve from 0.93284
81/81 [==============================] - 2s 24ms/step - loss: 0.2012 - accuracy: 0.9303 - val_loss: 1.2123 - val_accuracy: 0.6394
Epoch 10: early stopping
history.history.keys()
plt.plot(history.history['accuracy'], label='Accuracy')
plt.plot(history.history['val_accuracy'], label='Val Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.title('Model Accuracy')
plt.show()
# Test 데이터로 성능 예측하기
i=1
plt.figure(figsize=(16, 8))
for img, label in zip(X_test[:8], y_test[:8]):
# 모델 예측(predict)
pred = model.predict(img.reshape(-1,128, 128, 3))
pred_t = np.argmax(pred)
plt.subplot(2, 4, i)
plt.title(f'True Value:{label}, Pred Value: {pred_t}')
plt.imshow(img)
plt.axis('off')
i = i + 1
Image_dataset_from_directory 이용하여 데이터셋 만들기
from glob import glob
import os
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
# 약 3,700장의 꽃 사진 데이터세트를 사용합니다.
# 아래 데이터 가져오기 그냥 사용합니다.
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)
# 하이터 파라미터 정의
input_shape = (224, 224, 3)
batch_size = 32
num_classes = 5
# 이미지 패스 지정
img_path ='/root/.keras/datasets/flower_photos/'
# image_dataset_from_directory 함수 활용하여
# 이미지 폴더 밑의 이미지들에 대해 원핫인코딩된 labeling수행, 이미지 배치, 셔플 수행
# Train Dataset 만들기
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
directory=img_path,
label_mode="categorical", # binary , categorical
batch_size=batch_size,
image_size=(224, 224), # 사이즈 확인
seed=42,
shuffle=True,
validation_split=0.2,
subset="training" # One of "training" or "validation". Only used if validation_split is set.
)
# Test Dataset 만들기
test_ds = tf.keras.preprocessing.image_dataset_from_directory(
directory=img_path,
label_mode="categorical", # binary , categorical
batch_size=batch_size,
image_size=(224, 224), # 사이즈 확인
seed=42,
validation_split=0.2,
subset="validation" # One of "training" or "validation". Only used if validation_split is set.
)
# Class 이름 확인
train_ds.class_names
# 40,000건 중에서 32,000건 Train 사용. test용으로 8,000건 사용
len(train_ds) * 32 , len(test_ds) * 32
batch_img, batch_label = next(iter(train_ds))
batch_img.shape, batch_label.shape
(TensorShape([32, 224, 224, 3]), TensorShape([32, 5]))
# Hyperparameter Tunning
num_epochs = 10
batch_size = 32
learning_rate = 0.001
dropout_rate = 0.5
input_shape = (224, 224, 3) # 사이즈 확인
num_classes = 5
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D, Rescaling
model = Sequential()
model.add(Rescaling(1. / 255)) # 이미지 Rescaling. 없이 하면 성능이 안나옴.
model.add(Conv2D(32, kernel_size=(5,5), strides=(1,1), padding='same', activation='relu', input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Conv2D(64,(2,2), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(5, activation='softmax'))
# Model compile
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate), # Optimization
loss='categorical_crossentropy', # Loss Function
metrics=['accuracy']) # Metrics / Accuracy
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
# EarlyStopping
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=3)
# ModelCheckpoint
checkpoint_path = "my_checkpoint.ckpt"
checkpoint = ModelCheckpoint(filepath=checkpoint_path,
save_best_only=True,
monitor='val_loss',
verbose=1)
# image_dataset_from_directory 이용하여 데이터 만들었을때 아래와 같이 학습 진행
# num_epochs = 10
# 모델 학습(fit)
history = model.fit(
train_ds,
validation_data=(test_ds),
epochs=10,
callbacks=[es, checkpoint]
)
history.history.keys()
plt.plot(history.history['accuracy'], label='Accuracy')
plt.plot(history.history['val_accuracy'], label='Val Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.title('Model Accuracy')
plt.show()
predict
# 배치사이즈 이미지/라벨 가져오기
batch_img , batch_label = next(iter(test_ds))
type(batch_img), batch_img.shape
# Test 데이터로 성능 예측하기
i = 1
plt.figure(figsize=(16, 30))
for img, label in list(zip(batch_img, batch_label)):
pred = model.predict(img.numpy().reshape(-1, 224,224,3), verbose=0)
pred_t = np.argmax(pred)
plt.subplot(8, 4, i)
plt.title(f'True Value:{np.argmax(label)}, Pred Value: {pred_t}')
plt.imshow(img/255) # 이미지 픽셀값들이 실수형이므로 0~1 사이로 변경해야 에러 안남
i = i + 1