เจ็บแค่ไหนก็ต้องฝืนยิ้มว่าไม่เป็นไร

แต่ AI ดูออกนะ 😊😊

Bright
5 min readJun 21, 2022

ทุกคนเคยโกหกกันไหมครับ ไม่ว่าจะเป็นการโกหกจากสาเหตุอะไรก็ตาม

เพราะมนุษย์นั้นเป็นสิ่งมีชีวิตที่ค่อนข้างซับซ้อนซ่อนเงื่อน พวกเราจึงมักจะมีกลไกในการป้องกันตัวเองอยู่เสมอ การโกหกก็คือหนึ่งในกลไกนั้นครับ การปกปิดสิ่งที่เราคิดอยู่เพื่อให้พ้นสถานการณ์อันคับขันก็ไม่ต่างจากการแกล้งตายของสัตว์ตัวน้อยเมื่อเจอผู้ล่าตัวใหญ่ แต่เพราะสมองเราคิดแบบนึง และสีหน้าท่าทางกลับแสดงอีกแบบนึง จึงไม่แปลกครับ ที่กลไกนี้จะไม่ได้สมบูรณ์ 100% และมีช่องโหว่เกิดขึ้น

Picture from Disney Inside Out

สมมติว่าในหัวเรามีเจ้าตัวอารมณ์พวกนี้คุมเหมือนบอร์ดบริหารแบบในเรื่อง Inside Out ( ในหนังจะบอกว่าคนเรานั้นมีเจ้าตัวอารมณ์ทั้ง 5 คอยคุมเราอยู่ เวลาเกิดการกระทำอะไรขึ้น ก็มาจากเจ้าพวกนี้เป็นคนสั่ง ) แล้วถ้าเกิดว่าการโกหกนั้น เจ้าอารมณ์พวกนี้ดันคิดต่างและทะเลาะกัน ถ้าในจังหวะที่กำลังชุลมุนกันอยู่ ต้าว Anger เผลอเอามือไปโดนปุ่มบางปุ่มเข้าล่ะ แน่นอน ร่างกายของเราก็ต้องมีรีแอ็คชั่นที่เกิดจากปุ่มเจ้าปัญหานั้นแน่ ๆ แต่จะเกิดนานเท่าไหร่ก็ขึ้นอยู่กับอีก 4 ตัวที่เหลือจะกู้สถานการณ์กลับมาได้เร็วแค่ไหน โชคดีครับที่เจ้าตัวอารมณ์ของเราฝึกรับมือกับเหตุการณ์แบบนี้มาดีจึงแก้ได้อย่างฉับไวและอาจจะไวเพียงแค่เสี้ยววิจนมนุษย์คนอื่นไม่ทันได้สังเกต เหตุการณ์แบบนี้แหละครับที่ทำให้เกิด Micro-expression ขึ้น

ผมขอตั้งชื่อไทยให้ Micro-expression ว่า “อารมณ์เสี้ยววิ” ละกันครับ เพราะอารมณ์นี้มักแสดงบนใบหน้าแบบที่เราไม่รู้ตัว ควบคุมไม่ได้และใช้เวลาแค่ประมาณ 0.5 วิเท่านั้นเอง โดยมักเป็นอารมณ์ที่เรารู้สึกในขณะนั้นจริง ๆ แต่อาจจะต้องปั้นสีหน้าหรือโกหกเอาไว้ แต่ก็นั่นแหละครับ หลุดออกมาอยู่ดี 😓 ซึ่งพอมันเร็วจนมนุษย์ทั่วไปไม่สามารถสังเกตได้เนี่ย ผมก็เลยคิดว่าเราน่าจะลองให้เจ้า AI นวัตกรรมสุดแสนฉลาดช่วยหาให้ ก็เลยออกมาเป็นโปรเจคนี้ครับ Micro-expression recognition หรือ การตรวจหาอารมณ์เสี้ยววิด้วย AI ( ชื่อเท่ได้เพียงแค่เติม AI 😉)

Problem statement — เหตุผลที่ต้องใช้ AI แก้ปัญหา แต่จะมีกี่เหตุผลเธอก็เลือกเขา

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

การสร้าง Machine learning หรือ AI ในการตรวจหาก็จะมี process คร่าว ๆ ประมาณนี้

  • เก็บสะสม data — SAMM dataset
  • จัดการกับ data ที่หามาได้ — Try different input and cross validation
  • หา model ที่เหมาะกับ data — CNN
  • เทรน model นั้นด้วย data ของเรา
  • ประเมินผล model — with human baseline

Data collection — การเก็บข้อมูล ก็ยังง่ายกว่าเก็บหัวใจที่ถูกเธอเหยียบย่ำขึ้นมา

