Regularization แบบสมัยใหม่ ด้วยเทคนิค Augmentation, Batch Normalization

Pattharadet Vachirapuchai
8 min readOct 7, 2020

Regularization

Regularization คือ การปรับแต่งให้ Model มีประสิทธิภาพในการทำนายที่ดี ลด Error จากข้อมูลที่มันไม่เคยเห็นมาก่อน ด้วยการเรียนรู้จาก Training Dataset และ Regularization เป็นวิธีที่ใช้เพื่อแก้ปัญหา Underfitting หรือ Overfitting ของ Machine Learning Model ก็ได้

เริ่มที่ Fashion-MNIST Dataset

Import Library ที่จำเป็น

from tensorflow.keras.models import Sequential

from tensorflow.keras.layers import Dense, Activation, Conv2D, MaxPool2D, Flatten, Dropout, BatchNormalization

from tensorflow.keras.optimizers import RMSprop,Adam

from tensorflow.keras.utils import to_categorical

from tensorflow.keras.preprocessing.image import ImageDataGenerator

from sklearn.model_selection import train_test_split

import matplotlib.pyplot as plt

from tensorflow.keras.datasets import fashion_mnist

import plotly.graph_objs as go

import cv2

import plotly.subplots as tools

from plotly.offline import iplot

กำหนดค่า

IMG_ROWS = 28

IMG_COLS = 28

NUM_CLASSES = 10

TEST_SIZE = 0.2

RANDOM_STATE = 99

NO_EPOCHS = 10

BATCH_SIZE = 128

Load Dataset

(train_data, y), (test_data, y_test) = fashion_mnist.load_data()

print(“Fashion MNIST train — rows:”,train_data.shape[0],” columns:”, train_data.shape[1], “ rows:”, train_data.shape[2])

print(“Fashion MNIST test — rows:”,test_data.shape[0],” columns:”, test_data.shape[1], “ rows:”, train_data.shape[2])

แสดงรูป

for i in range(9):

plt.subplot(330 + 1 + i)

plt.imshow(train_data[i], cmap=plt.get_cmap(‘gray’))

plt.show()

ขยายมิติของ Dataset

print(train_data.shape, test_data.shape)

train_data = train_data.reshape((train_data.shape[0], 28, 28, 1))

test_data = test_data.reshape((test_data.shape[0], 28, 28, 1))

print(train_data.shape, test_data.shape)

Scaling

train_data = train_data / 255.0

test_data = test_data / 255.0

เข้ารหัสผลเฉลยแบบ One-hot Encoding

print(y.shape, y_test.shape)

print(y[:10])

y = to_categorical(y)

y_test = to_categorical(y_test)

print(y.shape, y_test.shape)

y[:10]

Train และ Validate โดยการสุ่มในสัดส่วน 80:20

X_train, X_val, y_train, y_val = train_test_split(train_data, y, test_size=TEST_SIZE, random_state=RANDOM_STATE)

X_train.shape, X_val.shape, y_train.shape, y_val.shape

Baseline Model

นิยาม Model, Compile Model และ Train Model โดยยังไม่ใช้เทคนิค Regularization

นิยาม Model

model = Sequential()

#1. CNN LAYER

model.add(Conv2D(filters = 32, kernel_size = (3,3), padding = ‘Same’, input_shape=(28, 28, 1)))

model.add(Activation(“relu”))

#2. CNN LAYER

model.add(Conv2D(filters = 32, kernel_size = (3,3), padding = ‘Same’))

model.add(Activation(“relu”))

model.add(MaxPool2D(pool_size=(2, 2)))

#3. CNN LAYER

model.add(Conv2D(filters = 64, kernel_size = (3,3), padding = ‘Same’))

model.add(Activation(“relu”))

#4. CNN LAYER

model.add(Conv2D(filters = 64, kernel_size = (3,3), padding = ‘Same’))

model.add(Activation(“relu”))

model.add(MaxPool2D(pool_size=(2, 2)))

#FULLY CONNECTED LAYER

model.add(Flatten())

model.add(Dense(256))

model.add(Activation(“relu”))

#OUTPUT LAYER

model.add(Dense(10, activation=’softmax’))

Compile Model

optimizer = Adam()

