[ML] LSTMs แบบ (เกือบ) ละเอียดยิบ ๆ

จริง ๆ ผมเขียนเรื่องนี้ไปแล้วรอบนึง แต่คิดว่ารอบนั้นน่าจะยังเขียนได้ละเอียดไม่พอ แถมมันยังคร่าวจนแทบจะไม่ได้อะไรเลย คราวนี้เลยจะพยายามเขียนเกี่ยวกับเจ้า machine learning ที่ชื่อว่า Long Short-Term Memory หรือ LSTMs ให้มันละเอียด และกลับมาอ่านเองได้รู้เรื่องที่สุด เข้าใจง่ายที่สุด โดยรวบรวมข้อมูลจากหลายสำนักมาเพื่อความแม่นยำ

แต่ก่อนจะเข้าเนื้อเรื่อง ซึ่งมันค่อนข้างจะไปเร็วและพยายามรวบรัด จึงขอให้ทุกท่านมีความรู้เรื่องเหล่านี้มาก่อนประมาณหนึ่งนะ อาจจะไม่มาก แต่พอเข้าใจ concept ของมันก็เป็นอันใช้ได้ เรื่องที่ว่าก็คือ

  • Machine learning คืออะไร ไปเข้าใจมาคร่าว ๆ ก่อน
  • Neural network เอาแค่มันทำงานยังไง และเข้าใจ concept คร่าว ๆ ก็พอ

เอาล่ะ ถ้ามีพื้นฐานเรื่องเหล่านี้มาบ้างแล้ว เราก็มาเริ่มกันเลยดีกว่า

Neural Networks (NNs)

ในโลกของ neural network รูปแบบหลักที่เรามักจะเจอบ่อย ๆ ก็คงจะไม่พ้นตามรูปที่เห็น คือการที่แบ่งข้อมูลออกเป็นสามส่วน อันได้แก่ input layer, hidden layer, และ output layer ซึ่งจุดเด่นของตัว NNs ก็คงหนีไม่พ้น hidden layer

โครงสร้างของ Neural network

Hidden layer ของ NNs ปฏิบัติตนราวกับ black box คือเราจะไม่มีทางรู้เลยว่าข้างในการทำงานของมันเป็นอย่างไร เป็นเรื่องที่เข้าใจยาก รู้แค่เพียงว่า มันจะทำการสุ่มตัวเลขมาบนแต่ละ node และสร้างน้ำหนักให้กับแต่ละเส้นที่โยงถึงกัน ผลลัพธ์ที่ได้ในแต่ละ node ก็จะมาจากการคูณกันของ น้ำหนักในเส้นกับค่าในแต่ละ node นั่นแหละ

hidden node = sigma(wight * node value) + bias

Note: bias ที่ถูกเพิ่มใน neural networks นั้นมีประโยชน์เพื่อทำให้กราฟสามารถขยับไปทางขวาหรือขยับไปทางซ้ายได้นั่นเอง

Neural network มีหลายประเภทมาก ๆ และในบทนี้ ประเภทของ NNs ที่เราสนใจและต้องการจะนำไปใช้คือ recurrent neural networks หรือเรียกสั้น ๆ ว่า RNNs

Recurrent Neural Networks (RNNs)

ถ้าแปลกันตรงตัว recurrent จะหมายถึง การหวนย้อนคืนกลับมาอีก ซึ่งการทำงานของ RNNs นั้นก็ตรงตัวตามชื่อเลย เพราะมันคือการเอาผลลัพธ์ที่ได้จากการคำนวณย้อนกลับมาใช้เป็นข้อมูลขาเข้าอีกครั้ง ดังรูป ซึ่งมีประโยชน์อย่างมากในข้อมูลที่มีความต่อเนื่อง เช่น time series ข้อมูลเสียง ข้อความ หรือแม้แต่รูปภาพเองก็ตาม

ในแต่ละ node ของ RNNs จะมีข้อมูลขาเข้าสองอย่างอันได้แก่ input ณ node นั้น ๆ และผลลัพธ์ที่ได้จากการคำนวณใน node ก่อนหน้า ซึ่งทั้งสองข้อมูลจะถูกนำมารวมเข้าด้วยกันและออกผลลัพธ์มาเป็นสองทางคือ ผลลัพธ์ที่ออก ณ node นั้น ๆ และออกเพื่อไปเข้าเป็นข้อมูลขาเข้าใน node ถัดไป

