Make your own Neural Network #4

Thana Hongsuwan
12 min readJan 1, 2024

--

ในบทความที่ผ่านมาได้อธิบายการนำเอาเมทริกซ์มาใช้ในโครงข่ายประสาทเทียม ในบทความนี้จะแสดงการนำมาใช้จริงในโครงข่ายประสาทเทียมแบบ 3 ชั้น

บทความนี้เรียบเรียงจากหนังสือ Make your own Neural Network

A Three Layer Example with Matrix Multiplication

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

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

เราจะมาแนะนำศัพท์ที่ใช้กันทั่วไปในเรื่องของ Neural Network กันก่อน ชั้นแรกที่เรารู้จักกัน ก็คือ ชั้นอินพุต ชั้นสุดท้าย ก็คือ ชั้นเอาต์พุต ส่วนชั้นตรงกลาง เรียกว่า ชั้นฮิดเดน (Hidden Layer) ฟังดูลึกลับมืดมนใช่ไหม แต่จริงๆ ไม่มีเหตุผลอะไรลึกลับมืดมนหรอกครับ ชื่อมันติดมาเท่านั้นเอง เพราะค่าเอาต์พุตของชั้นนี้ ไม่จำเป็นต้องปรากฏชัดเจนเหมือนเอาต์พุตอื่น เลย “ซ่อน” อยู่ ยอมรับว่าอาจจะฟังดูจืดไปหน่อย แต่ไม่มีเหตุผลอะไรที่ดีกว่านี้อีกแล้วจริงๆ

มาลองดูเครือข่ายตัวอย่างที่แสดงในแผนภาพกันดีกว่าครับ เราเห็นว่าอินพุตทั้งสามตัวมีค่าเท่ากับ 0.9, 0.1 และ 0.8 ดังนั้นเมทริกซ์อินพุต I จึงมีดังนี้

ง่ายใช่มั้ยล่ะ เสร็จชั้นอินพุตแรกแล้ว เพราะชั้นอินพุตมีหน้าที่แค่แสดงอินพุตเท่านั้น

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

ดังที่เราเพิ่งกล่าวถึงไป สัญญาณที่รวมเข้าสู่ชั้นกลางนี้คือ X = W.I โดยที่ I คือเมทริกซ์ของสัญญาณอินพุต และ W คือเมทริกซ์ของค่าน้ำหนัก เรามี I แล้ว แต่ W คืออะไร? แผนภาพด้านล่างแสดงค่าน้ำหนักบางส่วน ที่สร้างขึ้นโดยการสุ่ม

คุณจะเห็นได้ว่าน้ำหนักระหว่างโหนดอินพุตแรกและโหนดแรกใน Hidden Layer ตรงกลางคือ w1,1 = 0.9 ตรงกับในแผนภาพเครือข่ายด้านบน ในทำนองเดียวกัน คุณจะเห็นน้ำหนักสำหรับลิงก์ระหว่างโหนดที่สองของอินพุตและโหนดที่สองของ Hidden Layer คือ w2,2 = 0.8 ดังที่แสดงในแผนภาพ แผนภาพไม่ได้แสดงลิงก์ระหว่างโหนดอินพุตที่สามและโหนด Hidden Layer แรก ซึ่งเรากำหนดให้เป็น w3,1 = 0.1

แต่เดี๋ยวก่อน ทำไมเราถึงเขียน “input_hidden” ถัดจาก W นั่นเป็นเพราะ W input_hidden คือน้ำหนักระหว่างเลเยอร์อินพุตและ Hidden Layer เราต้องการ
เมทริกซ์ของน้ำหนักอีกชุดหนึ่งสำหรับลิงก์ระหว่าง Hidden Layer และ
เลเยอร์เอาต์พุต และเราสามารถเรียกมันว่า W hidden_output

ต่อไปนี้คือเมทริกซ์ที่สองของ W hidden_output ที่ใส่ค่าน้ำหนักเข้าไปแล้ว จะเห็นได้ว่า ลิงก์ระหว่าง Hidden Layer ที่สามและโหนดเอาต์พุตที่สามเป็น w3,3 = 0.9 เช่นเดียวกับค่าในรูป

เยี่ยมมาก!

เราได้จัดเรียงเมทริกซ์น้ำหนักแล้ว ไปต่อกันกับการหาอินพุตแบบรวมที่มีการควบคุมเข้าสู่ Hidden Layer กันเถอะ เราควรตั้งชื่อที่สื่อความหมายด้วย เพื่อให้เรารู้ว่ามันหมายถึงอินพุตรวมไปยังเลเยอร์กลาง ไม่ใช่เลเยอร์สุดท้าย เรียกมันว่า X hidden

X hidden = W input_hidden ∙ I

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

เราจะใช้คอมพิวเตอร์คำนวณส่วนนี้ออกมาให้ ซึ่งจะทำสิ่งนี้ร่วมกันโดยใช้ภาษา Python ในตอนต่อๆ ไป (ต้องติดตามต่อไป 55) เราจะไม่ทำตอนนี้เพราะเราไม่อยากเสียสมาธิจากซอฟต์แวร์คอมพิวเตอร์ในตอนนี้

ดังนั้นเรามีอินพุตแบบรวมที่มีการควบคุมเข้าสู่เลเยอร์ซ่อนตรงกลาง ซึ่งก็คือ 1.16, 0.42 และ 0.62 และเราใช้เมทริกซ์เพื่อทำงานหนักๆ ให้เรา นั่นเป็นความสำเร็จที่น่าภาคภูมิใจ!

มาสร้างการรวมอินพุต เข้าสู่ Hidden Layer ที่สองกันเถอะ

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

O hidden = sigmoid( X hidden )

ฟังก์ชันการทำงานแบบ sigmoid จะถูกนำไปใช้กับแต่ละองค์ประกอบใน X hidden เพื่อผลิตเมทริกซ์ที่มีเอาต์พุตของ Hidden Layer ตรงกลาง

มาตรวจสอบองค์ประกอบแรกกันเพื่อให้แน่ใจกันดีกว่า ฟังก์ชันการทำงานแบบ sigmoid คือ y = 1/(1 + e −x) ดังนั้นเมื่อ x = 1.16 จะได้ e^1.16 = 0.3135 นั่นหมายความว่า y = 1/(1 + 0.3135) = 0.761

คุณจะสังเกตได้ว่าค่าของผลลัพธ์ทั้งหมดที่ได้จาก sigmoid จะอยู่ระหว่าง 0 ถึง 1 เท่านั้น เพราะว่าฟังก์ชัน sigmoid นี้จะไม่สร้างค่าที่อยู่นอกขอบเขตดังกล่าว ลองย้อนกลับไปดูกราฟของฟังก์ชัน logistic เพื่อแสดงให้เห็นภาพได้ชัดเจนยิ่งขึ้น

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

