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

Phromma P
9 min readOct 7, 2020

--

การเพิ่มประสิทธิภาพ Machine Learning Model มีวิธีการหลัก 2 อย่าง ที่ต้องให้ความสำคัญ คือ

1.การลด Generalization Error ด้วย Regularization

2.การลด Cost Value ด้วย Optimization หรือการหาค่าที่เหมาะสมที่สุด

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

ดังนั้นจึงกล่าวอีกอย่างหนึ่งว่า Regularization คือ วิธีที่ใช้เพื่อแก้ปัญหา Underfitting หรือ Overfitting ของ Machine Learning Model ก็ได้

เราจะทดลองแก้ปัญหา Overfitting ของ Neural Network แบบ Classification Model ที่มีการ Train ด้วย Fashion-MNIST Dataset โดยยกตัวอย่างเทคนิคที่เป็นที่นิยมในปัจจุบัน 3 เทคนิค ได้แก่

  • Augmentation
  • Batch Normalization
  • Dropout

ซึ่งในที่สุดแล้วจะทำให้สามารถเพิ่มประสิทธิภาพของ Model ได้มากน้อยเท่าไหร่

Fashion-MNIST เป็น Dataset ที่เป็นภาพเสื้อผ้า กระเป๋า และรองเท้า ขนาด 28x28 Pixel แบบ Grayscale แบ่งเป็นข้อมูล Train 60,000 ภาพ และข้อมูล Test อีก 10,000 ภาพ รวมทั้งหมด 10 ประเภท โดยมีการกำหนด Label ตั้งแต่ 0–9 ดังนี้

  • 0 = T-shirt/top
  • 1 = Trouser
  • 2 = Pullover
  • 3 = Dress
  • 4 = Coat
  • 5 = Sandal
  • 6 = Shirt
  • 7 = Sneaker
  • 8 = Bag
  • 9 = Ankle boot

สำหรับเครื่องคอมพิวเตอร์ที่มี GPU สามารถ Config การใช้งาน ด้วยคำสั่งต่อไปนี้

!nvidia-smi -L
import tensorflow as tf
tf.__version__config = tf.compat.v1.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.compat.v1.Session(config=config)

print( 'Tensorflow Version:', tf.__version__)
print("GPU Available::", tf.config.list_physical_devices('GPU'))

Import Library และกำหนดค่า Parameter ที่จำเป็น

from tensorflow.keras.models import Sequentialfrom tensorflow.keras.layers import Dense, Activation, Conv2D, MaxPool2D, Flatten, Dropout, BatchNormalizationfrom tensorflow.keras.optimizers import RMSprop,Adamfrom tensorflow.keras.utils import to_categoricalfrom tensorflow.keras.preprocessing.image import ImageDataGeneratorfrom sklearn.model_selection import train_test_splitfrom matplotlib import pyplotfrom tensorflow.keras.datasets import fashion_mnistimport plotly.graph_objs as gofrom plotly import toolsimport plotlyimport cv2IMG_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):
pyplot.subplot(330 + 1 + i)
pyplot.imshow(train_data[i], cmap=pyplot.get_cmap('gray'))

pyplot.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

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(0.001)
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 = tools.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]) plotly.offline.iplot(fig, filename='accuracy-loss')plot_accuracy_and_loss(train_model)
score = model.evaluate(test_data, y_test,verbose=0)
print("Test Loss:",score[0])
print("Test Accuracy:",score[1])

จากกราฟ Loss ด้านบน พบว่า Model มีปัญหา Overfitting ตั้งแต่รอบที่ 6 โดยเมื่อวัดประสิทธิภาพการ Predict ด้วย Test Dataset ได้ค่า Accuracy 92.24%

Image Augmentation

ปัญหา Overfitting ของ Model สามารถแก้ได้ด้วยการเพิ่มจำนวน Data ในการ Train แต่ด้วย Dataset ของเรามีจำกัด

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