model.compile(optimizer = optimizer, loss = “categorical_crossentropy”, metrics=[“accuracy”])

model.summary()

Train Model

train_model = model.fit(X_train, y_train,

batch_size=BATCH_SIZE,

epochs=NO_EPOCHS,

verbose=1,

validation_data=(X_val, y_val))

Evaluation

def create_trace(x,y,ylabel,color):

trace = go.Scatter(

x = x,y = y,

name=ylabel,

marker=dict(color=color),

mode = “markers+lines”,

text=x

)

return trace

def plot_accuracy_and_loss(train_model):

hist = train_model.history

acc = hist[‘accuracy’]

val_acc = hist[‘val_accuracy’]

loss = hist[‘loss’]

val_loss = hist[‘val_loss’]

epochs = list(range(1,len(acc)+1))

trace_ta = create_trace(epochs,acc,”Training accuracy”, “Green”)

trace_va = create_trace(epochs,val_acc,”Validation accuracy”, “Red”)

trace_tl = create_trace(epochs,loss,”Training loss”, “Blue”)

trace_vl = create_trace(epochs,val_loss,”Validation loss”, “Magenta”)

fig = make_subplots(rows=1,cols=2, subplot_titles=(‘Training and validation accuracy’,

‘Training and validation loss’))

fig.append_trace(trace_ta,1,1)

fig.append_trace(trace_va,1,1)

fig.append_trace(trace_tl,1,2)

fig.append_trace(trace_vl,1,2)

fig[‘layout’][‘xaxis’].update(title = ‘Epoch’)

fig[‘layout’][‘xaxis2’].update(title = ‘Epoch’)

fig[‘layout’][‘yaxis’].update(title = ‘Accuracy’, range=[0,1])

fig[‘layout’][‘yaxis2’].update(title = ‘Loss’, range=[0,1])

iplot(fig, filename=’accuracy-loss’)

score = model.evaluate(test_data, y_test,verbose=0)
print(“Test Loss:”,score[0])
print(“Test Accuracy:”,score[1])

ได้ค่าTest Loss: 0.30274444818496704

Test Accuracy: 0.917900025844574

Image Augmentation

คือ ปัญหา Overfitting ของ Model สามารถแก้ได้ด้วยการเพิ่มจำนวน Data ในการ Train แต่ด้วย Dataset ของเรามีจำกัด ดังนั้นในบางกรณีเราจึงต้องสังเคราะห์ Data ขึ้นมาเอง ในกรณีของ Data แบบ Image เราสามารถใช้เทคนิคอย่างเช่นการหมุนภาพ การเลื่อนภาพ และการกลับภาพ ฯลฯ ซึ่งนอกจากเป็นการขยายจำนวน Data แล้ว Image Augmentation ยังช่วยเพิ่มความหลากหลายของภาพที่จะนำไป Train อีกด้วย

หารูปที่อยาากทดลองทำมารูปนึงแล้วเรียกใช้รูปนั้น

cat = cv2.imread(‘/content/bc0e4dbb-d157–429e-b865-bab8ac879c96.jpg’)

cat.shape

แปลงระบบสีเป็นค่า Default ของ OpenCV Library เป็น RGB

cat = cv2.cvtColor(cat, cv2.COLOR_RGB2BGR)

Plot ภาพ

plt.figure(dpi=100)

plt.imshow(cat)

ขยายมิติของภาพจาก 3 มิติเป็น 4 มิติ

print(cat.shape)

cat = cat.reshape(1,cat.shape[0],cat.shape[1],cat.shape[2])

print(cat.shape)

ทำ Vertical Shift ด้วยการเลื่อนภาพขึ้นลงแบบสุ่มไม่เกิน 20%

datagen = ImageDataGenerator(height_shift_range=0.2)

aug_iter = datagen.flow(cat, batch_size=1)

fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(15,15))

for i in range(3):

image = next(aug_iter)[0].astype(‘uint8’)

ax[i].imshow(image)

ax[i].axis(‘off’)

ทำ Horizontal Shift ด้วยการเลื่อนภาพซ้ายขวาแบบสุ่มไม่เกิน 20%

datagen = ImageDataGenerator(width_shift_range=0.2)

aug_iter = datagen.flow(cat, batch_size=1)

fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(15,15))

for i in range(3):

image = next(aug_iter)[0].astype(‘uint8’)

ax[i].imshow(image)

ax[i].axis(‘off’)

บิดภาพ (Shear) แบบสุ่มไม่เกิน 20 องศา

datagen = ImageDataGenerator(shear_range=20)

aug_iter = datagen.flow(cat, batch_size=1)

fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(15,15))

for i in range(3):

image = next(aug_iter)[0].astype(‘uint8’)

ax[i].imshow(image)

ax[i].axis(‘off’)

ขยายภาพ (Zoom) แบบสุ่มไม่เกิน 30%

datagen = ImageDataGenerator(zoom_range=0.3)

aug_iter = datagen.flow(cat, batch_size=1)

fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(15,15))

for i in range(3):

image = next(aug_iter)[0].astype(‘uint8’)

ax[i].imshow(image)

ax[i].axis(‘off’)

พลิกภาพแนวตั้ง (Vertical Flip) แบบสุ่ม

datagen = ImageDataGenerator(vertical_flip=True)

aug_iter = datagen.flow(cat, batch_size=1)

fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(15,15))

for i in range(3):

image = next(aug_iter)[0].astype(‘uint8’)

ax[i].imshow(image)

ax[i].axis(‘off’)

fig.savefig(‘cat.jpeg’, dpi=300)

พลิกภาพแนวนอน (Horizontal Flip) แบบสุ่ม

datagen = ImageDataGenerator(horizontal_flip=True)

aug_iter = datagen.flow(cat, batch_size=1)

fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(15,15))

for i in range(3):

image = next(aug_iter)[0].astype(‘uint8’)

ax[i].imshow(image)

ax[i].axis(‘off’)

หมุนภาพ (Rotate) ไม่เกิน 30 องศา แบบสุ่ม

datagen = ImageDataGenerator(rotation_range=30)

aug_iter = datagen.flow(cat, batch_size=1)

fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(15,15))

for i in range(3):

image = next(aug_iter)[0].astype(‘uint8’)

ax[i].imshow(image)

ax[i].axis(‘off’)

Fill Mode

เมื่อมีการเลื่อนภาพ บิดภาพ หมุนภาพ จะเกิดพื้นที่ว่างที่มุม ซึ่งจะมีการเติมภาพให้เต็มโดยใช้เทคนิคแบบ Nearest Neighbor ซึ่งเป็นการดึงสีบริเวณใกล้เคียงมาระบาย แต่เราก็ยังสามารถกำหนดวิธีการเติมสีลงในภาพ (Fill) ด้วยเทคนิคอื่นได้จาก Parameter fill_mode

เติมสีดำ (Constant Values)

datagen = ImageDataGenerator(rotation_range=30, fill_mode = ‘constant’)

aug_iter = datagen.flow(cat, batch_size=1)

fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(15,15))

for i in range(3):

image = next(aug_iter)[0].astype(‘uint8’)

ax[i].imshow(image)

ax[i].axis(‘off’)

เติมสีข้างเคียง (Nearest Neighbor)

datagen = ImageDataGenerator(rotation_range=30, fill_mode = ‘nearest’)

aug_iter = datagen.flow(cat, batch_size=1)

fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(15,15))

for i in range(3):

image = next(aug_iter)[0].astype(‘uint8’)

ax[i].imshow(image)

ax[i].axis(‘off’)

เติมสีแบบกระจกสะท้อน (Reflect Values)

datagen = ImageDataGenerator(rotation_range=50, fill_mode = ‘reflect’)

aug_iter = datagen.flow(cat, batch_size=1)

fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(15,15))

for i in range(3):

image = next(aug_iter)[0].astype(‘uint8’)

ax[i].imshow(image)

ax[i].axis(‘off’)

เติมสีจากภาพแบบต่อกัน (Wrap Values)

datagen = ImageDataGenerator(rotation_range=30, fill_mode = ‘wrap’)

aug_iter = datagen.flow(cat, batch_size=1)

fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(15,15))

for i in range(3):

image = next(aug_iter)[0].astype(‘uint8’)

ax[i].imshow(image)

ax[i].axis(‘off’)