ข้อดีของ RNNs คือ มันมีการใช้ข้อมูลก่อนหน้าในการทำนายสิ่งที่อาจจะเกิดขึ้นในอนาคต นั่นหมายถึง อะไรที่เคยเกิดขึ้นในอดีตย่อมส่งผลต่อเหตุการณ์ที่จะเกิดขึ้นในอนาคตด้วย

แต่แม้ RNNs จะมีข้อดีในการทำงานของข้อมูลที่มีความต่อเนื่อง หนึ่งในข้อเสียของ RNNs ที่ต้องพบเจอคือ มันสามารถดูย้อนกลับได้แค่เพียงในช่วงระยะเวลาสั้น ๆ เท่านั้น ซึ่งปัญหาหลัก ๆ ของ RNNs นั้นเกิดมาจากค่า gradient ที่เริ่มน้อยลงในข้อมูลที่มีความยาวมากขึ้น จนแทบจะไม่สามารถเห็นความเปลี่ยนแปลงของ gradient ได้เลย ซึ่งปัญหานี้ถูกเรียกว่า Vanishing Gradient Problem (จะขอย่อว่า VGP เพื่อความกระชับในเนื้อหา)

Back-propagation

ก่อนจะเข้าสู่ว่า VGP มันคืออะไร ก็อยากจะให้ทำความเข้าใจกันก่อนว่า gradient คืออะไร ซึ่งก็หนีไม่พ้นที่จะต้องพูดถึงเรื่องของการทำ back-propagation ใน NNs ให้เข้าใจกันดีเสียก่อน

Back-propagation (หรือที่ผมจะขอเรียกว่า BP) คือการคำนวณย้อนหลังใน NNs เพื่อทำการปรับค่าน้ำหนักในแต่ละเส้นให้มีความสมดุลมากขึ้น ช่วยให้ NNs สามารถเรียนรู้ข้อมูลได้อย่างถูกต้องและแม่นยำมากขึ้นนั่นเอง

แต่ก่อนที่จะตรวจสอบน้ำหนักย้อนกลับโดยใช้ back-propagation สิ่งแรกที่ต้องทำก็คือ ต้องคำนวณไปจนเจอผลลัพธ์ก่อน เรียกกันว่า ‘Forward Pass’ ซึ่งพอคำนวณจนได้ผลลัพธ์ได้แล้ว ค่อยนำผลลัพธ์ของความผิดพลาดที่ได้มาเพื่อทำการเปลี่ยนแปลงค่าน้ำหนักใหม่ ซึ่งการทำย้อนกลับนี้จะเรียกว่า ‘Backward Pass’

ในการคำนวณไปข้างหน้านั้น เราจะสนใจเพียงสองค่าหลัก ๆ คือ Total Net Input ซึ่งเป็นการคำนวณน้ำหนักคูณถ่วงกับค่าของแต่ละ node และ Output ที่เป็นการคำนวณคำตอบของ node ที่ต้องการโดยใช้ activation function เข้ามาช่วย (เดี๋ยวเรื่องนี้อธิบายอีกทีข้างหลังเลย)

net = sigma(weight * node value) + bias
output = activation_function(net)

เมื่อการคำนวณเสร็จสิ้นจนถึง node ของผลลัพธ์ เราจะสามารถคำนวณค่าความผิดพลาดโดยรวมทั้งหมดของทุกผลลัพธ์ที่ออกมาได้โดยใช้สูตร Square Error มาช่วยในการคิดค่าความผิดพลาดโดยรวม และสิ่งนี้แหละที่เราเรียกว่า gradient

E_total = sigma((1/2) * (target - output)²)

และในที่สุดเราก็ได้เวลาคำนวณย้อนกับเพื่อนำค่าความผิดพลาดที่คำนวณมาได้ไปคิดดูว่า น้ำหนักจริง ๆ หลังจากผ่านการคำนวณไปแล้วควรเป็นเท่าไหร่กันแน่ หรือพูดในอีกความหมายคือ การเปลี่ยนแปลงของน้ำหนักเท่าไหร่ที่จะส่งผลต่อความผิดพลาดที่อาจจะเกิดขึ้นต่อไป

สูตร BP ของ RNNs
  • E : ค่าความผิดพลาดโดยรวม
  • o : ผลลัพธ์ที่ได้ในแต่ละ node
  • h : total net input
  • w : น้ำหนัก