ตัวอย่างการทำ Image Augmentation ในแบบต่างๆ ได้แก่

  1. Vertical Shift
  2. Horizontal Shift
  3. Shear
  4. Zoom
  5. Vertical Flip
  6. Horizontal Flip
  7. Rotate
  8. Fill Mode
    8.1 Constant Values
    8.2 Nearest Neighbor
    8.3 Reflect Values

Import Library ที่จำเป็น

import matplotlib.pyplot as plt

อ่านไฟล์ภาพ

cat = cv2.imread('cat.jpg')
cat.shape

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

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

Plot ภาพ

plt.figure(dpi=100)
plt.imshow(cat)

ขยายมิติของภาพจาก 3 มิติเป็น 4 มิติ เพื่อเตรียมนำเข้า Function ทำ Image Augmentation

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

โดย Default เมื่อมีการเลื่อนภาพ บิดภาพ หมุนภาพ จะเกิดพื้นที่ว่างที่มุม ซึ่งจะมีการเติมภาพให้เต็มโดยใช้เทคนิคแบบ 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 = 30history = 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])

จากกราฟ Loss ด้านบน เมื่อมีการ Train ทั้งหมด 30 Epoch พบว่า Validation Loss ไม่สูงขึ้นในรอบแรกๆ เหมือนในการ Train แบบไม่ใช้เทคนิค Image Augmentation โดยเมื่อวัดประสิทธิภาพการ Predict ด้วย Test Dataset ได้ค่า Accuracy 93.24% อย่างไรก็ตาม ใน Epoch ท้ายๆ Validation Loss ก็ยังมีแนวโน้มที่จะยกสูงขึ้นจนเกิดปัญหา Overfitting

Batch Normalization

Batch Normalization เป็นเทคนิคในการทำ Scaling Data เพื่อปรับค่าข้อมูลให้อยู่ในขอบเขตที่กำหนด ก่อนส่งออกจาก Node ใน Neural Network Layer เป็น Input ของ Layer ถัดไป เช่น Normalize ด้วยการแปลงค่าสีของภาพแบบ Grayscale จาก 0–255 เป็น 0–1 โดยนำค่าสีเดิมหารด้วย 255 ฯลฯ

นอกจากนี้การทำ Data Normalization กับ Feature อย่างเช่น อายุ และเงินเดือน จะทำให้ทั้ง 2 Feature มีน้ำหนักเท่ากัน มีการกระจายตัวเหมือนกัน ไม่มีตัวหนึ่งตัวใดมีอิทธิพลมากกว่ากัน ทั้งยังเป็นการเพิ่มความเร็วในการ Train Model และทำให้ค่า Loss ลดลง เพราะมีค่าข้อมูลที่เล็กกว่า

ในการทำ Data Normalization เราสามารถเลือกวิธีการได้หลายวิธี เช่น การทำ Min-Max Normalization หรือการทำ Standardization เป็นต้น

Min-Max Normalization = 𝑥′ = [𝑥–min(𝑥)]/[max(𝑥) — min(𝑥)]

Standardization = 𝑥′ = (𝑥–𝑥¯)/𝜎2

โดยที่ 𝑥¯ คือ Mean และ 𝜎2 คือ Variance

Batch Normalization จะใช้วิธีการแบบ Standardization

ซึ่งจะมีการกำหนดค่า Mean และ Variance โดยการเรียนรู้จาก Batch ขนาดเล็ก ที่หยิบมาสอน Model ด้วย Layer พิเศษใน Neural Network เอง

นิยามวิธีการทำ 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'))
  • Batch Normalization เหมาะสำหรับการวางไว้หลัง Activate Function ที่มีรูปร่างแบบ S-shapes เช่น Hyperbolic Tangent และ Sigmoid Activation Function
  • หรือวางไว้หน้า Activate Function ที่ให้ผลลัพธ์แบบ Non-Gaussian Distributions เช่น Rectified Linear (ReLU) Activation Function

Compile Model

optimizer = Adam()
model.compile(optimizer = optimizer, loss = "categorical_crossentropy", metrics=["accuracy"])
model.summary()