เราจะเพิ่มความหลากหลายของภาพเพื่อแก้ปัญหา Overfitting ตามขั้นตอนดังนี้

นิยามวิธีการทำ Image Augmentation

datagen = ImageDataGenerator(

rotation_range=0.05, #Randomly rotate images in the range

zoom_range = 0.2, # Randomly zoom image

width_shift_range=0.1, #Randomly shift images horizontally

height_shift_range=0.1, #Randomly shift images vertically

shear_range=0.05 #Randomly shear images

)

datagen.fit(X_train)

นิยาม Model

model = Sequential()

#1. CNN LAYER

model.add(Conv2D(filters = 32, kernel_size = (3,3), padding = ‘Same’, input_shape=(28, 28, 1)))

model.add(Activation(“relu”))

#2. CNN LAYER

model.add(Conv2D(filters = 32, kernel_size = (3,3), padding = ‘Same’))

model.add(Activation(“relu”))

model.add(MaxPool2D(pool_size=(2, 2)))

#3. CNN LAYER

model.add(Conv2D(filters = 64, kernel_size = (3,3), padding = ‘Same’))

model.add(Activation(“relu”))

#4. CNN LAYER

model.add(Conv2D(filters = 64, kernel_size = (3,3), padding = ‘Same’))

model.add(Activation(“relu”))

model.add(MaxPool2D(pool_size=(2, 2)))

#FULLY CONNECTED LAYER

model.add(Flatten())

model.add(Dense(256))

model.add(Activation(“relu”))

#OUTPUT LAYER

model.add(Dense(10, activation=’softmax’))

Compile Model

optimizer = Adam()

model.compile(optimizer = optimizer, loss = “categorical_crossentropy”, metrics=[“accuracy”])

model.summary()

Train Model

NO_EPOCHS = 30

