Regularization แบบสมัยใหม่ ด้วยเทคนิค Augmentation, Batch Normalization
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])
จบแล้วครับสำหรับ การทำ Regularization แบบสมัยใหม่ ด้วยเทคนิค Augmentation, Batch Normalization
เจอกันใหม่บทความหน้าครับ