จากภาพจะเห็นว่าใน Batch Normalization Layer จะมี Parameter สำหรับกำหนดค่า Mean และ Variance โดยการเรียนรู้จาก Batch ขนาดเล็กมาให้ Model เรียนรู้

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])

เมื่อดูจากกราฟ Loss พบว่า Training Loss มีแนวโน้มที่จะลดลง แต่ Validation Loss ค่อนข้างแกว่ง อาจต้องใช้เทคนิคอื่นๆร่วมแก้ปัญหา Overfitting ซึ่งเทคนิคหนึ่งที่มักนำมาใช้งานร่วมกับ Batch Normalization คือ Dropout !!!

Dropout

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

เราอาจมอง Dropout เหมือนกับการทำงานของบริษัทหนึ่งที่มีพนักงาน 100 คน ครับ

ในกรณีที่ไม่มีการใช้ Dropout เปรียบได้กับการที่บริษัทมีนโยบายไม่อนุญาตให้พนักงานคนใดเลยลาหยุดงาน ทำให้แต่ละคนมีความเชี่ยวชาญเฉพาะด้าน สามารถแก้ปัญหาแบบเดิมๆ ได้เป็นอย่างดี แต่เมื่อเจอปัญหาใหม่ๆ พวกเขาจะไม่สามารถประยุกต์ใช้ความรู้และทักษะความชำนาญเดิมมาแก้ปัญหาได้อย่างมีประสิทธิภาพ

ในกรณีที่มีการใช้ Dropout เปรียบได้กับการที่บริษัทมีนโยบายอนุญาตให้พนักงานสามารถลาหยุดงาน ด้วยการสุ่มในอัตราที่กำหนด เช่น วันละ 1 คน โดยคนที่ยังคงปฏิบัติงานต้องสลับกันมารับผิดชอบในหน้าที่ของพนักงานที่ได้หยุดพัก จนทำให้ทุกคนสามารถทำงานต่างๆ ทดแทนกันได้อย่างดี โดยไม่มีพนักงานคนใดมีอิทธิพลเหนือคนอื่น เมื่อเจอปัญหาใหม่ๆ พวกเขาจะสามารถประยุกต์ใช้ความรู้และทักษะความชำนาญมาแก้ปัญหาได้อย่างมีประสิทธิภาพ

อย่างไรก็ตาม ในการใช้งานจริง เราควรนำ Dropout มาใช้กับ Model ที่มี Capacity สูงมากพอ เช่นเดียวกับที่ควรนำไปใช้กับบริษัทที่มีพนักงานจำนวนมากๆ โดยมีอัตราการ Dropout ในช่วงระหว่าง 0.2–0.5

เราจะทดลองใช้เทคนิค Dropout ร่วมกับ Batch Normalization และ Image Augmentation เพื่อแก้ปัญหา 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(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 = 170
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)

เพิ่ม Epoch ในการ Train เป็น 170 จากเดิม 50 Epoch เพราะเราคาดว่า Validation Loss จะลดลงได้มากกว่าก่อนการใช้งาน Dropout

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])

เมื่อดูจากกราฟ Loss ด้านบน เมื่อมีการ Train ทั้งหมด 170 Epoch โดยใช้เทคนิค Augmentation, Batch Normalization และ Dropout พบว่า Validation Loss ไม่พุ่งขึ้นจนเกิดปัญหา Overfitting เหมือนกับในการ Train แบบไม่ใช้ Dropout เมื่อวัดประสิทธิภาพการ Predict ด้วย Test Dataset ได้ค่า Accuracy 93.66%

ขอบคุณครับ…

อ้างอิงจาก

https://blog.pjjop.org/modern-regularization-with-data-augmentation-batch-normalization-and-dropout/?fbclid=IwAR2YSpZ55ONRgBn7otQLQz1dEHAu4dWjRnRpW-vVlnCqauwX3bkS1wjBD64

--

--

No responses yet