ถ้าเป็นเครือข่ายประสาทเทียมสองชั้น เราก็จะหยุดแค่นี้แหละ เพราะนี่คือเอาต์พุตจากเลเยอร์ที่สอง แต่เราไม่หยุด เพราะเรามีเลเยอร์ที่สามอีก

แล้วเราจะคำนวณสัญญาณผ่านเลเยอร์ที่สามได้อย่างไร? จริงๆ แล้ววิธีคล้ายๆ กับเลเยอร์ที่สองเลย ไม่มีอะไรต่างกันมาก เราแค่มีสัญญาณเข้าสู่เลเยอร์ที่สาม คล้ายๆ กับที่เรามีเข้าสู่เลเยอร์ที่สอง

เรายังคงมีลิงค์ที่มีน้ำหนัก และยังคงมีฟังก์ชัน sigmoid เพื่อปรับการตอบสนองให้คล้ายกับธรรมชาติ ดังนั้นสิ่งที่ต้องจำไว้คือ ไม่ว่าเราจะมีเลเยอร์กี่ชั้น เราก็สามารถพิจารณาแต่ละเลเยอร์เหมือนกัน ด้วยสัญญาณที่เข้ามา เราเพียงรวมสัญญาณ ประมวลค่าน้ำหนักจากสัญญาณที่เข้ามา จากนั้นก็นำมาผ่าน Activation Function เพื่อผลิตเอาต์พุตจากเลเยอร์นั้น เราไม่สนใจว่าจะมีกี่ชั้น จะเป็นชั้นที่ 3 หรือชั้นที่ 103 วิธีการก็ยังคงเหมือนเดิม

เอาล่ะ เรามาคำนวณสัญญาณเข้าที่รวมและปรับแล้วเข้าสู่เลเยอร์สุดท้ายนี้กัน โดย X = W.I เหมือนกับที่เราทำมาก่อนหน้านี้

สัญญาณเข้าในเลเยอร์นี้ ก็คือเอาต์พุตที่มาจากเลเยอร์ที่สองที่เราเพิ่งคำนวณไป
O hidden และน้ำหนักที่ใช้ก็คือน้ำหนักสำหรับลิงค์ที่เชื่อมต่อระหว่างเลเยอร์ที่สองและสาม W hidden_output ซึ่งไม่ใช่น้ำหนักที่เราใช้ระหว่างเลเยอร์แรกและเลเยอร์ที่สอง ดังนั้นเราจะมี

X output = W hidden_output ∙ O hidden

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

แผนภาพที่ได้รับการอัปเดตตอนนี้แสดงความคืบหน้าของเราในการป้อนสัญญาณจากอินพุตเริ่มต้น ผ่านไปยังอินพุตที่รวมกันไปยังเลเยอร์สุดท้าย

งานที่เหลืออยู่ก็คือการใช้ activation function sigmoid ซึ่งไม่ยากเลย

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

เอาต์พุตสุดท้ายของเครือข่ายประสาทเทียมตัวอย่างที่มีสามเลเยอร์นี้คือ 0.726, 0.708 และ 0.778

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

แล้วยังไงต่อไป

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

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

Learning Weights From More Than One Node

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

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

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

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

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

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

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

ในตัวอย่างนี้มีโหนดสองโหนดที่ส่งสัญญาณไปยังโหนดเอาต์พุต โดยมีน้ำหนักของลิงค์คือ 3.0 และ 1.0 หากเราแบ่งความผิดพลาดตามสัดส่วนของน้ำหนักเหล่านี้ เราจะเห็นได้ว่าควรใช้ 3/4 ของความผิดพลาดของเอาต์พุตเพื่ออัปเดตน้ำหนักที่มากกว่า และ 1/4 ของความผิดพลาดสำหรับน้ำหนักที่น้อยกว่า

เราสามารถขยายแนวคิดเดียวกันนี้ไปยังโหนดอื่นๆ ได้อีก เช่น หากเรามีโหนด 100 โหนดเชื่อมต่อกับโหนดเอาต์พุต เราจะแบ่งความผิดพลาดไปทั่วทั้ง 100 การเชื่อมต่อไปยังโหนดเอาต์พุตนั้นตามสัดส่วนของความมีส่วนร่วมของลิงค์แต่ละตัวต่อความผิดพลาด โดยจะบ่งชี้ด้วยขนาดของน้ำหนักของลิงค์

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

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

Backpropagating Errors From More Output Nodes

แผนภาพต่อไปนี้แสดงเครือข่ายง่ายๆ ที่มีโหนดอินพุต 2 โหนด แต่ตอนนี้มีโหนดเอาต์พุต 2 โหนด

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

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

ให้ดูรูปภาพอีกครั้ง จะเห็นว่าเราติดป้ายข้อผิดพลาดที่โหนดเอาต์พุตแรกเป็น e1 โปรดจำไว้ว่านี่คือความแตกต่างระหว่างเอาต์พุตที่ต้องการที่จัดเตรียมโดยข้อมูลการฝึก t1 และเอาต์พุตจริง o1 นั่นคือ e1 = (t1 — o1) ข้อผิดพลาดที่โหนดเอาต์พุตที่สองมีป้ายกำกับว่า e2

คุณจะเห็นจากแผนภาพว่าข้อผิดพลาด e1 ถูกแบ่งตามสัดส่วนของลิงก์ที่เชื่อมต่อกัน ซึ่งมีน้ำหนัก w11 และ w21 ในทำนองเดียวกัน e2 จะถูกแบ่งตามสัดส่วนของน้ำหนัก w21 และ w22

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

ในทำนองเดียวกันส่วนของ e1 ที่ใช้ในการปรับค่าน้ำหนัก w21 คือ

หาก w11 มีขนาดเป็นสองเท่าของ w21 สมมติว่า w11 = 6 และ w21 = 3 ดังนั้นสัดส่วนของ e1 ที่ใช้ในการปรับ w11 จะเป็น 6/(6+3) = 6/9 = 2/3 นั่นหมายความว่าจะเหลือ e1 อีก 1/3 สำหรับน้ำหนักที่น้อยกว่า w21 ซึ่งเราสามารถยืนยันได้โดยใช้นิพจน์ 3/(6+3) = 3/9 ซึ่งเท่ากับ 1/3

แต่หากทั้งสองมีน้ำหนักเท่ากัน สัดส่วนทั้งสองจะเท่ากันครึ่งหนึ่ง ตามที่คาดไว้ มาดูกันให้แน่ใจ สมมติว่า w11 = 4 และ w21 = 4 ดังนั้นสัดส่วนจะเป็น 4/(4+4) = 4/8 = 1/2 สำหรับทั้งสองกรณี

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

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