เนื่องจาก Micro-expression เป็นเรื่องที่คนทำน้อย จึงทำให้ dataset หาได้ค่อนข้างยากและส่วนใหญ่ต้องส่ง email ไปขออนุญาตคนทำ dataset ก่อน จึงทำให้ผมหาได้แค่ SAMM dataset เราลองมาดูข้อมูลของ dataset นี้กัน

  • ประกอบไปด้วยรูปภาพที่แคปมาจากวิดีโอที่ถ่ายด้วยกล้องความเร็ว 200 fps
  • มีทั้งหมด 29 subjects 159 samples แต่ละ sample มีรูปประมาณ 30-100 รูป
  • มี .mat file ของทุก samples ให้
  • มีอารมณ์ทั้งหมด 7 อารมณ์ได้แก่ Happiness, Sadness, Anger, Disgust, Contempt, Fear และ Other
  • มี Onset frame ( หมายเลขเฟรมที่เริ่มอัดคลิป ), Apex frame ( หมายเลขเฟรมที่เป็นจุดพีคของการเกิด micro-expression ), Offset frame ( หมายเลขเฟรมที่จบการอัดคลิป ) และ Duration ( จำนวนเฟรมที่จับได้ ซึ่งสอดคล้องกับจำนวนรูปในไฟล์)
  • มี Action units ( หมายเลขตำแหน่งต่าง ๆ ของใบหน้าที่เกิดการขยับ )

และเมื่อเราได้ SAMM dataset มาแล้ว ต่อไปก็ถึงเวลาจัดการกับข้อมูลนี้

Preparing ( or preprocessing ) and cleaning data — จัดการจัดใจกับข้อมูล

ผมขอเรียก SAMM dataset ว่า แซม ละกันนะครับ 😄 เพราะเจ้าแซมของเราเนี่ยมีข้อมูลที่เราอาจจะไม่ได้ใช้อยู่เยอะมาก เราจึงต้องมาจัดการกับข้อมูลแต่ละตัว ว่าตัวไหนที่เราสามารถใช้ประโยชน์ได้ โดยข้อมูลที่ผมคิดว่าน่าจะเป็นประโยชน์กับเรานอกเหนือจาก Estimated Emotion ที่เป็นพระเอกในงานนี้ ก็คือ Apex frame และ Onset frame โดยเฉพาะ Apex frame ที่บ่งบอกว่าจุดที่เกิดอารมณ์นี้มากที่สุดหรือใบหน้าขยับมากที่สุดอยู่ที่เฟรมไหน จึงทำให้เป็นประโยชน์อย่างมากในการนำข้อมูลนี้มาใช้

หลังจากคัดว่าควรใช้ข้อมูลอะไร ก็มานั่งแก้ typo ที่อาจจะมีอยู่บ้างเล็กน้อยใน dataset และเตรียมหา input ของ model นี้

เพราะด้วยจำนวนข้อมูลที่มีอยู่น้อยมากกกกกกกกกกกกกกกกกกกกกกกกกกกกกกกและจำนวนอารมณ์จาก samples ก็ไม่เท่ากัน ( Imbalanced ) แบบมาก ๆๆๆๆๆๆๆๆๆ เลยต้องลองหาหลาย ๆ วิธีเพื่อได้โมเดลที่ดีที่สุด

Imbalanced data

เริ่มด้วยการตัด emotion ที่มีจำนวน data น้อยมาก ๆ ออกไปซึ่งได้แก่ Sadness, Fear และ Disgust ทำให้โมเดลเราจะทำนายได้แค่ 5 classes [ Anger, Contempt, Happiness, Surprise, Other] ( papers ส่วนใหญ่ก็ใช้ 5 classes นี้ )

จากนั้นผมได้ลอง input หลาย ๆ แบบ โดยทำไปทั้งหมด 4 แบบ

  • Original Apex frame — ใช้เฟรม ณ จุด Apex มาเป็น input
  • Difference of Apex frame and Onset frame — เนื่องด้วยเราได้แปลงข้อมูลภาพของเราเป็นตัวเลขเมื่อนำเข้าโมเดล จึงลองเอาผลต่างของ Apex กับ Onset มาเป็น input เพื่อแสดงว่าภาพตอนพีคกับตอนเริ่มต่างกันยังไง
  • Optical flow of Apex frame and Onset frame — เปลี่ยนจากผลต่างตัวเลขของ 2 เฟรมมาเป็น Optical flow ซึ่งก็คือแพทเทิร์นการขยับของภาพ โดยจะแสดงเป็นกลุ่มการไหลของแสง
  • Optical flow of Apex frame and Onset frame + Original Apex frame — คือการนำทั้ง Optical flow เมื่อกี้และภาพของ input แบบที่ 1 มารวมกันและนำไปเป็น input

