Notice
Recent Posts
Recent Comments
Link
«   2026/02   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
Tags
more
Archives
Today
Total
관리 메뉴

Silver bullet

Convolutional Neural Network (CNN) 이론 & 구현 실습 본문

AI/AI

Convolutional Neural Network (CNN) 이론 & 구현 실습

밀크쌀과자 2024. 7. 13. 07:58

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