Backpropagating Errors To More Layers

แผนภาพต่อไปนี้แสดงเครือข่ายประสาทเทียมแบบง่าย ๆ ที่มี 3 ชั้น ได้แก่ ชั้นข้อมูลเข้า ชั้น hidden และชั้นข้อมูลออก

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

จากภาพข้างล่าง จะเห็นได้ว่าต้องทำอะไรบ้างเมื่อมีเลเยอร์ใหม่เพิ่มเข้ามา ก็เพียงแค่นำข้อผิดพลาดที่เกี่ยวข้องกับเอาต์พุตของโหนดชั้นซ่อน (e_hidden) และแบ่งข้อผิดพลาดตามสัดส่วนอีกครั้ง ตามลิงก์ก่อนหน้าระหว่างชั้นอินพุตและชั้นซ่อน (w_ih) แผนภาพถัดไปแสดงแนวความคิดนี้

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

หากเราใช้ข้อผิดพลาดในเอาต์พุตของโหนดชั้นเอาต์พุต (e_output) ไปก่อน แล้วเราจะใช้ข้อผิดพลาดอะไรสำหรับโหนดชั้นซ่อน (e_hidden) นี่เป็นคำถามที่ดี เพราะโหนดในชั้นซ่อนกลางไม่มีข้อผิดพลาดที่ชัดเจน เราทราบจากการป้อนสัญญาณอินพุตไปข้างหน้าว่า ใช่ แต่ละโหนดในชั้นซ่อนมีเอาต์พุตเดียว คุณคงจำได้ว่านั่นเป็นฟังก์ชันกระตุ้นที่ใช้กับผลรวมถ่วงน้ำหนักของอินพุตไปยังโหนดนั้น แต่เราจะคำนวณข้อผิดพลาดได้อย่างไร

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

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

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

เราสามารถรวมข้อผิดพลาดที่แยกออกมาสำหรับลิงก์ต่างๆ โดยใช้ Back Propagation ข้อผิดพลาดที่เราเพิ่งเห็นก่อนหน้านี้ ดังนั้นข้อผิดพลาดของโหนดที่ซ่อนอยู่แรกคือผลรวมของข้อผิดพลาดแบบแยกในลิงก์ทั้งหมดที่เชื่อมต่อไปข้างหน้าจากโหนดเดียวกัน ในแผนภาพด้านบน เรามีเศษเสี้ยวของข้อผิดพลาดเอาต์พุต e output,1 บนลิงก์ที่มีน้ำหนัก w 11 และเศษเสี้ยวของข้อผิดพลาดเอาต์พุต e output,2 จากโหนดเอาต์พุตที่สองบนลิงก์ที่มีน้ำหนัก w 12

ซึ่งสามารถเขียนได้ดังนี้

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

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

แผนภาพถัดไปแสดงแนวคิดเดียวกันที่นำไปประยุกต์ใช้กับชั้นก่อนหน้า โดยทำงานย้อนกลับไป

Backpropagating Errors with Matrix Multiplication

เราสามารถใช้การคูณเมทริกซ์มาทำให้การคำนวณยุ่งยากพวกนี้มันง่ายขึ้นได้ไหม? เพราะตอนที่เราทำ feed forword ก็ได้ผลดีในการใช้การคูณเมทริกซ์มาช่วยคำนวณ

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

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

เราจะเริ่มต้นที่ข้อผิดพลาดที่ออกมาจากเครือข่ายประสาทเทียมที่ชั้นเอาต์พุตสุดท้าย ในที่นี้เรามีสองโหนดในชั้นเอาต์พุต คือ e 1 และ e 2

มาสร้างเมทริกซ์สำหรับข้อผิดพลาดใน hidden layer กัน อาจจะฟังดูยาก แต่เราจะทำทีละนิด

เริ่มที่โหนดแรกในชั้นซ่อน: ถ้าดูแผนภาพด้านบนอีกครั้ง จะเห็นว่าข้อผิดพลาดของโหนดซ่อนแรกมีสองเส้นทางที่มาจากชั้นเอาต์พุต เส้นทางเหล่านี้นำสัญญาณข้อผิดพลาด e1 * w11 / (w11 + w21) และ e2 * w12 / (w12 + w22) มา

โหนดที่สองในชั้นซ่อนก็เหมือนกัน: มีสองเส้นทางที่ส่งผลต่อข้อผิดพลาด ได้แก่ e1 * w21 / (w21 + w11) และ e2 * w22 / (w22 + w12) ซึ่งก่อนหน้านี้เราได้เห็นวิธีคำนวณนิพจน์เหล่านี้ไปแล้ว

เราได้เมทริกซ์ต่อไปนี้สำหรับชั้นซ่อนแล้ว ค่อนข้างซับซ้อนนิดหน่อย

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

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

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

ถึงเวลาที่จะทำอะไรที่สนุกๆ หน่อยแล้ว!

ลองดูนิพจน์ด้านบนอีกครั้งนะครับ จะเห็นได้ว่าสิ่งที่สำคัญที่สุดคือการคูณข้อผิดพลาดเอาต์พุต e_n กับน้ำหนักที่เชื่อมโยง w_ij ยิ่งน้ำหนักมากเท่าไหร่ ข้อผิดพลาดเอาต์พุตก็จะถูกส่งกลับไปยังชั้นซ่อนมากขึ้นเท่านั้น ตรงนี้สำคัญมาก ส่วนเศษส่วนของนิพจน์เป็นเหมือนตัวปรับสเกล ถ้าเราละเว้นตัวปรับสเกลนี้ไป เราจะเสียแค่การ scaling ของข้อผิดพลาดที่ถูกส่งกลับเท่านั้น หมายความว่า e1 * w11 / (w11 + w21) จะกลายเป็น e1 * w11 ซึ่งง่ายกว่าเยอะ

เมื่อเราทำเช่นนั้นเมทริกซ์การคูณก็จะง่ายขึ้นเยอะเลย

เมทริกซ์น้ำหนักนั้นเหมือนกับเมทริกซ์ที่เราสร้างไว้ก่อนหน้านี้ แต่ถูกพลิกกลับตามเส้นทแยงมุม ทำให้มุมบนขวาไปอยู่ด้านล่างซ้าย และมุมล่างซ้ายไปอยู่ด้านบนขวา การกระทำนี้เรียกว่าการ “transpose” เมทริกซ์ และเขียนเป็น w^T

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

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

