AI-For-Beginners/translations/th/lessons/4-ComputerVision/08-TransferLearning/TrainingTricks.md

110 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# เทคนิคการฝึกสอน Deep Learning
เมื่อเครือข่ายประสาทเทียมมีความลึกมากขึ้น การฝึกสอนเครือข่ายเหล่านี้ก็จะยิ่งท้าทายมากขึ้น หนึ่งในปัญหาหลักคือปัญหาที่เรียกว่า [vanishing gradients](https://en.wikipedia.org/wiki/Vanishing_gradient_problem) หรือ [exploding gradients](https://deepai.org/machine-learning-glossary-and-terms/exploding-gradient-problem#:~:text=Exploding%20gradients%20are%20a%20problem,updates%20are%20small%20and%20controlled.) [บทความนี้](https://towardsdatascience.com/the-vanishing-exploding-gradient-problem-in-deep-neural-networks-191358470c11) อธิบายปัญหาเหล่านี้ได้อย่างดี
เพื่อทำให้การฝึกสอนเครือข่ายลึกมีประสิทธิภาพมากขึ้น มีเทคนิคบางอย่างที่สามารถนำมาใช้ได้
## การรักษาค่าต่าง ๆ ให้อยู่ในช่วงที่เหมาะสม
เพื่อให้การคำนวณเชิงตัวเลขมีความเสถียรมากขึ้น เราต้องการให้ค่าทั้งหมดในเครือข่ายประสาทเทียมของเราอยู่ในช่วงที่เหมาะสม โดยทั่วไปคือ [-1..1] หรือ [0..1] แม้ว่าจะไม่ใช่ข้อกำหนดที่เข้มงวดมากนัก แต่ธรรมชาติของการคำนวณแบบ floating point คือค่าที่มีขนาดต่างกันมากไม่สามารถจัดการได้อย่างแม่นยำ ตัวอย่างเช่น หากเราบวก 10<sup>-10</sup> กับ 10<sup>10</sup> เรามักจะได้ 10<sup>10</sup> เพราะค่าที่เล็กกว่าจะถูก "แปลง" ให้มีลำดับเดียวกับค่าที่ใหญ่กว่า และ mantissa จะสูญหายไป
ฟังก์ชันการกระตุ้นส่วนใหญ่มีความไม่เชิงเส้นในช่วง [-1..1] ดังนั้นจึงสมเหตุสมผลที่จะปรับขนาดข้อมูลอินพุตทั้งหมดให้อยู่ในช่วง [-1..1] หรือ [0..1]
## การกำหนดค่าเริ่มต้นของน้ำหนัก
ในอุดมคติ เราต้องการให้ค่าต่าง ๆ อยู่ในช่วงเดียวกันหลังจากผ่านเลเยอร์ของเครือข่าย ดังนั้นการกำหนดค่าน้ำหนักเริ่มต้นในลักษณะที่รักษาการกระจายของค่าไว้จึงเป็นสิ่งสำคัญ
การแจกแจงแบบปกติ **N(0,1)** ไม่ใช่ตัวเลือกที่ดี เพราะถ้าเรามีอินพุต *n* ค่าเบี่ยงเบนมาตรฐานของผลลัพธ์จะเป็น *n* และค่ามีแนวโน้มที่จะหลุดออกจากช่วง [0..1]
การกำหนดค่าเริ่มต้นที่มักใช้ ได้แก่:
* การแจกแจงแบบสม่ำเสมอ -- `uniform`
* **N(0,1/n)** -- `gaussian`
* **N(0,1/√n_in)** รับประกันว่าอินพุตที่มีค่าเฉลี่ยเป็นศูนย์และค่าเบี่ยงเบนมาตรฐานเป็น 1 จะยังคงมีค่าเฉลี่ย/ค่าเบี่ยงเบนมาตรฐานเดิม
* **N(0,√2/(n_in+n_out))** -- ที่เรียกว่า **Xavier initialization** (`glorot`) ซึ่งช่วยให้สัญญาณอยู่ในช่วงระหว่างการส่งต่อและการส่งย้อนกลับ
## Batch Normalization
แม้จะมีการกำหนดค่าน้ำหนักเริ่มต้นที่เหมาะสม น้ำหนักก็ยังสามารถมีค่าที่ใหญ่หรือเล็กเกินไปในระหว่างการฝึกสอน ซึ่งจะทำให้สัญญาณหลุดออกจากช่วงที่เหมาะสม เราสามารถนำสัญญาณกลับมาอยู่ในช่วงที่เหมาะสมได้โดยใช้เทคนิค **normalization** หนึ่งในหลาย ๆ เทคนิค แม้ว่าจะมีหลายวิธี (เช่น Weight normalization, Layer Normalization) แต่ที่ใช้บ่อยที่สุดคือ Batch Normalization
แนวคิดของ **batch normalization** คือการพิจารณาค่าทั้งหมดใน minibatch และทำ normalization (เช่น ลบค่าเฉลี่ยและหารด้วยค่าเบี่ยงเบนมาตรฐาน) ตามค่าดังกล่าว โดยจะถูกนำมาใช้เป็นเลเยอร์ในเครือข่ายที่ทำ normalization หลังจากการใช้น้ำหนัก แต่ก่อนฟังก์ชันการกระตุ้น ผลลัพธ์คือเรามักจะได้ความแม่นยำที่สูงขึ้นและการฝึกสอนที่เร็วขึ้น
นี่คือ [งานวิจัยต้นฉบับ](https://arxiv.org/pdf/1502.03167.pdf) เกี่ยวกับ batch normalization, [คำอธิบายใน Wikipedia](https://en.wikipedia.org/wiki/Batch_normalization) และ [บทความแนะนำที่ดี](https://towardsdatascience.com/batch-normalization-in-3-levels-of-understanding-14c2da90a338) (และอีกบทความ [ในภาษารัสเซีย](https://habrahabr.ru/post/309302/))
## Dropout
**Dropout** เป็นเทคนิคที่น่าสนใจที่ลบเซลล์ประสาทบางส่วนแบบสุ่มในระหว่างการฝึกสอน โดยจะถูกนำมาใช้เป็นเลเยอร์ที่มีพารามิเตอร์หนึ่งตัว (เปอร์เซ็นต์ของเซลล์ประสาทที่จะลบออก โดยทั่วไปคือ 10%-50%) และในระหว่างการฝึกสอนจะทำให้ค่าขององค์ประกอบบางส่วนในเวกเตอร์อินพุตเป็นศูนย์แบบสุ่มก่อนที่จะส่งไปยังเลเยอร์ถัดไป
แม้ว่าจะฟังดูเป็นแนวคิดที่แปลก แต่คุณสามารถเห็นผลของ dropout ในการฝึกสอนตัวจำแนกตัวเลข MNIST ในโน้ตบุ๊ก [`Dropout.ipynb`](Dropout.ipynb) มันช่วยเร่งการฝึกสอนและช่วยให้เราบรรลุความแม่นยำที่สูงขึ้นในจำนวน epoch ที่น้อยลง
ผลกระทบนี้สามารถอธิบายได้หลายวิธี:
* มันสามารถถูกมองว่าเป็นปัจจัยสุ่มที่ทำให้โมเดลหลุดออกจาก local minimum
* มันสามารถถูกมองว่าเป็น *implicit model averaging* เพราะในระหว่าง dropout เรากำลังฝึกโมเดลที่แตกต่างกันเล็กน้อย
> *บางคนกล่าวว่าเมื่อคนเมาพยายามเรียนรู้อะไรบางอย่าง เขาจะจำสิ่งนั้นได้ดีขึ้นในเช้าวันรุ่งขึ้นเมื่อเทียบกับคนที่มีสติ เพราะสมองที่มีเซลล์ประสาทบางส่วนทำงานผิดปกติพยายามปรับตัวเพื่อเข้าใจความหมาย เราไม่เคยทดสอบว่าจริงหรือไม่*
## การป้องกัน Overfitting
หนึ่งในแง่มุมที่สำคัญมากของ deep learning คือการป้องกัน [overfitting](../../3-NeuralNetworks/05-Frameworks/Overfitting.md) แม้ว่าจะน่าดึงดูดใจที่จะใช้โมเดลเครือข่ายประสาทเทียมที่ทรงพลังมาก แต่เราควรปรับสมดุลจำนวนพารามิเตอร์ของโมเดลกับจำนวนตัวอย่างการฝึกสอนเสมอ
> ตรวจสอบให้แน่ใจว่าคุณเข้าใจแนวคิดของ [overfitting](../../3-NeuralNetworks/05-Frameworks/Overfitting.md) ที่เราได้แนะนำไว้ก่อนหน้านี้!
มีหลายวิธีในการป้องกัน overfitting:
* Early stopping -- ตรวจสอบข้อผิดพลาดในชุด validation อย่างต่อเนื่องและหยุดการฝึกสอนเมื่อข้อผิดพลาดใน validation เริ่มเพิ่มขึ้น
* Explicit Weight Decay / Regularization -- เพิ่มค่าปรับในฟังก์ชัน loss สำหรับค่าน้ำหนักที่มีค่าสูง ซึ่งช่วยป้องกันโมเดลจากการให้ผลลัพธ์ที่ไม่เสถียร
* Model Averaging -- ฝึกสอนโมเดลหลายตัวแล้วเฉลี่ยผลลัพธ์ ซึ่งช่วยลดความแปรปรวน
* Dropout (Implicit Model Averaging)
## ตัวปรับแต่ง / อัลกอริทึมการฝึกสอน
อีกแง่มุมที่สำคัญของการฝึกสอนคือการเลือกอัลกอริทึมการฝึกสอนที่ดี แม้ว่า **gradient descent** แบบคลาสสิกจะเป็นตัวเลือกที่สมเหตุสมผล แต่บางครั้งอาจช้าเกินไปหรือทำให้เกิดปัญหาอื่น ๆ
ใน deep learning เราใช้ **Stochastic Gradient Descent** (SGD) ซึ่งเป็น gradient descent ที่ใช้กับ minibatches ที่สุ่มเลือกจากชุดการฝึกสอน น้ำหนักจะถูกปรับโดยใช้สูตรนี้:
w<sup>t+1</sup> = w<sup>t</sup> - η∇ℒ
### Momentum
ใน **momentum SGD** เราจะเก็บส่วนหนึ่งของ gradient จากขั้นตอนก่อนหน้าไว้ มันคล้ายกับเมื่อเรากำลังเคลื่อนที่ไปในทิศทางหนึ่งด้วยแรงเฉื่อย และเราได้รับแรงกระแทกในทิศทางที่ต่างออกไป เส้นทางของเราไม่ได้เปลี่ยนทันที แต่ยังคงมีส่วนหนึ่งของการเคลื่อนที่เดิมอยู่ ที่นี่เราแนะนำเวกเตอร์ v เพื่อแสดงถึง *ความเร็ว*:
* v<sup>t+1</sup> = γ v<sup>t</sup> - η∇ℒ
* w<sup>t+1</sup> = w<sup>t</sup>+v<sup>t+1</sup>
พารามิเตอร์ γ แสดงถึงขอบเขตที่เราคำนึงถึงแรงเฉื่อย: γ=0 สอดคล้องกับ SGD แบบคลาสสิก; γ=1 เป็นสมการการเคลื่อนที่ล้วน ๆ
### Adam, Adagrad, ฯลฯ
เนื่องจากในแต่ละเลเยอร์เราคูณสัญญาณด้วยเมทริกซ์ W<sub>i</sub> ขึ้นอยู่กับ ||W<sub>i</sub>|| gradient อาจลดลงจนใกล้ 0 หรือเพิ่มขึ้นอย่างไม่จำกัด นี่คือแก่นของปัญหา Exploding/Vanishing Gradients
หนึ่งในวิธีแก้ปัญหานี้คือการใช้เฉพาะทิศทางของ gradient ในสมการ และละเว้นค่าขนาดสัมบูรณ์ เช่น
w<sup>t+1</sup> = w<sup>t</sup> - η(∇ℒ/||∇ℒ||), โดย ||∇ℒ|| = √∑(∇ℒ)<sup>2</sup>
อัลกอริทึมนี้เรียกว่า **Adagrad** อัลกอริทึมอื่น ๆ ที่ใช้แนวคิดเดียวกัน: **RMSProp**, **Adam**
> **Adam** ถือว่าเป็นอัลกอริทึมที่มีประสิทธิภาพมากสำหรับหลาย ๆ การใช้งาน ดังนั้นหากคุณไม่แน่ใจว่าจะใช้อันไหน - ใช้ Adam
### Gradient clipping
Gradient clipping เป็นการขยายแนวคิดข้างต้น เมื่อ ||∇ℒ|| ≤ θ เราจะพิจารณา gradient ดั้งเดิมในการปรับน้ำหนัก และเมื่อ ||∇ℒ|| > θ - เราจะแบ่ง gradient ด้วย norm ของมัน ที่นี่ θ เป็นพารามิเตอร์ ในกรณีส่วนใหญ่เราสามารถใช้ θ=1 หรือ θ=10
### Learning rate decay
ความสำเร็จของการฝึกสอนมักขึ้นอยู่กับพารามิเตอร์ learning rate η เป็นเรื่องที่สมเหตุสมผลที่จะสมมติว่าค่า η ที่ใหญ่ขึ้นส่งผลให้การฝึกสอนเร็วขึ้น ซึ่งเป็นสิ่งที่เราต้องการในช่วงเริ่มต้นของการฝึกสอน และจากนั้นค่า η ที่เล็กลงช่วยให้เราปรับแต่งเครือข่ายได้ดีขึ้น ดังนั้นในกรณีส่วนใหญ่เราต้องการลดค่า η ในกระบวนการฝึกสอน
สิ่งนี้สามารถทำได้โดยการคูณค่า η ด้วยตัวเลขบางตัว (เช่น 0.98) หลังจากแต่ละ epoch ของการฝึกสอน หรือโดยใช้ **learning rate schedule** ที่ซับซ้อนกว่า
## สถาปัตยกรรมเครือข่ายที่แตกต่างกัน
การเลือกสถาปัตยกรรมเครือข่ายที่เหมาะสมสำหรับปัญหาของคุณอาจเป็นเรื่องยาก โดยปกติเราจะเลือกสถาปัตยกรรมที่พิสูจน์แล้วว่าใช้ได้ผลสำหรับงานเฉพาะของเรา (หรืองานที่คล้ายกัน) นี่คือ [ภาพรวมที่ดี](https://www.topbots.com/a-brief-history-of-neural-network-architectures/) ของสถาปัตยกรรมเครือข่ายประสาทเทียมสำหรับการมองเห็นด้วยคอมพิวเตอร์
> สิ่งสำคัญคือต้องเลือกสถาปัตยกรรมที่ทรงพลังเพียงพอสำหรับจำนวนตัวอย่างการฝึกสอนที่เรามี การเลือกโมเดลที่ทรงพลังเกินไปอาจทำให้เกิด [overfitting](../../3-NeuralNetworks/05-Frameworks/Overfitting.md)
อีกวิธีที่ดีคือการใช้สถาปัตยกรรมที่ปรับตัวเองให้เหมาะสมกับความซับซ้อนที่ต้องการได้ ในระดับหนึ่ง สถาปัตยกรรม **ResNet** และ **Inception** มีความสามารถในการปรับตัวเอง [ข้อมูลเพิ่มเติมเกี่ยวกับสถาปัตยกรรมการมองเห็นด้วยคอมพิวเตอร์](../07-ConvNets/CNN_Architectures.md)
---
**ข้อจำกัดความรับผิดชอบ**:
เอกสารนี้ได้รับการแปลโดยใช้บริการแปลภาษา AI [Co-op Translator](https://github.com/Azure/co-op-translator) แม้ว่าเราจะพยายามให้การแปลมีความถูกต้อง แต่โปรดทราบว่าการแปลอัตโนมัติอาจมีข้อผิดพลาดหรือความไม่แม่นยำ เอกสารต้นฉบับในภาษาต้นทางควรถือเป็นแหล่งข้อมูลที่เชื่อถือได้ สำหรับข้อมูลที่สำคัญ ขอแนะนำให้ใช้บริการแปลภาษามนุษย์มืออาชีพ เราจะไม่รับผิดชอบต่อความเข้าใจผิดหรือการตีความที่ผิดพลาดซึ่งเกิดจากการใช้การแปลนี้