** Warning ภาพต่อไปนี้อาจจะมีเนื้อหาที่น่ากลัว ผมพยายามเลือกรูปที่ไม่ค่อยน่ากลัวแล้วครับ แต่ก็ยังน่ากลัวอยู่ T^T **

Original Apex frame
Difference of Apex frame and Onset frame
Optical flow
Optical flow + Original Apex frame

และผมได้ลองการแบ่ง train-validation data ทั้ง

  • K-folds cross validation — เพื่อใช้ประโยชน์ข้อมูลที่มีอยู่น้อยนิดให้มากที่สุดโดยแบ่งข้อมูลเป็นหลาย ๆ เซตและแยกกันเทรน ทำให้โมเดลได้เห็นข้อมูลหลายแบบมากขึ้น โดยใช้ Stratified Group เพราะทำให้ในการแบ่ง folds แต่ละครั้ง เกิดการแบ่งขึ้นโดยที่ sample ของแต่ละอารมณ์ เกิดความสมดุลกันมากที่สุด
  • LOSO ( Leave one subject out ) — เป็นการแบ่ง data โดยใช้ subject เป็นตัวแบ่งหลัก โดยจะมีจำนวนเซตทั้งหมดตามจำนวน subject ที่มี และแต่ละเซตก็จะมี subject เพียงคนเดียวที่เป็น validation data ส่วนที่เหลือจะเป็น training data ทำให้ผลัดกันเป็น validation ครบทุกคน ( วิธีนี้เป็นวิธีที่ใน papers ส่วนใหญ่ใช้กันจึงทำให้สามารถใช้ผลลัพธ์จาก LOSO ไปเปรียบเทียบได้ )

เมื่อได้ input และแบ่ง train-validation set แล้วต่อไปก็คือการเลือกใช้โมเดลนั่นเองคร้าบบบบ

Choosing the model — เลือกโมเดลที่ใช่ที่ชอบเพื่อเธอ

การตรวจจับ Micro-expression ถือเป็น 1 ในปัญหาของ Image classification ผมจึงเลือก CNN ( Convolutional Neural Network ) มาเป็นโมเดลของเรา โดยใช้เป็นโมเดล ResNet-18 ที่ pretrained มาจาก EfficientFace ซึ่งเทรนมาจาก MS-Celeb-1M และมีจำนวน classes มากถึง 12666 ที่เลือกใช้โมเดลตัวนี้เพราะได้ pretrained มาจาก dataset ที่เกี่ยวข้องกับใบหน้า ทำให้เวลาเอามาใช้ตรวจจับ Micro-expression ก็จะสามารถจับอารมณ์ได้เยอะขึ้น

MS-Celeb-1M dataset

Training model with SAMM — โมเดลยังมูฟออนไป epoch ต่อไป แต่ทำไมเรายังอยู่ที่เธอ

ส่วนนี้ก็ไม่มีอะไรมากครับ แค่ลองเอา training data มาใส่ในโมเดลและลองปรับพวก parameters ต่าง ๆ เพื่อให้ accuracy ออกมามากที่สุด ซึ่งตอนเทรนก็มีทั้ง validation loss เพิ่มขึ้น ลดลง เหวี่ยงไปเหวี่ยงมาเป็นรถไฟเหาะเลยครับ ตอนเทรนจะสังเกตได้ว่า model สามารถทำ accuracy กับ training set ได้ถึง 90–100% เลยครับแต่สำหรับ validation set ก็จะวนอยู่ประมาณ 40–60%

train-validation loss
validation loss like a rollercoaster

Evaluating model — โมเดลดีหรือไม่ ไม่รู้ รู้แค่เธอบอกว่าเราดีเกินไป

การที่จะประเมินว่าโมเดลเราดีหรือไม่ สามารถทำได้หลายวิธีครับ แต่ในโปรเจคนี้เราจะใช้

  • Accuracy — บอกความแม่นยำของโมเดลโดยหาได้จาก จำนวน sample ที่ทายถูกหารด้วยจำนวน sample ทั้งหมด แต่เพราะ data ของเรา imbalance จึงทำให้ไม่สามารถดูแค่ค่า Accuracy อย่างเดียวได้ เพราะถ้าเกิดโมเดลทำนาย class ที่มีจำนวนเยอะถูก ก็จะเป็นการดึงให้ Accuracy สูงกว่าความเป็นจริงได้
  • F1 score — ด้วยการที่ F1 score จะคิดคะแนนจากการดูจำนวนในแต่ละคลาสด้วย ทำให้ค่อนข้างแม่นยำกว่า Accuracy