เยี่ยมเลย! แค่ตัดตัวคูณปรับสเกลออกไปเนี่ย ถูกต้องแล้วเหรอ? ปรากฏว่าการส่งกลับสัญญาณข้อผิดพลาดแบบง่ายๆ นี้ใช้ได้ผลดีไม่แพ้แบบดั้งเดิมที่ซับซ้อนกว่าที่เราเคยทำในตอนแรก

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

How Do We Actually Update Weights?

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

จนถึงตอนนี้เราได้แพร่กระจายข้อผิดพลาดกลับไปยังแต่ละชั้นของเครือข่ายแล้ว ที่เราทำแบบนี้เพราะอะไร? ก็เพราะข้อผิดพลาดจะถูกใช้เป็นแนวทางในการปรับน้ำหนักเชื่อมต่อไง เพื่อปรับปรุงคำตอบโดยรวมที่เครือข่ายประสาทเทียมให้ออกมา ซึ่งมันก็เหมือนกับสิ่งที่เราทำกับตัวแยกประเภทเชิงเส้น (linear classifier) ในตอนเริ่มต้นของเรื่องนี้นั่นแหละ

แต่โหนดเหล่านี้ไม่ใช่ตัวแยกประเภทเชิงเส้นธรรมดานี่นา โหนดเหล่านี้จะซับซ้อนกว่าเล็กน้อย เพราะมันรวมสัญญาณแบบถ่วงน้ำหนักที่ส่งเข้ามาในโหนด แล้วใช้ฟังก์ชันซิกมอยด์ (sigmoid function) ได้เหรอ คำถามคือ เราจะปรับน้ำหนักเชื่อมต่อสำหรับลิงค์ที่เชื่อมระหว่างโหนดที่ซับซ้อนเหล่านี้ได้ยังไงกันล่ะ? ทำไมเราไม่ใช้พีชคณิตขั้นสูงอะไรสักอย่างคำนวณโดยตรงเลยว่าน้ำหนักควรเป็นเท่าไหร่?

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

จะเห็นว่ามันไม่ง่ายเลย แค่ดูสมการสุดสยองนี่ก็พอแล้ว มันแสดงเอาต์พุตของโหนดเอาต์พุตอันเป็นผลจากอินพุตและน้ำหนักเชื่อมต่อในเครือข่ายประสาทเทียมแบบง่ายๆ ที่มี 3 ชั้น ชั้นละ 3 โหนด อินพุตที่โหนด i คือ x i น้ำหนักสำหรับลิงค์ที่เชื่อมต่อโหนด i ไปยังโหนดซ่อน j คือ w i,j เอาต์พุตของโหนดซ่อน j ก็คือ x j และน้ำหนักสำหรับลิงค์ที่เชื่อมต่อโหนดซ่อน j ไปยังโหนดเอาต์พุต k ก็คือ w j,k สัญลักษณ์ Σ แปลกๆ นั่นหมายถึงให้บวกนิพจน์ถัดไปสำหรับค่าทั้งหมดระหว่าง a กับ b นะ

โอ้โห! งั้นอย่าไปยุ่งกับมันเลย แทนที่จะพยายามคิดอะไรให้ซับซ้อน เราอาจจะลองใช้ค่าน้ำหนักแบบสุ่มจนกว่าจะเจอค่าที่เหมาะสมก็ได้ดีไหม

ฟังดูบ้าๆ บอๆ ใช่มั้ย แต่จริงๆ แล้วยามเจอปัญหาที่ยากๆ การใช้วิธีนี้ก็ไม่เลวเลย! มันคือสิ่งที่เรียกว่า ‘วิธีบุกเบิก’ น่ะ

ลองนึกถึงการแฮ็คพาสเวิร์ด บางคนก็ใช้ brute force นี้ล่ะ โดยลองทุกความเป็นไปได้จนกว่าจะเจอ วิธีนี้ใช้ได้ดีถ้าพาสเวิร์ดคุณเป็นคำในภาษาอังกฤษและไม่ยาวเกินไป เพราะคอมพิวเตอร์ธรรมดาที่บ้านก็ทำได้

แต่นี่เราพูดถึงน้ำหนักในเครือข่ายประสาทเทียมนะ ลองคิดว่าแต่ละน้ำหนักมีค่าได้ตั้ง 1000 แบบ ระหว่าง -1 ถึง +1 เช่น 0.501, 0.203 หรือ 0.999 เครือข่ายประสาทเทียมแบบ 3 ชั้น 3 โหนดต่อชั้น มีน้ำหนักทั้งหมด 18 ตัว แปลว่าเรามี 18,000 ความเป็นไปได้ที่จะต้องลอง!

ถ้าเครือข่ายทั่วไปมี 500 โหนดต่อชั้น นั่นเท่ากับมี 500 ล้าน ความเป็นไปได้เลย! ถ้าใช้เวลาหนึ่งวินาทีต่อการคำนวณหนึ่งชุด เราก็จะใช้เวลา 16 ปี แค่เพื่ออัพเดทน้ำหนักหลังจากดูข้อมูลฝึกฝนแค่ตัวเดียว! แล้วถ้ามีข้อมูลฝึกฝนพันตัวละ? 16,000 ปีเลยแหละ!

คุณจะเห็นได้ว่าวิธีแบบ brute force นั้น น่าจะใช้ไม่ได้เช่นกัน ในความเป็นจริง มันแย่ลงอย่างรวดเร็วเมื่อเราเพิ่มชั้นเครือข่าย โหนด หรือความเป็นไปได้สำหรับค่าน้ำหนัก เพราะจะยิ่งใช้เวลามากขึ้นอย่างมาก

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

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

สิ่งแรกที่เราต้องทำคือ ยอมรับความเป็นจริงอันโหดร้าย

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

ความ “โหดร้าย” ยังไม่หมดแค่นั้น! เพราะยังมีปัญหาอื่นๆ อีก

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

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

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

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

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

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

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

มาลองดูแนวคิดการไต่ระดับความชันนี้ด้วยตัวอย่างง่ายๆ เพื่อให้เข้าใจกันถ่องแท้ กราฟด้านล่างแสดงฟังก์ชันง่ายๆ คือ y = (x — 1)² + 1 ถ้าฟังก์ชันนี้คือความผิดพลาด เป้าหมายของเราก็คือการหาค่า x ที่ทำให้ y มีค่าน้อยที่สุด ลองสมมติว่าฟังก์ชันนี้ไม่ง่ายแบบนี้ แต่เป็นฟังก์ชันยากๆ ซับซ้อนแทน

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

ลองจินตนาการว่าเราเริ่มต้นจากจุดอื่น ดังที่แสดงในกราฟถัดไป

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

