เหตุใดจึงควรกำหนดน้ำหนักของโครงข่ายประสาทเทียมให้เป็นตัวเลขสุ่ม [ปิด]


105

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

แต่ทำไมน้ำหนักเริ่มต้นของโครงข่ายประสาทเทียมจึงเริ่มต้นเป็นตัวเลขสุ่ม

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

จะไม่เริ่มต้นน้ำหนักเป็น 0 เป็นความคิดที่ดีกว่าหรือ? ด้วยวิธีนี้น้ำหนักจะสามารถหาค่า (ไม่ว่าจะเป็นบวกหรือลบ) ได้เร็วขึ้น?

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


8
นี้ดูเหมือนว่าเป็นแบบที่ดีกว่าสำหรับรอการตรวจสอบ
Sycorax

2
ฉันโหวตให้ปิดคำถามนี้เพราะไม่เกี่ยวกับการเขียนโปรแกรมตามที่กำหนดไว้ในศูนย์ช่วยเหลือแต่เกี่ยวกับทฤษฎีและวิธีการ ML ทั่วไป
desertnaut

คำตอบ:


141

การทำลายความสมมาตรเป็นสิ่งสำคัญที่นี่ไม่ใช่เพื่อเหตุผลด้านประสิทธิภาพ ลองนึกภาพ 2 ชั้นแรกของ perceptron (อินพุตและเลเยอร์ที่ซ่อนอยู่):

ป้อนคำอธิบายภาพที่นี่

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

ป้อนคำอธิบายภาพที่นี่

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

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

นี่คือปัญหาหลักเกี่ยวกับความสมมาตรและเหตุผลที่คุณควรเริ่มต้นการชั่งน้ำหนักแบบสุ่ม (หรืออย่างน้อยก็ด้วยค่าที่แตกต่างกัน) โปรดทราบว่าปัญหานี้ส่งผลกระทบต่อสถาปัตยกรรมทั้งหมดที่ใช้การเชื่อมต่อแบบแต่ละรายการ


1
คำอธิบายที่ยอดเยี่ยม แต่ทำไมใช้คำว่าsymmetryไม่correlation? ใครใช้คำว่าใครก่อน?
nn0p

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

@ffriend มากกว่าในกรณีที่เราใช้การออกกลางคันการสุ่มไม่จำเป็นอีกต่อไป ฉันผิดเหรอ?
emanuele

1
@emanuele Dropout เป็นการสุ่มแบบหนึ่งใช่มันควรจะใช้ได้ อย่างไรก็ตามการเชื่อมต่อทั้งหมดที่ไม่ "หลุด" ในการทำซ้ำแต่ละครั้งจะยังคงได้รับการอัปเดตแบบสมมาตรดังนั้นฉันเดาว่าการเรียนรู้จะค่อนข้างช้าดังนั้นจึงแนะนำให้ใช้การเริ่มต้นแบบสุ่มในเครือข่ายที่ใช้งานได้จริง
ffriend

สิ่งนี้อธิบายไปข้างหน้าได้ดี แต่ backprop ล่ะ?
zell

76

การเปรียบเทียบ:

ฉันหวังว่ามันจะเป็นการเปรียบเทียบที่ดี ฉันพยายามอธิบายให้ง่ายที่สุดแล้ว

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

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

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

นี่คือสิ่งที่มีความหมายโดยการทำลายสมมาตร การเริ่มต้นไม่สมมาตร ( ซึ่งแตกต่างกัน ) ดังนั้นคุณสามารถหาวิธีแก้ไขปัญหาเดียวกันได้

ในการเปรียบเทียบนี้ที่คุณที่ดินเป็นน้ำหนัก ดังนั้นด้วยน้ำหนักที่แตกต่างกันจึงมีโอกาสที่จะไปถึงจุดต่ำสุด ( หรือต่ำกว่า ) ได้ดีกว่า

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

ป้อนคำอธิบายภาพที่นี่


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

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

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

26

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

อาร์กิวเมนต์เดียวกันนี้ใช้กับอัลกอริทึมอื่น ๆ ซึ่งไม่สามารถค้นหา global optimum (k-mean, EM ฯลฯ ) และไม่ได้นำไปใช้กับเทคนิค global optimization (เช่น SMO algorithm สำหรับ SVM)


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

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