สูตรด้านบนนี้เป็นการใช้หลักการ chain rule ธรรมดา ๆ เพื่อหาคำตอบที่ต้องการในด้านซ้าย โดยมีหลักการดังนี้

  • “ dE / do ” มันคือการคำนวณว่า ค่าความผิดพลาดที่เกิดขึ้นมีผลต่อค่าของผลลัพธ์ที่ได้มากน้อยเพียงใด
  • “ do / dh ” คือการคำนวณความเปลี่ยนแปลงของ total net input ในผลลัพธ์ที่ออกไปในแต่ละ node
  • “ dh / dh ” คือการคำนวณการเปลี่ยนแปลงของ total net input ใน node หนึ่ง ๆ ซึ่งอาจจะส่งผลต่อ total net input ในอีก node หนึ่ง
  • “ dh / dw ” คือการคำนวณค่า net input ที่อาจจะส่งผลต่อการเปลี่ยนแปลงในน้ำหนักนั่นเอง
แผนภาพนี้ตั้งใจให้เห็นว่า มันคือการคำนวณย้อนกลับโดยเอาผลลัพธ์ที่ได้มาเทียบกับผลลัพธ์ก่อนหน้า เพื่อหาความเปลี่ยนแปลงที่เกิดขึ้น เพื่อนำไปหาค่าน้ำหนักที่สมดุลที่สุด

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

จากสูตรดังกล่าวจะเห็นว่า ค่า gradient นั้นเมื่อถูกคำนวณไปนาน ๆ ค่าจะยิ่งลดน้อยลงจนแทบจะไม่เห็นการเปลี่ยนแปลงใด ๆ แม้ข้อมูลที่เข้ามาจะมีการเปลี่ยนแปลงไปมากมายหรือยิ่งใหญ่แค่ไหนก็ตาม ซึ่งเหตุผลใหญ่ ๆ ที่ทำให้ gradient ถดถอยลงไปจนแทบไม่เห็นความเปลี่ยนแปลงนั้นก็มาจากตัว activation function เองนั่นแหละ

Long Short-Term Memory networks (LSTMs)

สืบเนื่องจากปัญหาที่เกิดขึ้นใน RNNs เกี่ยวกับค่า gradient ที่มีค่าน้อยลงจากการทำงานของ back-propagation จึงได้มีการคิดค้น machine learning ตัวใหม่ที่ใช้หลักการคล้าย ๆ เดิม แต่เปลี่ยนตัวฟังก์ชั่นด้านในให้มีความเสถียรและมีประสิทธิภาพมากขึ้น ซึ่งนั่นก็คือ Long Short-Term Memory หรือเรียกย่อ ๆ ว่า LSTMs นั่นเอง

LSTMs เกิดขึ้นครั้งแรกในปี 1997 โดย Hochreiter และ Schmidhuber ซึ่งหลักการของมันก็ง่าย ๆ คือการเก็บ ‘สถานะ’ ของแต่ละ node เอาไว้ด้วย เผื่อว่าตอนย้อนกลับมาจะได้รู้ว่าค่านี้แท้จริงแล้วเป็นอะไรมาก่อน

สิ่งที่ทำให้เจ้าตัว LSTMs โดดเด่นขึ้นมานั้นก็คือการที่มันสามารถเลือกได้ว่า ข้อมูลไหนที่ควรจะจดจำ ข้อมูลไหนที่ควรจะกำจัดทิ้งออกไป ผ่านการ ‘ลืม’ ของสถานะใน node นั้น ๆ

LSTMs architecture อ้างอิงจากบทความของ Colah’s

ในแบบพื้นฐานของ RNNs นั้นไม่ได้มีอะไรหวือหวา อาจจะมีเพียงแค่ tan hyperbolic เพียงฟังก์ชั่นเดียวภายในที่คอยใช้คำนวณค่าต่าง ๆ ก็ได้ แต่ใน LSTMs นั้น ภายในของมันประกอบด้วยฟังก์ชั่นต่าง ๆ ที่ถูกใช้นำมาประกอบกันเพื่อสร้างฟังก์ชั่นพิเศษ อันได้แก่ การอ่านข้อมูล การเขียนข้อมูล การอัพเดตข้อมูล และการลืมข้อมูล ซึ่งทำให้การจดจำข้อมูลในแต่ละ node ของมันเป็นไปได้อย่างคล่องตัวมากขึ้น ซึ่งฟังก์ชั่นพวกนี้ก็เปรียบเสมือนประตูที่คอยควบคุมข้อมูลที่เข้ามาในแต่ละ node ให้เป็นไปตามทิศทางที่มันต้องการนั่นเอง

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