สิ่งที่จำเป็นต้องเลือกคือขนาดของก้าวที่เดิน เพื่อป้องกันการเดินเลยจุดต่ำสุดไปแล้วเด้งไปมาไม่รู้จบ ลองนึกภาพว่าถ้าเราอยู่ห่างจากจุดต่ำสุดจริงครึ่งเมตร แต่ก้าวได้ทีละ 2 เมตร เราจะพลาดจุดต่ำสุดต่อไป เพราะทุกก้าวที่เดินไปจะเลยจุดต่ำสุดไปหมด การลดขนาดก้าวให้สัมพันธ์กับความลาดชันจะทำให้เราเดินก้าวเล็กๆ เมื่อเข้าใกล้จุดต่ำสุด นี่เป็นไปตามสมมติฐานว่ายิ่งใกล้จุดต่ำสุด ความลาดชันจะยิ่งน้อยลง ซึ่งเป็นสมมติฐานที่สมเหตุสมผลสำหรับฟังก์ชันต่อเนื่องส่วนใหญ่ แต่จะไม่ค่อยเหมาะกับฟังก์ชันซิกแซกที่มีรอยกระโดดและรอยแหว่ง ซึ่งนักคณิตศาสตร์เรียกว่า ‘ความไม่ต่อเนื่อง’ (discontinuities)

รูปต่อไปนี้แสดงแนวคิดการปรับขนาดก้าวตามความลาดชันของฟังก์ชันที่ลดลง ซึ่งเป็นตัวบ่งชี้ที่ดีว่าเราอยู่ใกล้จุดต่ำสุดแค่ไหน

เอ้อ สังเกตไหมว่าเราเพิ่มค่า x ในทิศทางตรงข้ามกับความลาดชัน เมื่อความลาดชันเป็นบวกเราจะลดค่า x ลง แต่ถ้าความลาดชันเป็นลบเราเพิ่มค่า x ขึ้น

เมื่อเราทำการไต่ระดับความชันนี้ เราไม่ได้คำนวณหาจุดต่ำสุดที่แท้จริงโดยใช้พีชคณิต เพราะสมมติว่าฟังก์ชัน y = (x — 1)² + 1 ซับซ้อนและยากเกินไป แม้ว่าเราจะไม่สามารถคำนวณความลาดชันได้อย่างแม่นยำทางคณิตศาสตร์ แต่เราสามารถประมาณค่ามันได้ และคุณจะเห็นได้ว่าแนวทางนี้ยังทำงานได้ดีในการพาเราไปยังทิศทางที่ถูกต้องโดยทั่วไป

วิธีการนี้ดีเยี่ยมจริงๆ โดยเฉพาะเมื่อเราทำงานกับฟังก์ชันที่มีหลายพารามิเตอร์ ไม่ใช่แค่ y ขึ้นอยู่กับ x แต่อาจจะเป็น y ขึ้นอยู่กับ a, b, c, d, e และ f คุณคงยังจำได้ว่าฟังก์ชันเอาต์พุต และฟังก์ชันความผิดพลาดของเครือข่ายประสาทเทียมขึ้นอยู่กับพารามิเตอร์น้ำหนักหลายต่อหลายตัว บ่อยครั้งก็หลายร้อยตัวเลยทีเดียว วิธีนี้จึงเหมาะกับเครือข่ายประสาทเทียมมาก

รูปต่อไปนี้แสดงการไต่ระดับความชันอีกครั้ง แต่คราวนี้ใช้ฟังก์ชันที่ซับซ้อนกว่าเล็กน้อย ซึ่งขึ้นอยู่กับพารามิเตอร์ 2 ตัว ฟังก์ชันนี้สามารถแสดงใน 3 มิติ โดยความสูงแทนค่าของฟังก์ชัน

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

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

รูปต่อไปนี้แสดงการไต่ระดับความชันสามครั้งที่แตกต่างกัน โดยมีครั้งหนึ่งติดอยู่ในหุบเขาที่ไม่ใช่

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

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

มีบางอย่างที่ต้องระวังตรงนี้ ดูตารางต่อไปนี้ที่มีค่าการฝึกฝนและค่าจริงสำหรับโหนดเอาต์พุตสามตัว พร้อมกับตัวเลือกสำหรับฟังก์ชันความผิดพลาด

ตัวเลือกแรกสำหรับฟังก์ชันความผิดพลาดคือ (ค่าเป้าหมาย — ค่าจริง) ดูเหมือนจะสมเหตุสมผลใช่มั้ยล่ะ? ถ้าคุณดูผลรวมของโหนดต่างๆ เพื่อดูภาพรวมว่าเครือข่ายได้รับการฝึกฝนได้ดีแค่ไหน คุณจะเห็นว่าผลรวมเป็นศูนย์!

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

ลองแก้ไขปัญหาด้วยการหาค่าสัมบูรณ์ (absolute value) ของความแตกต่างก่อนการบวก นั่นหมายถึงการไม่สนใจเครื่องหมายบวกลบ และเขียนแทนด้วย |ค่าเป้าหมาย — ค่าจริง| วิธีนี้อาจใช้ได้ เพราะไม่มีค่าใดหักล้างกันได้ สาเหตุที่วิธีนี้ไม่เป็นที่นิยมก็เพราะว่าความชันของฟังก์ชันไม่ต่อเนื่องใกล้จุดต่ำสุด และนั่นทำให้การไต่ระดับความชันทำงานได้ไม่ดีนัก เพราะอาจเกิดการกระเด้งไปมาในหุบเขารูปตัว V ที่ฟังก์ชันความผิดพลาดนี้มี ความชันจะไม่เล็กลงใกล้จุดต่ำสุด ดังนั้นการทำงานจึงไม่สิ้นสุด นั่นหมายความว่าอาจเกิดการกระเด้งไปมาในหุบเขารูปตัว V

ตัวเลือกที่สามคือการยกกำลังสองของความแตกต่าง (ค่าเป้าหมาย — ค่าจริง) ^ 2 เรามีเหตุผลหลายประการที่ชอบตัวเลือกนี้มากกว่าตัวเลือกที่สอง ดังนี้:

1. พีชคณิตที่ใช้สำหรับการคำนวณความชันสำหรับการไต่ระดับความชันนั้นทำได้ง่ายพอสมควรเมื่อใช้ฟังก์ชันความผิดพลาดแบบยกกำลังสองนี้

2. ฟังก์ชันความผิดพลาดมีความราบรื่นและต่อเนื่อง ทำให้การไต่ระดับความชันทำงานได้ดีโดยไม่มีช่องว่างหรือจุดกระโดด

3. ความชันจะเล็กลงเมื่อเข้าใกล้จุดต่ำสุด ซึ่งหมายความว่าความเสี่ยงที่จะพลาดเป้าหมายจะลดลงหากเราใช้ความชันนี้เพื่อปรับขนาดก้าวให้เหมาะสม