history = model.fit_generator(datagen.flow(X_train, y_train, batch_size=BATCH_SIZE),shuffle=True,epochs=NO_EPOCHS, validation_data = (X_val, y_val),verbose = 1, steps_per_epoch=X_train.shape[0] // BATCH_SIZE)

Plot กราฟ

plot_accuracy_and_loss(history)

วัดค่า Accuracy จาก Test Dataset

score = model.evaluate(test_data, y_test,verbose=0)

print(“Test Loss:”,score[0])

print(“Test Accuracy:”,score[1])

Batch Normalization

ป็นเทคนิคในการทำ Scaling Data หรือเรียกอีกอย่างหนึ่งว่าการทำ Normalization เพื่อปรับค่าข้อมูลให้อยู่ในขอบเขตที่กำหนด ก่อนส่งออกจาก Node ใน Neural Network Layer เป็น Input ของ Layer ถัดไป

นิยาม Image Augmentation

datagen = ImageDataGenerator(

rotation_range=0.05, # Randomly rotate images in the range

zoom_range = 0.2, # Randomly zoom image

width_shift_range=0.1, # Randomly shift images horizontally

height_shift_range=0.1, # Randomly shift images vertically

shear_range=0.05

)

datagen.fit(X_train)

นิยาม Model

model = Sequential()

#1. CNN LAYER

model.add(Conv2D(filters = 32, kernel_size = (3,3), padding = ‘Same’, input_shape=(28, 28, 1)))

model.add(BatchNormalization())

model.add(Activation(“relu”))

#2. CNN LAYER

model.add(Conv2D(filters = 32, kernel_size = (3,3), padding = ‘Same’))

model.add(BatchNormalization())

model.add(Activation(“relu”))

model.add(MaxPool2D(pool_size=(2, 2)))

#3. CNN LAYER

model.add(Conv2D(filters = 64, kernel_size = (3,3), padding = ‘Same’))

model.add(BatchNormalization())

model.add(Activation(“relu”))

#4. CNN LAYER

model.add(Conv2D(filters = 64, kernel_size = (3,3), padding = ‘Same’))

model.add(BatchNormalization())

model.add(Activation(“relu”))

model.add(MaxPool2D(pool_size=(2, 2)))

#FULLY CONNECTED LAYER

model.add(Flatten())

model.add(Dense(256))

model.add(BatchNormalization())

model.add(Activation(“relu”))

#OUTPUT LAYER

model.add(Dense(10, activation=’softmax’))

Compile Model

optimizer = Adam()

model.compile(optimizer = optimizer, loss = “categorical_crossentropy”, metrics=[“accuracy”])

model.summary()

Train Model

NO_EPOCHS = 50

history = model.fit_generator(datagen.flow(X_train, y_train, batch_size=BATCH_SIZE),shuffle=True,epochs=NO_EPOCHS, validation_data = (X_val, y_val),verbose = 1, steps_per_epoch=X_train.shape[0] // BATCH_SIZE)

Plot กราฟ

plot_accuracy_and_loss(history)

วัดค่า Accuracy จาก Test Dataset

score = model.evaluate(test_data, y_test,verbose=0)

print(“Test Loss:”,score[0])

print(“Test Accuracy:”,score[1])

Dropout

Dropout เป็นเทคนิคในการทำ Regularization ที่เรียบง่าย แต่มีประสิทธิภาพอย่างมาก โดยเมื่อมีการใช้งาน Dropout ภายใน Layer ที่กำหนดแล้ว Node ใน Layer นั้นจะถูกสุ่มเพื่อปิดการทำงานชั่วคราวในแต่ละรอบของการทำ Forward Propagation และ Back-propagation ตามอัตราที่กำหนด ในขณะที่มีการ Train Model ทำให้ไม่มีการ Update Weight ใดๆ ที่ถูกเชื่อมต่อกับ Neural Node ที่กำลังถูกปิด

นิยาม

datagen = ImageDataGenerator(

rotation_range=0.05, #Randomly rotate images in the range

zoom_range = 0.2, # Randomly zoom image

width_shift_range=0.1, #Randomly shift images horizontally

height_shift_range=0.1, #Randomly shift images vertically

shear_range=0.05 #Randomly shear images

)

datagen.fit(X_train)

นิยาม Model

model = Sequential()

#1. CNN LAYER

model.add(Conv2D(filters = 32, kernel_size = (3,3), padding = ‘Same’, input_shape=(28, 28, 1)))

model.add(BatchNormalization())

model.add(Activation(“relu”))

model.add(Dropout(0.3))

#2. CNN LAYER

model.add(Conv2D(filters = 32, kernel_size = (3,3), padding = ‘Same’))

model.add(BatchNormalization())

model.add(Activation(“relu”))

model.add(MaxPool2D(pool_size=(2, 2)))

model.add(Dropout(0.3))

#3. CNN LAYER

model.add(Conv2D(filters = 64, kernel_size = (3,3), padding = ‘Same’))

model.add(BatchNormalization())

model.add(Activation(“relu”))

model.add(Dropout(0.3))

#4. CNN LAYER

model.add(Conv2D(filters = 64, kernel_size = (3,3), padding = ‘Same’))

model.add(BatchNormalization())

model.add(Activation(“relu”))

model.add(MaxPool2D(pool_size=(2, 2)))

model.add(Dropout(0.3))

#FULLY CONNECTED LAYER

model.add(Flatten())

model.add(Dense(256))

model.add(BatchNormalization())

model.add(Activation(“relu”))

model.add(Dropout(0.30))

#OUTPUT LAYER

model.add(Dense(10, activation=’softmax’))

Compile Model

optimizer = Adam()

model.compile(optimizer = optimizer, loss = “categorical_crossentropy”, metrics=[“accuracy”])

model.summary()

Train Model

NO_EPOCHS = 50

history = model.fit_generator(datagen.flow(X_train, y_train, batch_size=BATCH_SIZE),

shuffle=True,

epochs=NO_EPOCHS, validation_data = (X_val, y_val),

verbose = 1, steps_per_epoch=X_train.shape[0] // BATCH_SIZE)

Plot กราฟ

plot_accuracy_and_loss(history)

วัดค่า Accuracy จาก Test Dataset

score = model.evaluate(test_data, y_test,verbose=0)

print(“Test Loss:”,score[0])

print(“Test Accuracy:”,score[1])

Datasetได้ค่า Accuracy 94.06

จบแล้วครับสำหรับ การทำ Regularization แบบสมัยใหม่ ด้วยเทคนิค Augmentation, Batch Normalization

เจอกันใหม่บทความหน้าครับ

--

--