สรุป Deep Learning ที่เรียนมาจากคลาส ดร.กานต์ — Part 2
หลังจากที่เราเรียนรู้ทฤษฎีของ Deep Learning และการใช้ Jupyter Notebook เบื้องต้นมาในพาร์ทก่อนหน้านี้แล้ว คราวนี้ถึงเวลาลงมื่อทำกันแล้วครับ
สิ่งที่เราจะมาเริ่มทำกันต่อไปนี้ คือเรื่องของการทำ Image Classification ด้วย Neural Network ครับ โดยเราจะใช้ Class 2 ตัวเพื่อมาลองทำกันในครั้งนี้ ก็คือ MLP (Multilayer Perceptron) กับ CNN (Convolutional Neural Network)
โอเคครับ เริ่มจากการเปิด Jupyter Notebook แล้วสร้างไฟล์ Python 3 ขึ้นมาและให้เราโหลด datasets มาครับ โดยข้อมูลชุดนี้จะประกอบไปด้วย รูปสุนัข รูปแมว และรูปแพนด้า คงจะเดาออกกันแล้วใช่ไหมครับว่าเรากำลังจะทำอะไรกัน ใช่แล้วครับ เราจะให้เจ้า Neural Network ของเรานั้นเรียนรู้และจำแนกชนิดของสัตว์ทั้งสามชนิดนั่นเอง
โหลด datasets สำหรับการทำเวิร์คช็อป>> http://bit.do/ezFRj
MLP (Multilayer Perceptron)
เป็น Neural Network ที่มีชั้นหลายๆชั้น ก็คือแบบธรรมดาๆนี่เอง อันดับแรกให้เราทำการนำโฟลเดอร์รูปภาพสัตว์มาไว้ในโฟลเดอร์เดียวกันกับไฟล์ python เพื่อให้ง่ายต่อการเรียกใช้ และเราจะลองทำการอ่านภาพจากโฟลเดอร์เข้ามาในโค้ดของเรากัน
import cv2
#อิมพอร์ต cv2 ที่มาจาก OpenCV
import matplotlib.pyplot as plt
#อิมพอร์ต pyplot เข้ามาในชื่อ plt
from imutils import paths
#อิมพอร์ต paths จาก imutilsimage_paths = list(paths.list_images('datasets/animals/'))
#อ่านรูปาภาพสัตว์ทั้งหมดจากโฟลเดอร์image = cv2.imread(image_paths[10])
#ลองใช้ cv2 อ่านรูปขึ้นมาสักรูปimage = cv2.imread(image_paths[10])
#ลองใช้ cv2 อ่านรูปขึ้นมาสักรูปnew_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
#หลังจากอ่านมาเสร็จแล้ว เราต้องแปลงสีก่อนเพราะ cv2 นั้นเมื่ออ่านรูปเข้ามา จะมีค่าพื้นฐานของสีเป็น BGR ซึ่งสีที่เราใช้ๆกันอยู่อย่างคุ้นตาคือ RGB เพราะฉะนั้นเราต้องแปลงก่อนplt.figure()
#เราใช้ pyplot ในการโชว์รูปขึ้นมา แต่ก่อนที่เราจะโชว์ขึ้นมาได้เราต้องสร้างตัว figure ขึ้นมาเสียก่อน เหมือนกับการสร้างหน้าต่างโปรแกรมขึ้นมาเพื่อที่จะให้เอารูปที่จะโชว์ไปแปะplt.imshow(new_image)
#ใช้ฟังก์ชั่น imshow ในการโชว์รูปออกมา
พิมพ์โค้ดเสร็จแล้ว ลองรันผลลัพธ์ดู
เท่านี้เราจะได้ภาพเจ้าหมาน้อยตัวนี้มาที่อยู่ในโฟลเดอร์ออกมาโชว์แล้ว
จากนั้นเมื่อเราได้ภาพแล้ว เราจะนำภาพที่ได้มา ไปแปลงเป็นข้อมูลกัน
import random
#อิมพอร์ต random เข้ามาเพื่อที่เราจะใช้ฟังก์ชั่น shuffleimport numpy as np
#อิมพอร์ต numpy เข้ามาในชื่อ nprandom.shuffle(image_paths)
#ใช้ฟังก์ชั่น shuffle ในการสลับรูปภาพเพื่อให้ภาพมันไม่เรียงติดกันเหมือนเดิมในทุกครั้งdata = []
labels = []
#สร้างตัวแปรอาเรย์ไว้รอเก็บค่าจากการแปลงรูปเป็นข้อมูล โดย data จะใช้เก็บข้อมูลเทรน ส่วน labels จะใช้เก็บเป็นข้อมูลสอน/คำตอบfor image_path in image_paths:
#วนลูปเพื่อทำการแปลงค่าจากรูปภาพเป็นข้อมูล
image = cv2.imread(image_path)
#อ่านรูปจาก image_path
image = cv2.resize(image, (32, 32))
#ปรับไซส์ให้รูปภาพมีคุณภาพต่ำลง(ตอนเทรนนิ่งข้อมูล คอมเราจะได้ไม่ทำงานหนักเกินไป)
labels.append(image_path.split('/')[-2])
#เอาชื่อ image_path ของแต่ละรูปมาเก็บค่าลงตัวแปรอาเรย์ labels
data.append(image)
#เอาข้อมูลรูปภาพใส่ตัวแปรอาเรย์ data เก็บไว้data = np.array(data)
labels = np.array(labels)
#แปลงตัวแปรอาเรย์ธรรมดาๆของเราให้เป็นอาเรย์ของ numpy เนื่องจากไลบรารี่ของ numpy จะช่วยให้เราจัดการพวกตัวแปรอาเรย์ได้ง่ายdata = data.reshape((3000, 3072))
#เนื่องจากตอนแรกข้อมูลที่เราอ่านมาจากภาพมันเป็นอาเรย์ 4 มิติ ขนาด 3000 x 32 x 32 x 3 เราจึง reshape ค่าให้เป็นอาเรย์ 2 มิติ ขนาด 3000 x 3072 เพื่อให้ง่ายต่อการนำเข้าฟังก์ชั่นเทรนข้อมูลdata = data/255.0
#แปลงสเกลของข้อมูลให้เล็กลง (255 คือจำนวนค่าระดับสี RGB)
แต่เมื่อเราลองสั่งโชว์ข้อมูล labels ออกมาดูจะพบว่า labels นั้นยังคงมีค่าเป็นตัวหนังสืออยู่ ซึ่งคอมพิวเตอร์ไม่เข้าใจหรอกว่าอะไรคือ dogs อะไรคือ cats เพราะฉะนั้นเราจะแปลงค่าพวกนี้ให้อยู่ในรูปที่คอมพิวเตอร์เข้าใจได้
from sklearn.preprocessing import LabelBinarizer
lb = LabelBinarizer()
#อิมพอร์ต LabelBinarizer ของ sklearn มาใช้labels = lb.fit_transform(labels)
#เรียกใช้ฟังก์ชั่น fit_transform เพื่อแปลง labels เป็นเลขฐานสอง
เมื่อแปลงมันเป็นตัวเลขแบบนี้แล้ว เราจะเห็นว่าคอมพิวเตอร์เราเข้าใจค่า labels พวกนี้โดยมันรู้ว่า dogs เป็น [0 1 0] cats เป็น[1 0 0] pandas เป็น [0 0 1]
เมื่อเราพิมพ์คำสั่ง lb.classes_ เพื่อจะดูว่าค่า labels ที่จะสามารถจำแนกประเภทออกมาได้มีอะไรบ้าง จะเห็นว่าค่าที่จำแนกออกมาได้ จะมีอยู่ 3 ประเภทก็คือ cats, dogs และ pandas นั่นเอง
ถ้าเราอยากจะพิสูจน์ว่าเจ้า labels นี้มันจะสามารถจำแนกคำตอบออกมาให้เราจริงๆรึเปล่า ให้เราลองเทสได้ด้วยการใช้คำสั่ง lb.inverse_transform คือการแปลงค่ากลับเป็นแบบเดิม ก็คือแปลงจากตัวเลขกลับไปเป็นตัวหนังสือซึ่งเป็นค่าก่อนที่จะเปลี่ยนตัวเลขนั่นเอง
lb.inverse_transform(np.array([[0.1, 0.7, 0.2]]))
#ถ้าเราพิมพ์คำสั่งนี้ไป เราจะได้คำตอบเป็น dogs เพราะค่า [0.1, 0.7, 0.2] มันมีค่าใกล้ [0, 1, 0] เพราะฉะนั้นจึงเป็น dogs นั่นเอง
output: array(['dogs'], dtype='<U5')
lb.inverse_transform(np.array([[0.6, 0.4, 0.2]]))
#ถ้าเราพิมพ์คำสั่งนี้ไป เราจะได้คำตอบเป็น dogs เพราะค่า [0.6, 0.4, 0.2] มันมีค่าใกล้ [1, 0, 0] เพราะฉะนั้นจึงเป็น cats
output: array(['cats'], dtype='<U5')
lb.inverse_transform(np.array([[0.6, 0.5, 0.9]]))
#ส่วนอันนี้ก็จะได้คำตอบเป็น pandas พราะค่า [0.6, 0.5, 0.9] มันมีค่าใกล้ [0, 0, 1] ก็คือค่าหลักสุดท้ายมากสุดมีค่าเป็น 1 ส่วนสองหลักแรกมีค่าน้อยกว่าจึงเป็น 0
output: array(['pandas'], dtype='<U5')
หลังจากที่เรามี data ที่จะใช้เทรน กับ labels ที่จะใช้ไว้แม็พเป็นคำตอบแล้ว คราวนี้ถึงเวลาที่เราจะมาลองนำข้อมูลเข้าฟังก์ชั่นเทรนแล้วล่ะ โดยเราจะเริ่มจากโครงสร้าง Neural Network พื้นฐานนั่นก็คือ MLP หรือ Multi-Layer Perceptron
from sklearn.model_selection import train_test_split
#อิมพอร์ต train_test_split จาก sklearn.model_selection เข้ามาX_train, X_test, y_train, y_test = train_test_split(data, labels, test_size=0.2, random_state=5)
#เรียกใช้ฟังก์ชั่น train_test_split เพื่อทำการสร้างข้อมูลเทรนกับเทสจาก data และ labels โดยเลือก test_size เป็น 0.2 ก็คือนำข้อมูล 20% ของทั้งหมดมาใช้เป็นข้อมูลเทส และ random_state ค่านี้จะเป็นค่าที่ใช้ในการทำงานข้างในฟังก์ชั่นนี้ เพื่อให้ตอนที่เรารันโปรแกรมในครั้งต่อๆเราไปจะได้ค่าเทสและเทรนที่ออกมาคงที่เหมือนเดิมเสมอ เพื่อให้ง่ายต่อการดีบักเวลามันมีปัญหาด้วย ซึ่งถ้าเราไม่กำหนด random_state ลงไป เจ้าตัวฟังก์ชั่น train_test_split มันจะสุ่มค่า random_state ให้เราใหม่เองทุกครั้งที่เรารันโปรแกรม ทำให้ผลการสร้างข้อมูลเทสและเทรนแต่ละครั้งมันจะได้ไม่เหมือนเดิม ซึ่งค่าที่เค้าว่ามันเหมาะกับการทำ MLP นี้คือ 5 นั่นเองหลังจากนำข้อมูลเข้าฟังก์ชั่นแล้ว เราจะได้ตัวแปรออกมา 4 ตัวคือ
X_train, X_test, y_train, y_testfrom sklearn.neural_network import MLPClassifier
#อิมพอร์ต MLPClassifier จาก sklearn.neural_network มาใข้เพื่อ classified
mlp = MLPClassifier()
#ค่า default ของ hidden_layer_sizes ของ MLPClassifier มีค่าเป็น (100,)mlp.fit(X_train, y_train)
#ใช้ฟังก์ชั่น fit นำข้อมูล X_train และ y_train ปรับรูปเข้าในโมเดล ตรงนรี้จะเป็นเหมือนการนำข้อมูลเทรนไปสอนโมเดลนั่นเองy_pred = mlp.predict(X_test)
#หลังจากที่ตัวโมเดล MLP ของเรามันฉลาดขึ้นมาบ้างแล้ว คราวนี้เราจะใช้ข้อมูลเทส มาลองให้โมเดลมัน classified ดูโดยใช้ฟังก์ชั่น predict
ขอขั้นก่อนนิดนึง หลังจากที่เราสร้างข้อมูลเทรนกับเทสจากฟังก์ชั่น train_test_split แล้วเราลองเอาข้อมูลที่ได้มาโชว์จะเห็นว่า ข้อมูลเทส(X_test กับ y_test) ด้วยค่า test_size = 0.2 นั้นจะแบ่งออกมาเป็นแบบนั้นจริงๆ
เราจะเห็นว่า จากข้อมูลทั้งหมด 3000 แถวจะถูกแบ่งออกเป็นข้อมูลเทรนและเทสตามสัดส่วนเทรน 80%(2400) และเทส 20%(600) จริงๆ
หลังจากที่เราเรียกใช้ฟังก์ชั่น predict แล้วเราจะได้ข้อมูลการ classified ทั้งหมดอยู่ที่ตัวแปร y_pred แต่เมื่อลองโชว์ค่าดูจะเห็นว่า มันมีผลการ classified มันออกมาแล้ว แต่มันยังอยู่ในรูปที่อ่านค่ายากอยู่ เราอยากจะให้มันแสดงผลออกมาให้ดีกว่านี้ รวมกับดูผลความถูกต้องและแม่นยำของข้อมูลด้วย
from sklearn.metrics import accuracy_score, classification_report
#อิมพอร์ต accuracy_score กับ classification_report จาก sklearn.metricsaccuracy_score(y_test, y_pred)
#จากนั้นมาเรียกใช้ฟังก์ชั่น accuracy_score เพื่อดูความแม่นของข้อมูลที่ predict กัน
ความถูกต้องได้ 0.47 โอ้แม่พระ คะแนนแย่มาก !!!!
print(classification_report(y_test, y_pred, target_names=lb.classes_))
#เราลองมาดูผลการ classification อย่างละเอียดกัน
เมื่อเราโชว์ค่าออกมาก็จะเห็นว่าจากผลการทำนาย ค่า precision หรือความแม่นยำที่โมเดลสามารถจำแนกประเภทของรูปสัตว์แต่ละชนิดออกจากกันได้เฉลี่ยรวมกันแล้วอยู่ที่ประมาณ 61% จะแบ่งเป็น 3 ประเภท
- cats มีความแม่นยำในการจำแนกอยู่ 47%
- dogs มีความแม่นยำในการจำแนกอยู่ 58%
- pandas มีความแม่นยำในการจำแนกอยู่ 76%
ส่วนอีกจุดนึงคือ recall ที่บอกอัตราการตอบถูกของประเภทนั้นๆเฉลี่ยอยู่ที่ 54% แบ่งตามประเภท
- cats อัตราการตอบถูก 62%
- dogs อัตราการตอบถูก 29%
- pandas อัตราการตอบถูก 74%
จากผลการทดลอง Deep Leaning แบบ MLP ด้วย MLPClassifier แล้วจะเห็นว่าผลลัพธ์ค่อนข้างไม่ดีนัก เอาล่ะคราวนี้เราจะมาลองไปทำ CNN (Convolutional Neural Network) ดูบ้างซิ เผื่อว่ามันจะมีอะไรดีขึ้น
CNN (Convolutional Neural Network)
อธิบายเบื้องต้นก่อน CNN นั้นคือรูปแบบหนึ่งของ feed-forward และก็จัดเป็น Deep Learning ประเภทหนึ่งเหมือนกัน โดยตรงส่วนของ hidden layer ของ CNN นั้นจะมี Convolutional Layers เพิ่มขึ้นมาเป็นส่วนที่ใช้ในการฟิลเตอร์รูปโดยมี Kernel function เพื่อใช้แปลงคุณลักษณะ และเพื่อแยกองค์ประกอบออกมา เช่น ขอบรูป สี ลักษณะรูปทรง เป็นต้น และก็จะมีพวก Activation Function ที่ช่วยแปลงค่าให้อยู่ในรูปที่ง่ายต่อการคำนวนและได้ผลลัพธ์ดียิ่งขึ้น รวมถึงส่วนที่เรียกว่า Pooling โดยส่วนนี้จะทำหน้าที่ปรับไซส์ของข้อมูลให้มีขนาดเล็กลงโดยที่รายละเอียดของข้อมูลนั้นยังคงเดิม(ยังคงอยู่ไว้ได้มากที่สุด) และในส่วนสุดท้ายก็จะเป็น Fully connected layer ที่จะคอยเชื่อมต่อแต่ละ perceptron ในแต่ละชั้นเข้าด้วยกัน
อันดับแรกสร้างไฟล์ใหม่ขึ้นมาอีกไฟล์นึง และตรงส่วนการการอ่านภาพจากโฟลเดอร์เข้ามาในโค้ดของเรา จะทำเหมือนกับข้างบนเลย (ตรงส่วนนี้ก็อปโค้ดมาก็ได้)
จากนั้นเพิ่มโค้ดต่อไปนี้เข้าไป
from keras import backend
from keras.models import Sequential
from keras.layers.convolutional import Conv2D
from keras.layers.core import Dense, Flatten
from sklearn.model_selection import train_test_split
#อิมพอร์ตพวกของต่างๆที่จะต้องใช้จาก kerasX_train, X_test, y_train, y_test = train_test_split(data, labels, test_size=0.2, random_state=5)
#เรียกใช้ฟังก์ชั่น train_test_split เพื่อทำการสร้างข้อมูลเทรนกับเทสmodel = Sequential()
#ใช้โมเดล Sequential ของ kerasmodel.add(Conv2D(32, (3, 3), input_shape=(32, 32 ,3), activation='relu', padding='same'))
#ใข้คำสั่ง model.add() เพิ่มชั้น(Layer)ให้กับโมเดลโดยให้ชั้นนี้เป็น convolution layer ด้วยฟังก์ชั่น Conv2D โดยค่าพารามิเตอร์แรกคือ filters มีค่าเป็น 32 คือบอกว่า คือจำนวนฟิลเตอร์ทั้งหมดของเลเยอร์นี้มี 32 ชั้น, พารามิเตอร์ตัวที่สองคือ kernel_size มีค่าเป็น 3x3 และ input_shape=(32, 32 ,3) คือรูปขนาด 32x32 และมี 3 channels ในนี้ก็คือ RGB, activation function เป็น relu, และ padding เซ็ทไว้เป็น same เพื่อให้ข้อมูลที่ส่งออกมีขนาดเท่าเดิม (ไม่ให้ output ที่ได้มีขนาดเล็กลง)model.add(Flatten())
#เพิ่มชั้น(Layer) ที่เป็น flatten ให้กับโมเดลเพื่อแปลงข้อมูลจากภาพให้เป็นเวคเตอร์ ที่จะสามารถส่งต่อให้ชั้นต่อไปได้ (ง่ายๆคือเอาข้อมูลอาร์เรย์ขนาดหลายมิติจากชั้นที่แล้ว มาตีแผ่ออกเหลือแค่มิติเดียว)model.add(Dense(3, activation='softmax'))
#เพิ่มชั้น(Layer) ที่เป็น dense ให้กับโมเดลซึ่งก็คือชั้นที่เป็น fully connected นั่นเอง และใช้ activation function เป็น softmax และมี output เป็นอาร์เรย์ขนาด (*, 3)
อ่านแล้วเราอาจจะยังมองภาพไม่ค่อยออกว่า Kernel ทำงานยังไง เราลองมาดูภาพคร่าวๆในส่วนฟิลเตอร์ของ Kernel กัน
สีเขียวคือรูปที่เป็น Input สีเหลืองคือ Kernel ขนาด 3x3 ส่วนสีชมพูคือ Output ที่ได้จากการ Convoluted (แต่จากรูปนี้มันไม่ได้เป็น padding = same เพราะ Convoluted Feature มันมีขนาดลดลง)
รูปด้านล่างนี้เพื่อให้มองเข้าใจง่ายของการทำชั้นที่เป็น Flatten เข้าไป
พิมพ์เสร็จแล้วจะได้หน้าตาแบบนี้
หากถ้าเราอยากรู้ว่า ข้างในโมเดลมีหน้าตาเป็นยังไง มีอะไรอยู่บ้าง ให้ลองใช้คำสั่ง
model.summary()
เมื่อเราดู summary ของโมเดลก็จะเห็นข้อมูลของโมเดล ทั้งจำนวนและชนิดของ Layer แต่ละชั้น, Output และ Param มีขนาดเท่าไหร่
model.compile(loss='categorical_crossentropy', optimizer='adam')
#เซ็ทค่ากระบวนการเรียนรู้ให้กับโมเดลก่อนจะนำไปใช้เทรนข้อมูลด้วยฟังก์ชั่น compile โดยกำหนด loss funtion เป็น categorical_crossentropy และ Optimization Algorithm เป็น adammodel.fit(X_train, y_train, epochs=10, validation_split=0.2)
#ใช้ฟังก์ชั่น fit นำข้อมูล X_train และ y_train ปรับรูปเข้าในโมเดล ตรงนรี้จะเป็นเหมือนการนำข้อมูลเทรนไปสอนโมเดลนั่นเอง โดยค่า epochs=10 คือเซ็ทให้โมเดลนี้ทำการเทรน 10 รอบ, validation_split=0.2 คือเซ็ทให้ 20% จากข้อมูลเทรนทั้งหมดเป็น validation data เอาไว้ใช้ประเมินผลในตอนสุดท้ายของการเทรนแต่ละ epoch
หลังจากที่รันโค้ดชุดนี้ เราจะเห็นผลการรันเทสข้อมูลแต่ละ epoch ขึ้นมาให้เราดู และจะเห็นว่ามีข้อมูลเทรนทั้งหมด 1920 ตัวอย่าง และมีข้อมูลที่ใช้สำหรับการทำ validation 480 ตัวอย่าง
y_pred = model.predict(X_test)
#หลังจากที่เราเทรนตัวโมเดลเราเสร็จ คราวนี้เราจะใช้ข้อมูลเทสมาลองให้โมเดลมัน classified โดยใช้ฟังก์ชั่น predictfrom sklearn.metrics import accuracy_score, classification_report #อิมพอร์ต accuracy_score กับ classification_report จาก sklearn.metrics accuracy_score(y_test.argmax(axis=1), y_pred.argmax(axis=1))
#จากนั้นมาเรียกใช้ฟังก์ชั่น accuracy_score เพื่อดูความแม่นของข้อมูลที่ predict กัน
ที่เราต้องใช้ y_test.argmax(axis=1), y_pred.argmax(axis=1) ในการใช้ฟังก์ชั่น accuracy_score เนื่องจากค่า y_pred ที่เราได้มาจาก model.predict นั้นมันสะเปะสะปะมาก และมันไม่สามารถเอามาเป็นตัวบ่งชี้การ classification ได้ ถ้าเราลองใส่ค่าเข้าฟังก์ชั่น accuracy_score เป็น y_test และ y_pred แบบธรรมดาๆ จะพบกับเออเร่อแบบข้างล่างนี้
ValueError: Classification metrics can't handle a mix of multilabel-indicator and multiclass targets
ก็คือไม่สามารถใช้ label ที่เป็นค่าผสมๆกันแบบนี้ได้นั่นเอง เราจึงใช้ฟังก์ชั่น argmax(axis=1) ของ numpy เพื่อหา index ที่มีค่ามากที่สุดของอาร์เรย์แต่ละช่อง เพื่อให้ค่ามันถูกจัดกลุ่มไม่สะเปะสะปะนั่นเอง โดย y_pred นี้เป็นค่าอาร์เรย์ 2 มิติ axis=1 ก็คืออาเรย์มิติที่ 2 ของตัว y_pred นั่นเอง (ถ้าเป็นมิติแรก axis=0)
หลังจากที่เรารัน accuracy_score แล้วเนี่ย เราจะเห็นความถูกต้องที่ได้ 0.705 โอ้แม่พระ คะแนนดีขึ้นกว่าแบบเดิมเยอะเลย ก่อนหน้านี้ที่เราใช้โมเดล MLPClassifier นั้นค่ามันออกมาแค่ 0.47 เอง !!!!
โอเค ไม่รอช้าเรามาดู classification อย่างละเอียดกัน
print(classification_report(y_test.argmax(axis=1), y_pred.argmax(axis=1), target_names=lb.classes_))
#เราลองมาดูผลการ classification อย่างละเอียดกัน
เมื่อเราโชว์ค่าออกมาก็จะเห็นว่าจากผลการทำนาย ค่า precision หรือมีความแม่นยำในการจำแนกที่ได้เฉลี่ยรวมกันแล้วอยู่ที่ประมาณ 70% (ซึ่งเมื่อเทียบกับ MLPClassifier ที่ได้ 61% แล้วก็ถือว่าดีกว่าขึ้นมานิดนึง) โดยจะแบ่งเป็น 3 ประเภท
- cats มีความแม่นยำในการจำแนกอยู่ 71%
- dogs มีความแม่นยำในการจำแนกอยู่ 59%
- pandas มีความแม่นยำในการจำแนกอยู่ 81%
ส่วนอ recall ที่บอกอัตราการตอบถูกของประเภทนั้นๆเฉลี่ยอยู่ที่ 70% แบ่งเป็
- cats อัตราการตอบถูก 63%
- dogs อัตราการตอบถูก 62%
- pandas อัตราการตอบถูก 87%
จากผลการทดลอง Deep Leaning แบบ CNN เทียบกับ MLP แล้วถือว่าผลที่ได้จาก CNN ดีกว่า MLP แบบธรรมดา แต่ยังอยู่ในขั้นที่ไม่ได้ดีมากเท่าที่ควร เราเลยจะมาลองปรับปรุงเพิ่มเติมให้มันดีขึ้นกัน (แต่ไม่รู้มันจะดีขึ้นจริงรึเปล่านะ 555)
เราจะมาลองเพิ่มชั้นที่เป็น Convolution layer เข้าไปอีก 2 ชั้นดู เพื่อให้ได้มุมมองลึกลงเข้าไปอีก โดยคราวนี้ใช้ filter 128 อันเลย
model_2 = Sequential()
model_2.add(Conv2D(32, (3, 3), input_shape=(32, 32 ,3), activation='relu', padding='same'))
model_2.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model_2.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model_2.add(Flatten())
model_2.add(Dense(3, activation='softmax'))model_2.compile(loss='categorical_crossentropy', optimizer='adam')model_2.fit(X_train, y_train, epochs=10, validation_split=0.2)y_pred = model_2.predict(X_test)from sklearn.metrics import accuracy_score, classification_report
print(accuracy_score(y_test.argmax(axis=1), y_pred.argmax(axis=1)))
print(classification_report(y_test.argmax(axis=1), y_pred.argmax(axis=1), target_names=lb.classes_))
หลังจากเพิ่ม Convolution layer ไปอีก 2 ชั้นแล้วรันดูผลลัพธ์ ปรากฏว่ามันยิ่งแย่ลงกว่าเดิมอีก เพราะฉะนั้นประเด็นมันไม่ได้อยู่ตรงที่การดูเข้าไปในมุมมองที่ลึกลงของรูปแล้วล่ะ เราควรลองปรับปรุงด้วยวิธีอื่นแทน
ซึ่งผมพามาสุดได้เท่านี้5555
ต่อจากนี้ผู้อ่านต้องไปทำการปรับจูนค่าโมเดลกันเองแล้วนะครับ
คราวนี้เราจะมาลองทำการเพิ่มประสิทธิภาพและความเร็วให้การเทรนข้อมูลดีกว่า เพราะก่อนหน้านี้ตอนเทรนข้อมูลที่เพิ่มชั้นที่เป็น Convolution layer เข้าไปอีก 2 ชั้นนี่ เสียงพัดลมคอมพิวเตอร์ผมร้องอย่างกะไอพ่นเครื่องบิน
from keras.layers.convolutional import MaxPooling2D
from keras.layers.core import Dropout
#อิมพอร์ต MaxPooling2D กับ Dropout มาmodel_3 = Sequential()
model_3.add(Conv2D(32, (3, 3), input_shape=(32, 32 ,3), activation='relu', padding='same'))
model_3.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model_3.add(Conv2D(128, (3, 3), activation='relu', padding='same'))model_3.add(MaxPooling2D(pool_size=(3, 3)))
#เพิ่มชั้น Pooling เข้ามา ชั้นนี้จะทำหน้าที่ก็คือเอาภาพที่ convoluted แล้วมาปรับไซส์ของข้อมูลให้มีขนาดเล็กลงmodel_3.add(Dropout(0.2))
#ชั้น DropOut นี้จะมีการสุ่มค่าขึ้นมาเพื่อตัดค่าบางส่วนของข้อมูลออก เพื่อเอาไว้กันการเกิด Overfitting ของข้อมูลโดยอันนี้จะเซ็ทไว้ที่ 0.2model_3.add(Flatten())
model_3.add(Dense(3, activation='softmax'))model_3.compile(loss='categorical_crossentropy', optimizer='adam')
model_3.fit(X_train, y_train, epochs=10, validation_split=0.2)y_pred = model.predict(X_test)from sklearn.metrics import accuracy_score, classification_report
print(accuracy_score(y_test.argmax(axis=1), y_pred.argmax(axis=1)))
print(classification_report(y_test.argmax(axis=1), y_pred.argmax(axis=1), target_names=lb.classes_))
หลังจากเพิ่ม Pooling กับ Dropout ก็รู้สึกว่ามันดีขึ้นกว่าเดิมนิดนึง555 แต่คอมก็ร้องเป็นเครื่องบินไอพ่นเหมือนเดิม