ใช่ ยังมีตัวเลือกอื่นอีกมากมายนอกเหนือจากสามตัวเลือกที่ผ่านมา คุณสามารถสร้าง cost function ที่ซับซ้อนและน่าสนใจได้มากมาย บางตัวใช้ไม่ได้ผลเลย บางตัวใช้ได้ดีกับปัญหาเฉพาะบางประเภท และบางตัวก็ใช้ได้ดีแต่ไม่คุ้มกับความซับซ้อนเพิ่มเติม

ถูกต้องเลย! ตอนนี้เราใกล้ถึงเส้นชัยแล้ว

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

มาเริ่มด้วยภาพ เพราะจะช่วยให้เราจดจ่อกับสิ่งที่เรากำลังพยายามบรรลุอยู่เสมอ

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

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

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

มาเขียนสิ่งที่เราต้องการในเชิงคณิตศาสตร์กันเถอะ

สมการข้างต้น มีความหมายว่า ค่าความผิดพลาด E เปลี่ยนแปลงอย่างไร เมื่อค่าน้ำหนัก w_jk เปลี่ยนแปลง? ถ้าค่านี้น้อยลง นั่นคือความชันของฟังก์ชันความผิดพลาดที่เราต้องการกำลังเดินลงไปหาค่าต่ำสุด

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

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

ก่อนอื่น ให้เราขยายฟังก์ชันความผิดพลาดนั้น ซึ่งก็คือผลรวมของความแตกต่างระหว่างค่าเป้าหมายและค่าจริงยกกำลังสอง และผลรวมนั้นครอบคลุมโหนดเอาต์พุตทั้งหมด n โหนด

ทั้งหมดที่เราทำตรงนี้คือการเขียนว่าฟังก์ชันความผิดพลาด E คืออะไร

จริงๆ เราสามารถทำให้มันง่ายขึ้นได้ สังเกตว่าเอาต์พุตที่โหนด n ซึ่งก็คือ o_n นั้นขึ้นอยู่กับลิงก์ที่เชื่อมต่อกับมันเท่านั้น นั่นหมายความว่าสำหรับโหนด k เอาต์พุต o_k จะขึ้นอยู่กับน้ำหนัก w_jk เท่านั้น เนื่องจากน้ำหนักเหล่านั้นเป็นน้ำหนักสำหรับลิงก์ที่เข้าสู่โหนด k

อีกวิธีหนึ่งในการมองสิ่งนี้ก็คือ เอาต์พุตของโหนด k ไม่ได้ขึ้นอยู่กับน้ำหนัก w_jb โดยที่ b ไม่เท่ากับ k เนื่องจากไม่มีลิงก์เชื่อมต่อกัน น้ำหนัก w_jb นั้นมีไว้สำหรับลิงก์ที่เชื่อมต่อกับโหนดเอาต์พุต b ไม่ใช่โหนด k

นั่นหมายความว่าเราสามารถลบ o_n ทั้งหมดออกจากผลรวมนั้น ยกเว้น o_k ซึ่งเป็นโหนดที่น้ำหนัก w_jk เชื่อมต่อ นี่ลบผลรวมยุ่งยากๆ นั้นออกไปหมดเลย! เป็นเทคนิคเด็ดที่ควรเก็บไว้ใช้

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

ดังนั้น เราสามารถเขียนสมการให้ง่ายขึ้นเป็นแบบนี้

โอ้ เราเริ่มคุ้นเคยกับแคลคูลัสกันบ้างแล้ว

ให้สังเกตุว่าส่วน t_k นั้นเป็นค่าคงที่ จึงไม่เปลี่ยนแปลงเมื่อ w_jk เปลี่ยนแปลง นั่นคือ t_k ไม่ใช่ฟังก์ชันของ w_jk ถ้าคุณลองคิดดู มันคงจะแปลกมากถ้าตัวอย่างความจริงที่ระบุค่าเป้าหมายนั้นเปลี่ยนแปลงไปขึ้นอยู่กับน้ำหนัก! นั่นเหลือส่วน o_k ซึ่งเรารู้ว่าขึ้นอยู่กับ w_jk เพราะน้ำหนักถูกใช้เพื่อส่งต่อสัญญาณไปข้างหน้าเพื่อกลายเป็นเอาต์พุต o_k

เราจะใช้ chain rule เพื่อแบ่งแยกงานหาอนุพันธ์นี้ออกเป็นชิ้นที่จัดการได้ง่ายขึ้น

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

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

o_j นั้นเป็นเอาต์พุตจากโหนดชั้นซ่อนก่อนหน้า ไม่ใช่เอาต์พุตจากชั้นสุดท้าย o_k เราจะหาอนุพันธ์ของฟังก์ชันซิกมอยด์ได้อย่างไร? เราสามารถทำแบบยากๆ โดยใช้แนวคิดพื้นฐาน แต่คนอื่นได้ทำงานนี้ไปแล้ว เราสามารถใช้คำตอบที่รู้จักกันดีได้ เช่นเดียวกับนักคณิตศาสตร์ทั่วโลกทำทุกวัน

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

ส่วนสุดท้ายเพิ่มเติมนั้นคืออะไร? มันคือ chain rule ที่ใช้กับอนุพันธ์ของซิกมอยด์อีกครั้ง เพราะนิพจน์ภายในฟังก์ชัน sigmoid() นั้นก็ต้องหาอนุพันธ์เทียบกับ w_jk ด้วยเช่นกัน ซึ่งนั่นก็ง่ายและคำตอบก็คือ o_j นั่นเอง

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

นี่คือคำตอบสุดท้ายที่เรากำลังมุ่งไปสู่ คำตอบที่อธิบายความชันของฟังก์ชันความผิดพลาด เพื่อให้เราปรับน้ำหนัก w_jk ได้

ฮิ้ว! ในที่สุดเราก็ได้มาแล้ว

นั่นเป็นนิพจน์มหัศจรรย์ที่เราตามหาอยู่ กุญแจสู่การฝึกอบรมเครือข่ายประสาทเทียม