มีสูตรหรือกฎมาตรฐานในการกำหนดค่าเริ่มต้นน้ำหนักหรือไม่? ฉันมีโครงข่ายประสาทเทียมแบบฟีดไปข้างหน้าหลายชั้นและมีการแพร่กระจายกลับซึ่งใช้ฟังก์ชัน sigmoid
lkkkk

มีกฎง่ายๆในหนังสือ S.Haykin "neural networks"
lejlot

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

4

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


2
  1. จะไม่เริ่มต้นน้ำหนักเป็น 0 เป็นความคิดที่ดีกว่าหรือ? ด้วยวิธีนี้น้ำหนักจะสามารถหาค่า (ไม่ว่าจะเป็นบวกหรือลบ) ได้เร็วขึ้น?

  2. การทำลายสมมาตรทำให้เรียนรู้เร็วขึ้นได้อย่างไร

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

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

การทำให้น้ำหนักไม่เป็นศูนย์ (แต่ใกล้ 0 เช่น 0.1 เป็นต้น) อัลกอริทึมจะเรียนรู้น้ำหนักในการทำซ้ำครั้งต่อไปและจะไม่ติด ด้วยวิธีนี้การทำลายสมมาตรจึงเกิดขึ้น

  1. มีปรัชญาพื้นฐานอื่น ๆ ที่อยู่เบื้องหลังการสุ่มน้ำหนักนอกเหนือจากการหวังว่าค่าเหล่านี้จะอยู่ใกล้ค่าที่เหมาะสมที่สุดเมื่อเริ่มต้นหรือไม่?

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

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

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

โพสต์ 2015 เนื่องจากความก้าวหน้าในการวิจัยการเรียนรู้ของเครื่องHe-et-al Initializatio n จึงถูกนำมาใช้เพื่อแทนที่การเริ่มต้นแบบสุ่ม

w=np.random.randn(layer_size[l],layer_size[l-1])*np.sqrt(2/layer_size[l-1])

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

โดยสรุปแล้วน้ำหนักสุ่มที่ไม่ใช่ศูนย์ช่วยเราได้

  1. ออกมาจาก optima ในพื้นที่
  2. ทำลายสมมาตร
  3. เข้าถึง Optima ทั่วโลกในการทำซ้ำเพิ่มเติม

1

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


1

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

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

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

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

[1]: https://i.stack.imgur.com/2dioT.png [Kalhor, A. (2020). การจำแนกประเภทและการถดถอย NNs บรรยาย.]

ในกรณีที่ง่ายที่สุดน้ำหนักใหม่จะเป็นดังนี้:

W_new = W_old + D_loss

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

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


0

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

dZ2 = A2 - ย

dW2 = (1 / ม.) * dZ2 * A2.T

ละเว้น db2 (ขออภัยไม่เสียใจ;))

dZ1 = W2.T * dZ2. * g1 '(Z1)

...

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


0

ฉันได้เรียนรู้สิ่งหนึ่ง: ถ้าคุณเริ่มต้นน้ำหนักเป็นศูนย์จะเห็นได้ชัดว่าหน่วยกระตุ้นในเลเยอร์เดียวกันจะเหมือนกันนั่นหมายความว่าพวกมันจะมีค่าเท่ากัน เมื่อคุณ backbrop คุณจะพบว่าแถวทั้งหมดของ dW เกรเดียนต์ก็เหมือนกันดังนั้นแถวทั้งหมดของเมทริกซ์น้ำหนัก W จะเท่ากันหลังจากอัปเดตการไล่ระดับสี โดยทั่วไปการกำหนดค่าเริ่มต้นน้ำหนักทั้งหมดให้เป็นศูนย์จะส่งผลให้เครือข่ายไม่สามารถทำลายสมมาตรได้ ซึ่งหมายความว่าเซลล์ประสาททุกเซลล์ในแต่ละชั้นจะเรียนรู้สิ่งเดียวกันและคุณอาจฝึกเครือข่ายประสาทด้วยn[l]=1n[l]=1สำหรับทุกเลเยอร์และเครือข่ายก็ไม่มีประสิทธิภาพมากไปกว่าตัวจำแนกเชิงเส้นเช่นการถดถอยโลจิสติกส์ หลักสูตร Andrew Ng:

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.