(อ้างอิงจาก: http://colah.github.io/posts/2015-08-Understanding-LSTMs/)

Forget Gate Layer ประตูลืม

Forget gate คือประตูที่จะใช้เป็นตัวกำหนดว่า ข้อมูลที่เข้ามานั้นสมควรที่จะได้ออกไปทั้งหมด หรือไม่สมควรที่จะมีข้อมูลใด ๆ หลุดรอดออกไปได้เลยกันแน่ ซึ่งข้อมูลที่จำเป็นต้องใช้ในการตัดสินใจว่าจะเก็บข้อมูลนี้ไว้หรือไม่นั้นก็มาจากข้อมูลขาเข้า ณ node นั้น ๆ รวมกับผลลัพธ์ที่ถูกคำนวณมาจาก node ก่อนหน้า ผ่านเข้า sigmoid function และนำไปคูณกับสถานะของ node ก่อนหน้าโดยใช้สูตร Pointwise Multiplication ในการคำนวณ

ผลลัพธ์ได้ของประตูบานนี้จะอยู่ที่ [0,1] ซึ่งค่า 0 หมายถึงไม่มีข้อมูลใดที่จะสามารถไหลผ่านไปได้เลย ในขณะที่ 1 หมายถึงปล่อยให้ข้อมูลที่เข้ามาไหลผ่านไปได้ทั้งหมดนั่นเอง

Input Gate Layer ประตูทางเข้า

Input Gate คือประตูที่ใช้เพื่อเปิดรับข้อมูลที่เข้ามาใหม่เพื่อให้บันทึกลงไปในแต่ละ node หรือเรียกว่าการ ‘write’ ข้อมูลลงไปนั่นเอง

การคำนวณของมันก็เช่นเดียวกันกับการคำนวณข้อมูลขาเข้าของ Forget Gate แต่สิ่งที่แตกต่างจะอยู่ในบรรทัดถัดไป

Update Cell State ประตูแปลงร่าง

ระหว่างที่ input gate เปิดประตูเพื่อรับข้อมูลมาจดจำใน node ตัวเอง มันก็จะมีอีก node หนึ่งที่จะถูกผลักเข้าสู่กระบวนการแปลงโฉมโดยฟังก์ชั่น tan hyperbolic เพื่อให้ได้อีกหนึ่งข้อมูลที่มีความใกล้เคียงกับข้อมูลขาออกจาก node นี้ ผลลัพธ์ที่ได้จะเหมือนเป็นผู้ท้าชิงในสนามที่จะถูกนำไปดัดแปลงอีกทีตามสถานะที่ถูกคำนวณมาก่อนหน้าเพื่อส่งเป็นข้อมูลขาออกต่อไป

เพราะหลังจากคำนวณที่ได้ข้อมูลที่กำลังจะเป็นข้อมูลขาออกแล้ว มันจะถูกนำไป pointwise กับข้อมูลที่ได้จากประตูทางเข้า และหลังจากได้ผลลัพธ์นี้ สุดท้ายมันก็จะเอาไป รวมกับข้อมูลแรกที่ได้จาก forget gate (ซึ่งถูก pointwise ไปกับสถานะจาก node ก่อนหน้าแล้ว) อีกที

ถ้าคิดว่าอ่านแล้วยังตามไม่ทัน แนะนำให้ดูรูปประกอบ

ซึ่งพอกระบวนการทั้งหมดเสร็จสิ้น ค่าที่ได้ออกมาจะเป็นค่าสถานะใหม่ของ node นั้น ๆ ที่ผ่านการอัพเดทสถานะจาก node ก่อนหน้า

Output Gate Layer ประตูทางออก

Output Gate คือประตูที่ใช้บอกว่า ข้อมูลนี้เตรียมพร้อมที่จะเป็นข้อมูลขาออกแล้วหรือยัง ซึ่งข้อมูลขาออกของแต่ละ node ใน LSTMs นั้นมีด้วยกันทั้งหมด 3 แห่ง แต่มีเพียง 2 ค่า คือ

  • ค่าที่เกิดจากคำนวณโดยมีการ update สถานะแล้ว (ซึ่งถูกคำนวณจากขั้นตอน Update cell state) ค่านี้จะถูกส่งต่อทันทีโดยไม่ผ่านฟังก์ชั่นใด ๆ อีกไปให้ node ถัดไป
Note: พูดง่าย ๆ คือค่าสถานะนี้จะดำเนินเป็นเส้นตรงเสมอจากขาเข้าไปจนขาออก โดยจะมีการเปลี่ยนแปลงจากการถูก pointwise ภายในแต่ละ node นั่นเอง
  • ค่าของข้อมูลขาเข้าที่ถูกดัดแปลงผ่านการคำนวณใน output gate ค่านี้จะถูกส่งต่อไปเป็นข้อมูลขาเข้าของ node ถัดไป และยังถูกส่งไปเป็นผลลัพธ์ของ node นั้น ๆ ด้วย

ในส่วนนี้เราจะพูดถึงเฉพาะค่าที่ถูกส่งต่อไปเป็นข้อมูลขาเข้าใน node ถัดไป (เพราะค่าแรกพูดไปแล้วในส่วนที่แล้ว)

ค่านี้ก็เช่นเดียวกับประตูอื่น ๆ คือการนำข้อมูลจาก node ที่แล้วที่เข้ามา รวมกับข้อมูลขาเข้าใน node นั้น ๆ ผ่านฟังก์ชั่น sigmoid เช่นเดียวกับประตูบานอื่น ๆ

แต่สิ่งที่แตกต่างกันก็คือ หลังจากที่มันผ่านการคำนวณค่า sigmoid แล้ว มันจะถูกนำมา pointwise กับค่าสถานะปัจจุบันของ node ที่ได้ถูกคำนวณมาเรียบร้อยแล้วจากประตูบานอื่นที่ผ่านมา ซึ่งค่าสถานะนั้นจะถูกนำไปเข้าฟังก์ชั่น tan hyperbolic หรือ tanh ก่อน และจึงนำผลลัพธ์ที่ได้หลังจากเข้าฟังก์ชั่นนั้นแล้วมา pointwise กับค่าที่ออกมาจาก sigmoid function นั่นเอง

ซึ่งผลลัพธ์ที่ได้จากการกระทำนี้จะถูกแบ่งออกไปเป็นสองข้อมูล คือผลลัพธ์ของ node นั้น ๆ และข้อมูลที่จะถูกส่งต่อไปเป็นข้อมูลขาเข้าใน node ต่อไป

Summary

ถ้าจะให้สรุปการทำงานของ LSTMs แบบรวบรัดที่สุดก็คงพูดได้ว่า มันเป็นการทำงานที่มีการเก็บสถานะของข้อมูลเอาไว้อยู่ตลอดเวลาผ่านประตูสามบานที่อยู่ภายในอันได้แก่ ประตูลืม ประตูทางเข้า และประตูทางออก ซึ่งประตูเหล่านี้จะเป็นตัวควบคุมทิศทางการไหลของข้อมูลในแต่ละ node แบบ analog นั่นเอง

ซึ่งจริง ๆ แล้ว รูปแบบของ LSTMs ไม่ได้จำเป็นต้องเป็นดังในภาพที่ให้ซะทีเดียว การทำงานภายในของมันอาจมีการปรับเปลี่ยนได้ตามความเหมาะสมของแต่ละงาน โดยใช้หลักการเดียวกันคือการพยายามยืดระยะเวลาของข้อมูลในแต่ละ node ให้สามารถอยู่ได้นานมากขึ้น เป็นความจำที่มีการศึกษาน้ำหนักของแต่ละ node ที่ถูกคำนวณในระยะเวลาสั้น ๆ ให้ยาวมากขึ้นตามชื่อ Long Short-Term Memory

ดูเหมือนจะจบแล้ว (ถ้าอ้างอิงตามบทความของ Colah’s ซึ่งอธิบายไว้ดีมาก ๆ) แต่มันมีเรื่องนึงที่ผมติดค้างไว้ตั้งแต่ต้น และอย่างที่บอกไป สิ่งนี้นี่แหละที่เป็นตัวปัญหาทำให้เกิด VGP ขึ้น จนต้องมี LSTMs ที่เปรียบหีบของฟังก์ชั่นช่วย ซึ่งเมื่อมันถูกนำมาจัดวางอย่างถูกที่ถูกทางแล้ว มันก็จะช่วยในการทำงานได้มากขึ้น

สิ่งเหล่านั้นคือสิ่งที่เรียกว่า activation function

Activation Function

Activation function ยังไม่มีชื่อภาษาไทยอย่างเป็นทางการจากเท่าที่สืบค้นมา แต่ ณ ที่นี้จะเรียกมันว่า ‘ฟังก์ชั่นช่วย’ เพราะมันได้ช่วยให้ผลลัพธ์ที่เป็นข้อมูลขาออกที่ออกมาจากในแต่ละ node มีประสิทธิภาพมากขึ้น

ฟังก์ชั่นช่วยจะช่วยในการจำกัดขอบเขตของค่าที่เป็นไปได้ให้น้อยลงจนสามารถเห็นขอบได้ ลองคิดเล่น ๆ ดูว่า ถ้าสมมติเราให้ค่าผลลัพธ์ที่ออกมาเป็นอะไรก็ได้ตั้งแต่ (- ∞, ∞) นั่นก็หมายถึงการที่ข้อมูลมันไร้ซึ่งขอบเขตและยากต่อการคำนวณใน node ต่อ ๆ ไป

ซึ่งในหลาย ๆ activation function นั้นพยายามให้ค่าอยู่ในช่วงระหว่าง [0,1] หรือ [-1,1] เป็นต้น ซึ่งจะยกตัวอย่างแต่ละฟังก์ชั่นให้ฟังแบบคร่าว ๆ ดังนี้

Step function

หลักการของมันก็ง่าย ๆ คือ ผลลัพธ์จะเป็น 1 ก็ต่อเมื่อ ค่าเริ่มต้นที่เข้ามานั้นมีค่ามากกว่า 0 และมันจะเป็น 0 ในกรณีที่ตรงกันข้ามกัน

แต่ข้อเสียหลัก ๆ ของมันเลยคือ มันสามารถตอบได้เพียงว่า ‘ใช่’ หรือ ‘ไม่ใช่’ ตามผลลัพธ์ที่ออกมาเป็น 0 หรือ 1 เท่านั้น นั่นหมายความว่า หากเราต้องการที่ใช้มันเพื่อทำนายมากกว่าแค่ 2 คำตอบ ก็อาจจะเป็นเรื่องยากต่อการตัดสินใจก็เป็นได้

Linear function

สูตรของการทำ linear นั้นก็คือสมการเส้นตรงธรรมดา ๆ เลยนั่นคือ

f(x) = ax + b

ซึ่งคราวนี้เราสามารถใช้มันเพื่อทำนายได้มากกว่า 2 คำตอบแล้ว

แต่มันก็ยังไม่ดีพออยู่ดี.. อย่าลืมว่าในการทำ BP นั้นเราจำเป็นต้องทำการคำนวณย้อนหลังซึ่งต้องใช้หลักการ derivative ในการหาคำตอบด้วยซึ่งค่า derivative ของ linear นั้นเป็นค่าคงที่ !

f’(x) = a

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

Logistic activation function (sigmoid: σ)

เมื่อ linear ไม่ได้เป็นผลลัพธ์ที่ดีเสมอไป และอีกอย่างคือ ช่วงคำตอบของการใช้ linear function นั้นเป็นไปได้ตั้งแต่ (- ∞, ∞) ซึ่งกว้างมาก การใช้ sigmoid function จึงเหมือนตัวช่วยที่ช่วยร่นระยะของข้อมูลให้อยู่แค่ในช่วง [0,1] เท่านั้น และหลักสำคัญคือยังช่วยให้ gradient มีความนุ่มนวลมากขึ้น (smooth gradient) ไม่แข็งเหมือน step function และใน linear function

f(x) = 1 / (1 + exp(-x))

แม้ sigmoid จะได้รับความนิยมอย่างมากในการคำนวณของ NNs แต่มันก็มีข้อเสียอยู่เหมือนกัน และตัวของ sigmoid นี่แหละที่เป็นเจ้าของปัญหา VGP ที่เกิดขึ้น

ทำความเข้าใจกันอีกครั้ง gradient คือค่าที่บอกว่า ความเปลี่ยนแปลงในค่าเริ่มต้นส่งผลต่อผลลัพธ์ที่กำลังจะออกมาในอนาคตนะ ซึ่งถ้าค่ามีมาก ก็จะบอกได้ถึงการเปลี่ยนแปลงที่มีมากตามไปด้วย

แต่การคำนวณย้อนหลังหลาย ๆ ตลบของ sigmoid นั้นยิ่งทำให้ค่า gradient ลดลงไปตามระยะทางที่ต้องผ่าน ซึ่งหมายความว่า แม้ค่าเริ่มต้นจะเปลี่ยนแปลงไปมากหรือน้อยแค่ไหนก็ตาม ค่า gradient เองก็ไม่ได้มีความเปลี่ยนแปลงไปจากเดิมมากสักเท่าไหร่ ซึ่งก็จะทำให้ NNs ไม่สามารถเรียนรู้ได้อย่างมีประสิทธิภาพเท่าที่ควร

Tan hyperbolic function (tanh)

ปัญหาของ sigmoid จริง ๆ อาจจะอยู่ที่ช่วงของมันมีค่าเล็กจนเกินไปจนทำให้เห็นความเปล่ยนแปลงใน gradient ได้น้อย tanh จึงได้ทำการแก้ไขปัญหานั้นด้วยการปรับระยะใหม่ของ sigmoid ให้มีช่วงกว้างมากขึ้นจาก [0,1] ใน sigmoid ให้กลายเป็น [-1,1] ไปซะเลย

f(x) = (exp(z) - exp(-z))/(exp(z) + exp(-z))

ซึ่งระยะที่กว้างขึ้นใน tanh ก็ได้ทำให้ gradient ใน tanh สามารถสังเกตได้ง่ายและเห็นความเปลี่ยนแปลงได้ดีขึ้นกว่าใน sigmoid อีกด้วย tanh จึงกลายเป็นฟังก์ชั่นที่ถูกใช้กันอย่างแพร่หลายในฐานะฟังก์ชั่นช่วย

Rectified linear unit (ReLU)

ถึงแม้ว่า tanh จะทำงานได้ดีในตัวของมันเองอยู่แล้ว ก็ยังมีคนอีกส่วนหนึ่งที่เสนออีกฟังก์ชั่นที่น่าสนใจกว่าและประกาศตนว่าเป็นฟังก์ชั่นที่ทำงานได้ดีกว่าฟังก์ชั่นอื่น ๆ ด้วย ซึ่งนั่นก็คือ ReLU

หลักการของ ReLU นั้นง่ายแสนง่าย มันแค่ตรวจสอบเอาว่าค่าที่ส่งเข้ามานั้นมากกว่า 0 หรือไม่ ถ้าใช่ก็แค่ส่งค่านั้นไปทำงานต่อ แต่ถ้าไม่ใช่ก็จับให้มันเท่ากับ 0 ซะให้หมด !

f(x) = max(0,x)

นั่นหมายถึง ค่าที่เป็นไปได้นั้นคือ [0,∞) ซึ่งถ้าเทียบกับ tanh แล้วมันก็มีความน่าสนใจกว่าตรงที่การคำนวณนั้นเป็นไปได้ง่ายกว่าหลายเท่า

แต่.. ใช่ว่าจะไม่มีข้อเสีย เพราะสิ่งที่เป็นข้อเสียหลัก ๆ เลยของ ReLU นั้นอยู่ในช่วงที่ค่าของข้อมูลเกิดติดลบหรือเท่ากับศูนย์ขึ้นมา เพราะมันจะส่งผลให้กับการทำงานของกราฟไม่สามารถควบคุมค่าที่ติดลบได้เท่าที่ควร


จริง ๆ ก็ไม่ได้อยากจะขึ้นหัวข้อว่า LSTMs สักเท่าไหร่ เพราะดูเนื้อหาของมันแทบจะมีอยู่แค่ตรงกลางสั้น ๆ นิดเดียว แต่กว่าที่จะเข้าใจเรื่องของ LSTMs ได้อย่างกระจ่างถ่องแท้ก็ต้องอาศัยเรื่องอื่น ๆ อีกมากมายเข้ามาช่วยในการอธิบายเหตุผล ความเป็นมาเป็นไป รวมไปถึงหลักการทำงานของมันอีกด้วย

ปล. reference เยอะมาก เอามาแปะในนี้น่าจะได้ medium อีกหนึ่งชุด