มันคุ้มค่าที่จะดูอีกครั้ง และการเน้นสีช่วยให้เห็นแต่ละส่วนชัดเจนขึ้น ส่วนแรกเป็นเพียงข้อผิดพลาด (ค่าเป้าหมาย — ค่าจริง) ที่เรารู้กันดี ส่วนผลรวมที่อยู่ภายในซิกมอยด์นั้นเป็นเพียงสัญญาณที่เข้าสู่โหนดชั้นสุดท้าย เราอาจเรียกมันว่า i_k เพื่อให้ดูง่ายขึ้น มันเป็นเพียงสัญญาณที่เข้าสู่โหนดก่อนที่จะใช้ฟังก์ชันกระตุ้น

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

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

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

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

  • ส่วนแรกที่เคยเป็นข้อผิดพลาด (เป้าหมาย — จริง) เปลี่ยนเป็นข้อผิดพลาดที่รวมกลับกันออกมาจากโหนดซ่อน เช่นเดียวกับที่เราเห็นข้างต้น ให้เรียกมันว่า e_j
  • ส่วนซิกมอยด์สามารถคงเหมือนเดิมได้ แต่นิพจน์ผลรวมภายในอ้างอิงถึงชั้นก่อนหน้า ดังนั้นผลรวมจะรวมอินพุตทั้งหมดที่ควบคุมโดยน้ำหนักเข้าสู่โหนดซ่อน j เราสามารถเรียกสิ่งนี้ว่า i_j
  • ส่วนสุดท้ายคือเอาต์พุตของชั้นแรกของโหนด o_i ซึ่งก็คือสัญญาณอินพุต

วิธีเจ๋งๆ นี้ช่วยในการหลีกเลี่ยงงานหนักมากมาย คือการใช้ประโยชน์จากความสมมาตรของปัญหาเพื่อสร้างนิพจน์ใหม่ มันง่ายแต่เป็นเทคนิคที่มีประสิทธิภาพมาก ใช้โดยนักคณิตศาสตร์และนักวิทยาศาสตร์ระดับหัวกะทิ คุณสามารถสร้างความประทับใจให้เพื่อนของคุณด้วยวิธีนี้ได้แน่นอน!

ดังนั้น ส่วนที่สองของคำตอบสุดท้ายที่เราพยายามมาตลอดคือดังต่อไปนี้ ความชันของฟังก์ชันความผิดพลาดสำหรับน้ำหนักระหว่างชั้นอินพุตและชั้นซ่อน

ตอนนี้เรามีนิพจน์มหัศจรรย์ที่สำคัญทั้งหมดสำหรับความชันแล้ว เราสามารถใช้พวกมันเพื่ออัปเดตน้ำหนักหลังตัวอย่างการฝึกแต่ละตัวอย่างได้

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

น้ำหนักที่อัปเดต w_jk คือน้ำหนักเดิมที่ปรับด้วยค่าลบของความชันของข้อผิดพลาดที่เราเพิ่งคำนวณ มันเป็นค่าลบเพราะเราต้องการเพิ่มน้ำหนักถ้ามีความชันบวก และลดลงถ้ามีความชันลบ ตามที่เราเห็นก่อนหน้านี้ สัญลักษณ์ alpha ᵬ, เป็นตัวคูณที่ควบคุมความแรงของการเปลี่ยนแปลงเหล่านี้เพื่อให้แน่ใจว่าเราไม่ overshoot มันมักถูกเรียกว่าอัตราการเรียนรู้

นิพจน์นี้ใช้กับน้ำหนักระหว่างชั้นอินพุตและชั้นซ่อนด้วยเช่นกัน ไม่เฉพาะกับน้ำหนักระหว่างชั้นซ่อนและชั้นเอาต์พุต ความแตกต่างคือความชันของข้อผิดพลาด ซึ่งเรามีนิพจน์สองนิพจน์ข้างต้น

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

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

เมทริกซ์การเปลี่ยนแปลงน้ำหนักประกอบด้วยค่าที่จะปรับน้ำหนัก w_j,k ที่เชื่อมโยงโหนด j ในชั้นหนึ่งกับโหนด k ในชั้นถัดไป คุณจะเห็นได้ว่าส่วนแรกของนิพจน์ใช้ค่าจากชั้นถัดไป (โหนด k) และส่วนสุดท้ายใช้ค่าจากชั้นก่อนหน้า (โหนด j)

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

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

ก็เป็นอันว่างานเสร็จเรียบร้อย

Weight Update Worked Example

มาลองทำตัวอย่างสองสามตัวอย่างพร้อมตัวเลขกัน เพื่อดูวิธีการอัปเดตค่าน้ำหนัก

เครือข่ายในรูปด้านล่างเป็นเครือข่ายที่เราเคยใช้ก่อนหน้านี้ แต่คราวนี้ได้เพิ่มค่าเอาต์พุต ตัวอย่างจาก hidden node แรก o_j=1 และ hidden node ที่สอง o_j=2 ตัวเลขเหล่านี้เป็นเพียงตัวเลขที่สร้างขึ้นเพื่อแสดงวิธีการนี้เท่านั้นและไม่ได้คำนวณอย่างถูกต้องโดยการป้อนสัญญาณไปข้างหน้าจากชั้นอินพุต

เราต้องการอัปเดตน้ำหนัก w_11 ระหว่างชั้นซ่อนกับชั้นเอาต์พุต ซึ่งปัจจุบันมีค่า 2.0

มาเขียน error slope อีกครั้ง

มาทำทีละขั้นตอน

  • ส่วนแรก (t_k — o_k) คือข้อผิดพลาด e_1 = 1.5 เหมือนกับที่เราเห็นก่อนหน้านี้
  • ผลรวมภายในฟังก์ชันซิกมอยด์ Σ_j w_jk . o_j คือ (2.0 * 0.4) + (4.0 * 0.5) = 2.8
  • ซิกมอยด์ 1/(1 + e^(-2.8)) เป็น 0.943 จากนั้นนิพจน์ตรงกลางคือ 0.943 * (1–0.943) = 0.054
  • ส่วนสุดท้ายคือเพียงแค่ o_j ซึ่งเป็น o_j=1 เพราะว่าเราสนใจน้ำหนัก w_11 โดยที่ j = 1 ในที่นี้ก็คือ 0.4 นั่นเอง

เมื่อคูณทั้งสามส่วนเข้าด้วยกัน และอย่าลืมเครื่องหมายลบที่จุดเริ่มต้น จะได้ 0.06048

หากเรามีอัตราการเรียนรู้ 0.1 จะได้การเปลี่ยนแปลงเท่ากับ (0.1 * 0.06048) = +0.006 ดังนั้น w_11 ใหม่คือ 2.0 เดิม บวก 0.006 = 2.006

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

Preparing Data

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

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

Inputs
ลองดูแผนภาพด้านล่างของ Activation Function ซิกมอยด์ คุณจะเห็นได้ว่าหากอินพุตมีค่ามาก ฟังก์ชันจะเปลี่ยนแปลงน้อยลงเรื่อยๆ และมีค่าลู่เข้าหา 1 (แบนลงเรื่อยๆ)

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

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