และผมได้ลอง plot Confusion Matrix มาดู เพื่อ visualize ให้เห็นไปเลยว่าแนวโน้มของการทำนายเป็นแบบไหน

แต่แน่นอนว่าการที่จะบอกได้ว่าดีหรือไม่ ก็จำเป็นจะต้องมีตัวเปรียบเทียบหรือ Baseline ซึ่งในโปรเจคนี้มีทั้ง Human baseline และ Random baseline

Human baseline ได้ให้อาสาสมัครจำนวน 29 คน ลองทำแบบทดสอบในการแยก Micro-expression ดู โดยแบบทดสอบมีทั้งหมด 10 ข้อและได้ผลลัพธ์ดังนี้

  • Accuracy เฉลี่ยทุกข้ออยู่ที่ 27.59%
  • และมี Accuracy เฉลี่ยแต่ละข้อดังนี้
Accuracy เฉลี่ยแต่ละข้อ

Random baseline เกิดจากการสุ่มเลขระหว่าง 0 ถึง 4 เป็นจำนวน 10 เลข โดยสุ่มทั้งหมด 30 เซต เพื่อให้ใกล้เคียงกับ Human baseline ซึ่งได้ผลลัพธ์ดังนี้

  • Accuracy เฉลี่ยทุกข้ออยู่ที่ 21.38%
  • มี Accuracy เฉลี่ยแต่ละข้อดังนี้

ซึ่งพอมาเทียบกับโมเดลของเราที่เทรนโดยยังไม่เคยเห็น subject ทุกคนในแบบทดสอบ พบว่าโมเดลสามารถทำนายถูก 6 ข้อจาก 10 ข้อหรือคิด Accuracy เป็น 60%

ผลลัพธ์ที่โมเดลทำนายออกมา
AI compare with 29 people
AI compare with Human baseline and Random baseline

เมื่อนำมาวิเคราะห์ในแต่ละข้อพบว่า ข้อที่มนุษย์ได้ accuracy สูงกว่าข้ออื่น ๆ โมเดลก็สามารถทำนายข้อพวกนั้นได้ถูกต้อง

ส่วนโมเดลที่เทรนแบบ LOSO ก็ได้ผลลัพธ์ประมาณนี้ครับ

LOSO Accuracy and F1

Confusion matrix ของ LOSO

จะเห็นได้ว่าในช่อง diagonal ของแต่ละแถวจะมีค่ามากที่สุดในแถวนั้น ๆ ( แต่มันก็ยังกระจายอยู่ดี 😥 ) ซึ่งอันนี้คือโมเดลของผมที่มีค่า F1 score มากที่สุด เพราะส่วนใหญ่โมเดลอื่นจะสามารถจับ Anger กับ Other ได้ แต่ Contempt, Happiness, Surprise กลับจับได้น้อย โดยเฉพาะ Contempt ซึ่งน่าจะมาจากการที่อารมณ์นี้มักจะเกิดการขยับน้อยและส่วนใหญ่จะเกิดบริเวณมุมปาก ทำให้โมเดลอาจจะสับสนกับอารมณ์อื่น ๆ ที่เกิดบริเวณมุมปากอย่าง Happiness และ Anger ได้

Error analysis

ปัญหาหลัก ๆ ของโปรเจคนี้ที่ทำให้ accuracy ไม่ได้สูงมากเกิดจาก

  • จำนวนข้อมูลที่มีน้อย
  • ความ Imbalance ของข้อมูลในแต่ละ class
  • sample บางคลิป แทบไม่ขยับหรือขยับน้อยมาก
  • sample บางคลิป มีตำแหน่งหน้า ที่ไม่ตรงกันใน Apex frame กับ Onset frame ทำให้ optical flow ฟุ้งกระจาย

สามารถไปลอง model เล่น ๆ ได้ที่ Link..

และส่ง feedback หรือคำแนะนำได้ที่ Link

ในอนาคต ถ้ามีโอกาสได้ทำเกี่ยวกับเรื่องนี้อีก ผมก็อาจจะไปสนใจในส่วนของ Action Units เพราะถือเป็นอีก feature ที่ค่อนข้างมีความแน่นอนในการตรวจหาอารมณ์

สุดท้ายนี้ขอขอบคุณโครงการ AI Builders พี่ตอย พี่ปิงและพี่เมนเทอร์ทุกคนที่คอยให้ความรู้และแบ่งปันประสบการณ์ซึ่งมีส่วนช่วยให้โปรเจคนี้ผ่านไปได้ด้วยดี ขอบคุณมากครับ

พระอาทิตย์ขึ้นแล้ว แต่ accuracy ยังไม่ขึ้นเลย

--

--