Visualizing Kernels and Feature Maps in Deep Learning Model (CNN)
CNN (Convolutional Neural Network) เป็นโครงสร้างภายใน Deep Learning Model ที่ใช้แนวคิดของ Convolution ในการทำงานกับข้อมูล 2 มิติ เช่น Image Data ซึ่งแต่ละ Pixel ของ Image จะมีความสัมพันธ์กันในเชิงพื้นที่ (Spatial Relationship) ลักษณะโครงสร้างของ CNN ที่ถูกออกแบบมาเพื่อทำงานกับ Image Data ในตอนเริ่มต้น จึงสามารถแสดงข้อมูลที่เป็นองค์ประกอบของการตัดสินใจหรือการทำนายของ Model ด้วยภาพได้ดีกว่า Neural Network ชนิดอื่นๆ
CNN ประกอบด้วย Kernel และผลลัพธ์จากการกระทำทางคณิตศาสตร์ของ Kernel กับ Input Image ที่เรียกว่า Activation Map หรือ Feature Map โดยทั้ง Kernel และ Feature Map นั้นสามารถแสดงผลได้ด้วยภาพ
ในบทความนี้ จะลอง Create a Model with 2D CNN Layer และวาด Algorithm ของ Model กันค่ะ
2D Convolutions Concept
เป็นการนำ Matrix ขนาดเล็ก ของ Weight หรือที่เรียกว่า Kernel มา Slide ไปบน 2D Input Image (สีฟ้า)โดยขณะที่มีการทาบ Kernel บน Input Image มันจะคูณค่าแต่ละ Pixel ของ Input Image กับ Kernel แล้วนำผลลัพธ์ทั้งหมดมาบวกกันเป็น 1 จุด Pixel ของ Feature Map (สีเขียว)
2D Convolutions Concept จะมีการสร้าง Feature Map ขึ้นมาด้วยการนำ Kernel Slide ไปบน Input Image จะใช้ Parameter น้อยกว่า Fully Connected Layer
Padding
ขณะที่มีการ Slide Kernel จะเห็นได้ว่า Pixel ตรงขอบภาพสีฟ้าจะไม่มีทางอยู่ตรงกลาง Kernel ตอนที่มันทาบลงไป เพราะเราไม่สามารถขยาย Kernel ให้เลยออกไปนอกขอบของภาพ จึงทำให้ Feature Map ที่ได้มีขนาดเล็กกว่า Input Image เพื่อจะทำให้ Feature Map มีขนาดเท่ากับ Input Image และ Pixel ที่ขอบภาพอยู่ตรงกลาง Kernel ตอนที่มันทาบลงไป เราจะต้องมีการทำ Padding โดยการเสริมกรอบด้วยการเติม 0 (Zero Padding) รอบๆ ภาพเดิม
Striding
เป็นกระบวนการในการทำ Convolution โดยการเลื่อนแผ่น Kernel ไปบน Input Image ซึ่งโดย Default ของ Convolution แล้ว Stride จะมีค่าเท่ากับ 1 คือจะมีการเลื่อน Kernel ไปบน Input Image ครั้งละ 1 Pixel การเพิ่มค่า Stride มากขึ้น จะทำให้การเลื่อมกันของ Kernel ตอนที่มีการทาบกับ Input Image และขนาดของ Feature Map ลดลง ถ้ากำหนด Stride เท่ากับ 2 แล้ว Kernel ขนาด 3x3 จะถูก Slide ข้าม Pixel ของ Input Image ขนาด 5x5 ทีละ 2 Pixel ทำให้ได้ Feature Map ขนาด 2x2 ดังภาพด้านล่างนี้
Pooling
เป็นวิธีการลดขนาดภาพโดยการทำ Max Pooling หรือ Average Pooling โดย Pooling จะเป็นกระบวนการทำงานภายนอก CNN Layer โดยทำการเลือกตัวแทนของภาพด้วยการหาค่ามากที่สุด หรือค่าเฉลี่ยจาก Pixel ใน Window ตามขนาดที่กำหนด เช่น ขนาด 2x2 ซึ่งจะทำให้มีการลดขนาดของภาพลงได้ครึ่งหนึ่งดังตัวอย่างด้านล่าง
Multi-channel
ใช้จัดการกับ Input Image แบบ 3 Channel เช่นภาพสีในระบบ RGB จะต้องใช้ Kernel จำนวน 3 ตัว ในการ Slide ไปบน Input Image แต่ละ Channel ซึ่งเราเรียก Kernel ทั้ง 3 ตัวว่า Filter (ในที่นี้ 1 Filter ประกอบด้วย 3 Kernel)
Feature Map แต่ละ Version ขนาด 3x3 ที่เกิดจากการ Slide Kernel ไปบน Input Channel ขนาด 5x5 จะถูกนำมารวมกันเป็น Output Channel 1 Channel เพื่อจะส่งต่อไปยัง Neural Network Layer ถัดไป
ซึ่ง Output Channel จะถูกนำมาบวกกับ Bias ในขั้นตอนสุดท้ายของกระบวนการทำ Convolution
เพื่อจะสร้าง Output Channel 1 Channel ดังภาพจะต้องใช้ Filter 1 Filter ซึ่งแต่ละ Filter ก็จะประกอบด้วยจำนวน Kernel 3 Kernel ดังนั้นถ้าต้องการสร้าง Output Channel หลาย Channel เราจะต้องมีจำนวน Filter หลาย Filter นั่นเองง
Visualizing CNN
สำหรับผู้ที่มี GPU Config การใช้งาน ด้วยคำสั่งนี้
!nvidia-smi -Limport 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.layers import Dense, Flatten, Conv2D, Dropout, Activation, BatchNormalization, MaxPool2D
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import Adam
import tensorflow as tf
from tensorflow.keras.datasets import fashion_mnist
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.callbacks import ModelCheckpoint
from tensorflow.python.keras.models import load_modelfrom sklearn.model_selection import train_test_splitimport numpy as np
import matplotlib.pyplot as pltimport plotly.graph_objs as go
from plotly import tools
import plotlyimport cv2from keras.callbacks import ModelCheckpoint%matplotlib inline
อ่านไฟล์ภาพ
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)
cat.shape
Create a Model with 2D CNN Layer
นิยาม Model แบบ 2D Convolution โดยรับ Input Image ขนาด 900x900 Pixel แบบ 3 Channel โดยมี Filter ขนาด 3x3 จำนวน 3 Filter เพื่อนำไป Slide บน Input Image ของแต่ละ Channel
จากภาพด้านบน Model ของเราจะมีจำนวน Parameter เท่ากับ (Filter + Bias) 3x3x3x3 + 3 = 84 Parameter
model = Sequential()
model.add(Conv2D(3, # number of filter layers
(3, # y dimension of kernel
3), # x dimension of kernel
input_shape=cat.shape))
model.summary()
ทดลองขยายมิติของภาพจาก 3 มิติเป็น 4 มิติ เพื่อเตรียมนำเข้า Predict Function
cat_batch = np.expand_dims(cat,axis=0)
cat_batch.shape
ทดลอง predict Model โดยใช้ค่า Weight และ Bias แบบสุ่มในตอนเริ่มต้น โดยยังไม่มีการ Train Model
conv_cat = model.predict(cat_batch)
conv_cat.shape
เนื่องจากเรามีการนิยาม Model โดยกำหนดจำนวน Filter ไว้ที่ 3 Filter ดังนั้นจึงทำให้ได้ Output Channel ขนาด 1438 x 1078 ทั้งหมด 3 Channel ซึ่งขนาดของ Output Channel จะลดลงจากเดิม 1440 x 1080 Pixel เนื่องมาจาก มีการ Slide Kernel ขนาด 3x3 ไปบน Input Image โดยไม่มีการทำ Padding
นิยาม visualize_cat Function ที่รับภาพเป็น Matrix, ขยายภาพเป็น 4 มิติ แล้ว Predict ภาพ ก่อนจะหดให้เหลือ 3 มิติเท่าเดิมเพื่อจะ Plot ภาพต่อไป
def visualize_cat(model, cat):
cat_batch = np.expand_dims(cat,axis=0)
conv_cat = model.predict(cat_batch)
conv_cat = np.squeeze(conv_cat, axis=0)
print(conv_cat.shape)
conv_cat = cv2.cvtColor(conv_cat, cv2.COLOR_RGB2BGR)
plt.imshow(conv_cat)
Plot ภาพ
visualize_cat(model, cat)
นิยาม Model แบบ 2D Convolution โดยรับ Input Image ขนาด 900x900 Pixel แบบ 3 Channel โดยมี Filter ขนาด 10x10 จำนวน 3 Filter เพื่อนำไป Slide บน Input Image แต่ละ Channel
model = Sequential()
model.add(Conv2D(3,(10, 10), input_shape=cat.shape))
model.summary()
Plot ภาพ
visualize_cat(model, cat)
นิยาม Model แบบ 2D Convolution โดยรับ Input Image ขนาด 900x900 Pixel แบบ 3 Channel โดยมี Filter ขนาด 3x3 จำนวน 1 Filter
model = Sequential()
model.add(Conv2D(1,(3,3),input_shape=cat.shape))
model.summary()
นิยาม visualize_cat_one_channel Function ที่รับภาพเป็น Matrix ขยายภาพเป็น 4 มิติ แล้ว Predict ภาพ ก่อนจะหดให้เหลือ 2 มิติ เพื่อจะ Plot ภาพ แบบ 1 Channel ต่อไป
def visualize_cat_one_channel(model, cat):
cat_batch = np.expand_dims(cat,axis=0)
conv_cat2 = model.predict(cat_batch)
conv_cat2 = np.squeeze(conv_cat2, axis=0)
conv_cat2 = conv_cat2.reshape(conv_cat2.shape[:2])
plt.imshow(conv_cat2)
Plot ภาพ
visualize_cat_one_channel(model, cat)
นิยาม Model แบบ 2D Convolution โดยรับ Input Image ขนาด 900x900 Pixel แบบ 3 Channel โดยมี Filter ขนาด 20x20 จำนวน 1 Filter
model = Sequential()
model.add(Conv2D(1,(20,20),input_shape=cat.shape))
model.summary()
Plot ภาพ
visualize_cat_one_channel(model, cat)
นิยาม Model แบบ 2D Convolution โดยรับ Input Image ขนาด 900x900Pixel แบบ 3 Channel โดยมี Filter ขนาด 20x20 จำนวน 1 Filter และเพิ่ม Relu Activation Function
model = Sequential()
model.add(Conv2D(1(20,20),input_shape=cat.shape))model.add(Activation('relu'))
model.summary()
Plot ภาพ
นิยาม Model แบบ 2D Convolution โดยรับ Input Image ขนาด 900x900 Pixel แบบ 3 Channel โดยมี Filter ขนาด 3x3 จำนวน 1 Filter และเพิ่ม Max Pooling ขนาด 5x5
model = Sequential()
model.add(Conv2D(1,(3,3),input_shape=cat.shape))
model.add(MaxPool2D(pool_size=(5,5)))
model.summary()
Plot ภาพ
visualize_cat_one_channel(model, cat)
เมื่อเพิ่ม Max Pooling จะเห็นได้ว่าความละเอียดของภาพจะต่ำลง เนื่องจากทำการยุบรวมจาก 5x5 ให้เหลือแค่ 1 pixel
นิยาม Model แบบ 2D Convolution โดยรับ Input Image ขนาด 1440x1080 Pixel แบบ 3 Channel โดยมี Filter ขนาด 3x3 จำนวน 1 Filter เพิ่ม Relu Activation Function และ Max Pooling ขนาด 5x5
model = Sequential()
model.add(Conv2D(1,(3,3),input_shape=cat.shape))
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=(5,5)))
model.summary()
Plot ภาพ
visualize_cat_one_channel(model, cat)