ข้อแนะนำคือให้ปรับสเกลอินพุตให้อยู่ในช่วง 0.0 ถึง 1.0 บางคนจะเพิ่มออฟเซ็ตเล็กน้อยให้กับอินพุต เช่น เริ่มจาก 0.01 เพื่อหลีกเลี่ยงการมีอินพุตเป็นศูนย์ซึ่งอาจสร้างปัญหาได้ เนื่องจากจะทำให้ความสามารถในการเรียนรู้หายไปโดยการตั้งค่า o_j = 0 ซึ่งจะทำให้นิพจน์การอัพเดตน้ำหนักกลายเป็นศูนย์

Outputs

เอาต์พุตของโครงข่ายประสาทเทียม คือสัญญาณที่ออกมาจากชั้นโหนดสุดท้าย ถ้าเราใช้ Activation Function ที่ไม่สามารถให้ค่าสูงกว่า 1.0 การตั้งค่าเป้าหมายการฝึกอบรมให้มีค่าสูงกว่านี้ก็จะไม่สมเหตุสมผล พึงระลึกว่า logistic function นั้นไม่ถึง 1.0 ด้วยซ้ำ เพียงแต่เข้าใกล้ค่านี้มากขึ้นเรื่อยๆ ซึ่งนักคณิตศาสตร์เรียกว่าการลู่เข้าแบบ asymptotic ไปยัง 1.0

แผนภาพต่อไปนี้แสดงให้เห็นชัดเจนว่า ค่าเอาต์พุตที่มากกว่า 1.0 และต่ำกว่าศูนย์นั้นเป็นไปไม่ได้จากฟังก์ชันการกระตุ้นโลจิสติกส์

หากเรากำหนดค่าเป้าหมายอยู่ในช่วงที่ไม่สามารถทำได้ การฝึกอบรมโครงข่ายจะทำให้น้ำหนักเพิ่มขึ้นเรื่อยๆ เพื่อพยายามสร้างเอาต์พุตที่ใหญ่ขึ้นเรื่อยๆ ซึ่งในทางปฏิบัติแล้วไม่สามารถสร้างได้ด้วย Activation Function ซึ่งเป็นสิ่งที่ไม่ดีเพราะจะทำให้โครงข่ายอิ่มตัว

ดังนั้นเราควรปรับขนาดค่าเป้าหมายของเราให้ตรงกับเอาต์พุตที่เป็นไปได้จากฟังก์ชันการกระตุ้น โดยระมัดระวังไม่ให้ใช้ค่าที่ไม่เคยถึงจริงๆ

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

Random Initial Weights
การพิจารณาแบบเดียวกับอินพุตและเอาต์พุต เราควรหลีกเลี่ยงค่าน้ำหนักเบื้องต้นที่ใหญ่ เพราะมันก่อให้เกิดสัญญาณขนาดใหญ่ที่ไหลเข้าสู่ Activation Function นำไปสู่ภาวะอิ่มตัวที่เราเพิ่งพูดถึง และลดความสามารถในการเรียนรู้ของน้ำหนักที่ดี

เราสามารถเลือกน้ำหนักเบื้องต้นแบบสุ่มและสม่ำเสมอจากช่วง -1.0 ถึง +1.0 นั่นจะเป็นแนวคิดที่ดีกว่ามาก การใช้ช่วงที่กว้างมาก เช่น 1000 ถึง +1000

เราทำได้ดีกว่านี้ไหม? น่าจะเป็นไปได้

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

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

กฎเกณฑ์เบื้องต้นที่นักคณิตศาสตร์นำเสนอ คือการสุ่มตัวอย่างน้ำหนักเริ่มต้นจากช่วง ซึ่งประมาณเป็น 1 หารด้วยรากที่สองของจำนวนลิงค์ที่เข้าสู่โหนด ดังนั้น ถ้าโหนดหนึ่งมีลิงค์เข้ามา 3 เส้น น้ำหนักเริ่มต้นควรอยู่ในช่วง 1/(√3) = 0.577 ส่วนถ้าโหนดหนึ่งมีลิงค์เข้ามา 100 เส้น น้ำหนักเริ่มต้นควรอยู่ในช่วง 1/(√100) = 0.1

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

หากคุณคุ้นเคยกับแนวคิดการสุ่มตัวอย่างจากการแจกแจงความน่าจะเป็น กฎเกณฑ์เบื้องต้นนี้จริงๆ แล้วคือการสุ่มตัวอย่างจากการแจกแจงปกติ (Normal Distribution) โดยมีค่าเฉลี่ยเป็นศูนย์ และส่วนเบี่ยงเบนมาตรฐานเท่ากับ 1 หารด้วยรากที่สองของจำนวนลิงค์ที่เข้าสู่โหนด อย่างไรก็ตาม เราไม่ควรกังวลมากเกินไปว่าจะต้องทำให้ถูกต้องแม่นยำเป๊ะๆ เพราะกฎเกณฑ์นี้เป็นแนวทางเบื้องต้นที่ตั้งอยู่บนสมมติฐานหลายอย่าง ซึ่งอาจไม่ถูกต้องเสมอไป เช่น สมมติว่าใช้ฟังก์ชันการกระตุ้นแบบ tanh() หรือสมมติให้การแจกแจงสัญญาณอินพุตเป็นแบบเฉพาะเจาะจง

แผนภูมิต่อไปนี้สรุปแนวทางที่ง่ายและแนวทางที่ซับซ้อนมากขึ้นโดยใช้การแจกแจงปกติ

แต่จะอย่างไรก็ตาม อย่าตั้งค่าน้ำหนักเริ่มต้นให้มีค่าคงที่เท่ากันหมด โดยเฉพาะค่าศูนย์ นั่นจะแย่มาก!

ที่ว่าแย่มากเพราะโหนดแต่ละโหนดในโครงข่ายจะรับค่าสัญญาณเท่ากัน และเอาต์พุต ที่ออกมาจากโหนดเอาต์พุตแต่ละโหนดก็จะเท่ากัน

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

ความสมมาตรนี้ไม่ดีเพราะหากโครงข่ายที่ผ่านการฝึกอบรมอย่างถูกต้องควรมีน้ำหนักที่ไม่เท่ากัน (ซึ่งเป็นไปได้อย่างมากสำหรับปัญหาเกือบทั้งหมด) คุณก็จะไม่มีทางบรรลุถึงจุดนั้นได้

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

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

แต่ตอนนี้เราได้มาถึงจุดสุดท้ายของทฤษฎีแล้ว ในบทความต่อไปเราจะมาทดลองลงมือสร้าง Neural Network โดยใช้ภาษา Python กัน

--

--

Thana Hongsuwan
Thana Hongsuwan

Written by Thana Hongsuwan

Maker สมัครเล่น สนใจเทคโนโลยีด้าน Hardware เช่น Arduino, ESP8266, ESP32, Internet of Things, Raspberry P, Deep Learning

No responses yet