การเข้ารหัสข้อมูลมุมสำหรับโครงข่ายประสาทเทียม


20

ฉันกำลังฝึกอบรมโครงข่ายประสาทเทียม (รายละเอียดไม่สำคัญ) โดยที่ข้อมูลเป้าหมายเป็นเวกเตอร์ของมุม (ระหว่าง 0 ถึง 2 * pi) ฉันกำลังมองหาคำแนะนำเกี่ยวกับวิธีการเข้ารหัสข้อมูลนี้ นี่คือสิ่งที่ฉันกำลังพยายาม (ด้วยความสำเร็จที่ จำกัด ):

1) การเข้ารหัส 1-of-C: ฉันวางมุมที่เป็นไปได้ในการตั้งค่าไว้ที่ 1,000 มุมหรือแยกกันแล้วระบุมุมที่ต้องการโดยการใส่ 1 ที่ดัชนีที่เกี่ยวข้อง ปัญหาเกี่ยวกับสิ่งนี้คือเครือข่ายเรียนรู้ที่จะเอาท์พุททั้งหมด 0 (เนื่องจากเป็นสิ่งที่ถูกต้องเกือบ)

2) การปรับขนาดง่าย: ฉันปรับขนาดช่วงสัญญาณเครือข่าย ([0,1]) ถึง [0,2 * pi] ปัญหาตรงนี้คือมุมโดยธรรมชาติมีลักษณะเป็นวงกลม (เช่น 0.0001 และ 2 * pi นั้นอยู่ติดกัน) ด้วยการเข้ารหัสชนิดนี้ข้อมูลนั้นจะหายไป

ข้อเสนอแนะใด ๆ ที่จะได้รับการชื่นชม!


1
คุณไม่ควรมีปัญหากับเครือข่ายที่เอาท์พุทศูนย์ทั้งหมดถ้าคุณใช้เลเยอร์เอาท์พุท softmax - ซึ่งคุณควรทำโดยทั่วไปถ้าคุณกำลังใช้เอาต์พุต catagorical (เช่น 1-of-C)
Lyndon White

7
แนวคิดการเข้ารหัสเก็งกำไรอย่างหมดจด (ฉันไม่เคยเห็นมันทำหรือทดสอบ แต่ฉันไม่ได้ดู) คือการเข้ารหัสมุมของคุณ ( θ ) เป็นคู่: θ(sin(θ),cos(θ))theta)) ฉันคิดว่ามันจะเป็นแผนที่แบบต่อเนื่องที่มีค่าทั้งหมดเช่น0และ2πใกล้กัน ฉันคิดว่าฉันอาจสร้างตัวอย่างนี้และทดสอบ
Lyndon White

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

ตอนนี้ฉันไม่ได้ใช้เลเยอร์ softmax และนั่นอาจเป็นปัญหา ฉันจะใช้สิ่งนี้ในวันนี้ถ้าฉันมีโอกาส! แนวคิด (เพราะบาป) ของคุณน่าสนใจมากและฉันชอบโดยเฉพาะอย่างยิ่งที่ทำให้ช่วงนั้นเป็น [-1,1] (ดีถ้าคุณทำงานกับฟังก์ชันเปิดใช้งาน tanh) ฉันหวังว่าจะเห็นผลลัพธ์ของคุณ 1
Ari Herman

การอัปเดตอย่างรวดเร็ว: ฉันพยายามนำเลเยอร์ softmax มาใช้และยังไม่มีโชค ฉันคิดว่าปัญหาคือสำหรับปัญหานี้มันเป็นสิ่งสำคัญที่ "angularity" ของข้อมูลที่จะแสดงอย่างใดในการเข้ารหัส ด้วยการเข้ารหัสหมวดหมู่โทโพโลยีของข้อมูลเป้าหมายจะหายไป ดังนั้นข้อผิดพลาดของ 0.5 * pi และ 0.05 * pi จึงดูเหมือนกันกับเครือข่าย (จะเห็นว่าทั้งสองเป็นประเภทที่ไม่ถูกต้อง)
Ari Herman

คำตอบ:


18

บทนำ

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

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

แต่เป็นต้นไปด้วยคำตอบจริง

วิธี

ฉันเสนอว่ามุมจะแสดงเป็นคู่ค่าไซน์และโคไซน์θ

ดังนั้นฟังก์ชั่นการเข้ารหัสคือ: และฟังก์ชั่นการถอดรหัสคือ:สำหรับarctan2เป็น tangents ผกผัน, รักษาทิศทางในทุกด้านθ(sin(θ),cos(θ))
(y1,y2)arctan2(y1,y2)

ในทางทฤษฎีคุณสามารถทำงานกับมุมได้อย่างเท่าเทียมกันหากเครื่องมือของคุณใช้atan2เป็นฟังก์ชันเลเยอร์ (รับ 2 อินพุตและสร้างเอาต์พุต 1 เอาต์พุต) TensorFlow ทำสิ่งนี้ในขณะนี้และรองรับการไล่ระดับสีลงบนมันแม้ว่าจะไม่ได้มีไว้สำหรับการใช้งานนี้ เราตรวจสอบโดยใช้กับฟังก์ชั่นการสูญเสียout = atan2(sigmoid(ylogit), sigmoid(xlogit)) min((pred - out)^2, (pred - out - 2pi)^2)ผมพบว่ามันได้รับการฝึกฝนไกลยิ่งกว่าการใช้ที่มีฟังก์ชั่นการสูญเสียouts = tanh(ylogit), outc = tanh(xlogit)) 0.5((sin(pred) - outs)^2 + (cos(pred) - outc)^2ซึ่งฉันคิดว่าสามารถนำมาประกอบกับการไล่ระดับสีไม่ต่อเนื่องสำหรับatan2

การทดสอบของฉันที่นี่เรียกใช้เป็นฟังก์ชันการประมวลผลล่วงหน้า

เพื่อประเมินสิ่งนี้ฉันได้กำหนดภารกิจ:

ให้ภาพขาวดำแสดงบรรทัดเดียวบนพื้นหลังเปล่าเอาท์พุทมุมที่บรรทัดนั้นอยู่ที่ "แกน x บวก"

ฉันใช้งานฟังก์ชั่นการสุ่มสร้างภาพเหล่านี้โดยมีเส้นที่มุมสุ่ม (NB: เวอร์ชันก่อนหน้าของโพสต์นี้ใช้ความลาดชันแบบสุ่มแทนที่จะเป็นมุมสุ่มขอบคุณ @Ari Herman สำหรับชี้ให้เห็นตอนนี้แก้ไขแล้ว) ฉันสร้างโครงข่ายประสาทเทียมหลายแห่งเพื่อประเมินประสิทธิภาพของงาน รายละเอียดการใช้งานเต็มรูปแบบอยู่ในสมุดบันทึก Jupyterนี้ รหัสมีอยู่ในJuliaและฉันใช้ประโยชน์จากห้องสมุดเครือข่ายMocha Neural

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

การตั้งค่าการทดลอง

ภาพอยู่ที่พิกเซลโดยมีเส้นกำกับอยู่ตรงกลางและไปที่ขอบ ไม่มีสัญญาณรบกวน ฯลฯ ในภาพมีเพียงเส้น "สีดำ" บนพื้นหลังสีขาว101×101

สำหรับแต่ละเส้นทาง 1,000 การฝึกอบรมและ 1,000 ภาพการทดสอบถูกสร้างขึ้นแบบสุ่ม

เครือข่ายการประเมินผลมีชั้นความกว้างที่ซ่อนอยู่ 500 ชั้นเดียวมีการใช้เซลล์ประสาท Sigmoid ในชั้นที่ซ่อน

ได้รับการฝึกฝนโดย Stochastic Gradient Decent ที่มีอัตราการเรียนรู้คงที่ที่ 0.01 และโมเมนตัมคงที่ที่ 0.9

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

มันง่ายมากที่จะปรับแต่งพารามิเตอร์เหล่านี้ในรหัสทดสอบและฉันแนะนำให้คนทำเช่นนั้น (และมองหาข้อบกพร่องในการทดสอบ)

ผล

ผลลัพธ์ของฉันมีดังนี้:

|                        |  500 bins    |  scaled to 0-1 |  Sin/Cos     |  scaled to 0-1 |  Sin/Cos     |
|                        | 1,000 Iter   | 1,000 Iter     | 1,000 iter   | 10,000 Iter    | 10,000 iter  |
|------------------------|--------------|----------------|--------------|----------------|--------------|
| mean_error             | 0.4711263342 | 0.2225284486   | 2.099914718  | 0.1085846429   | 2.1036656318 |
| std(errors)            | 1.1881991421 | 0.4878383767   | 1.485967909  | 0.2807570442   | 1.4891605068 |
| minimum(errors)        | 1.83E-006    | 1.82E-005      | 9.66E-007    | 1.92E-006      | 5.82E-006    |
| median(errors)         | 0.0512168533 | 0.1291033982   | 1.8440767072 | 0.0562908143   | 1.8491085947 |
| maximum(errors)        | 6.0749693965 | 4.9283551248   | 6.2593307366 | 3.735884823    | 6.2704853962 |
| accurancy              | 0.00%        | 0.00%          | 0.00%        | 0.00%          | 0.00%        |
| accurancy_to_point001  | 2.10%        | 0.30%          | 3.70%        | 0.80%          | 12.80%       |
| accurancy_to_point01   | 21.90%       | 4.20%          | 37.10%       | 8.20%          | 74.60%       |
| accurancy_to_point1    | 59.60%       | 35.90%         | 98.90%       | 72.50%         | 99.90%       |

ที่ฉันอ้างถึงข้อผิดพลาดนี่คือค่าสัมบูรณ์ของความแตกต่างระหว่างเอาท์พุทมุมโดยเครือข่ายประสาทและมุมที่แท้จริง ดังนั้นค่าเฉลี่ยความผิดพลาด (ตัวอย่าง) คือค่าเฉลี่ยของกรณีทดสอบ 1,000 ข้อของความแตกต่างนี้ ฯลฯ ฉันไม่แน่ใจว่าฉันไม่ควรลดขนาดมันด้วยการทำผิดที่บอกว่าเท่ากัน เป็นข้อผิดพลาดของ ) π7π4π4

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

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

การสนทนา

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

การเข้ารหัส sin / cos ทำได้ดีกว่าการเข้ารหัสขนาด 0-1 อย่างมีนัยสำคัญ การปรับปรุงคือเท่าที่ 1,000 การฝึกอบรมซ้ำบาป / cos มีประสิทธิภาพดีขึ้นประมาณ 3 เท่าในตัวชี้วัดส่วนใหญ่กว่าการปรับสเกลอยู่ที่ 10,000 ซ้ำ

ฉันคิดว่าในส่วนนี้เกี่ยวข้องกับการปรับปรุงลักษณะทั่วไปเนื่องจากทั้งคู่ได้รับข้อผิดพลาดกำลังสองเฉลี่ยที่คล้ายกันในชุดการฝึกอบรมอย่างน้อย 10,000 ครั้งที่มีการเรียกใช้ซ้ำ

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

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

ข้อสรุป

ดูเหมือนว่าตัวแทน / บาปนั้นดีที่สุดโดยมีตัวแทนที่ฉันตรวจสอบที่นี่ มันสมเหตุสมผลแล้วที่จะมีค่าที่ราบรื่นเมื่อคุณเคลื่อนที่ไปรอบ ๆ วงกลม ฉันยังชอบที่สามารถผกผันกับarctan2ซึ่งเป็นสง่า

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


นี่คือการตอบสนองที่ละเอียดที่สุดที่ฉันเคยได้รับจากการแลกเปลี่ยนสแต็ค เนื่องจากฉันไม่คุ้นเคยกับ Julia มันเป็นเรื่องยากสำหรับฉันที่จะตรวจสอบรหัสของคุณ ... ดังนั้นดังนั้นฉันจะพยายามจำลองผลลัพธ์ของคุณโดยใช้ Python แทน ฉันจะโพสต์การค้นพบฉันในวันนี้หรือพรุ่งนี้
Ari Herman

ในขณะที่ฉันไม่แปลกใจเลยที่การทำหมันนั้นทำได้ไม่ดี แต่ฉันก็รู้สึกประหลาดใจในระดับที่ (0,1) การปรับขนาดนั้นทำได้ดีกว่าด้วยวิธี (cos, sin) ฉันสังเกตเห็นว่าคุณสร้างตัวอย่างของคุณโดยการสุ่มเลือกการขึ้นและลงของเส้น ฉันคิดว่านี่น่าจะสร้างเส้นที่มีมุมที่ไม่กระจายอย่างสม่ำเสมอ แต่มีความลาดชัน เป็นไปได้ไหมว่านี่เป็นสาเหตุที่วิธีการ (cos, sin) ทำได้ดีกว่ามาก? จะเกิดอะไรขึ้นถ้าคุณทำเป้าหมายให้เป็นสีแทน (มุม) ...
Ari Herman

คุณพูดถูกเกี่ยวกับความชันสุ่มกับมุมที่สุ่ม แต่ฉันไม่คิดว่าการกำหนดเป้าหมายtan(angle)จะไปได้ดีกว่าที่กำหนดไว้ไม่เป็นสีแทนสำหรับทุกมุม (เช่น ) ฉันจะรันใหม่ด้วยมุมที่สร้างแบบสุ่มและแก้ไขโพสต์ π/4
Lyndon White

ควรมีแผนที่หนึ่งถึงหนึ่งใกล้เคียงระหว่าง julia และ numpy และระหว่าง Mocha และ Caffe หากคุณต้องการนำมันมาใช้ใหม่ มีบางส่วนของรหัสที่คุณอ่านยากหรือไม่ จูเลียน่าจะเป็นภาษาที่เข้าใจง่าย ดังนั้นบางทีฉันอาจทำอะไรแปลก ๆ
Lyndon White

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

5

นี่คือการใช้งาน Python อีกวิธีหนึ่งเมื่อเปรียบเทียบการเข้ารหัสของLyndon Whiteกับวิธีการแบบ binned รหัสด้านล่างสร้างผลลัพธ์ต่อไปนี้:

Training Size: 100
Training Epochs: 100
Encoding: cos_sin
Test Error: 0.017772154610047136
Encoding: binned
Test Error: 0.043398792553251526

Training Size: 100
Training Epochs: 500
Encoding: cos_sin
Test Error: 0.015376604917819397
Encoding: binned
Test Error: 0.032942592915322394

Training Size: 1000
Training Epochs: 100
Encoding: cos_sin
Test Error: 0.007544091937411164
Encoding: binned
Test Error: 0.012796594492198667

Training Size: 1000
Training Epochs: 500
Encoding: cos_sin
Test Error: 0.0038051515079569097
Encoding: binned
Test Error: 0.006180633805557207

(บาป(θ),cos(θ))(บาป(θ),cos(θ))

import matplotlib.pyplot as plt
import numpy as np
import torch
import torch.nn as nn
import torch.utils.data

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")


class Net(nn.Module):
    def __init__(self, input_size, hidden_size, num_out):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.sigmoid = nn.Sigmoid()
        self.fc2 = nn.Linear(hidden_size, num_out)

    def forward(self, x):
        out = self.fc1(x)
        out = self.sigmoid(out)
        out = self.fc2(out)
        return out


def gen_train_image(angle, side, thickness):
    image = np.zeros((side, side))
    (x_0, y_0) = (side / 2, side / 2)
    (c, s) = (np.cos(angle), np.sin(angle))
    for y in range(side):
        for x in range(side):
            if (abs((x - x_0) * c + (y - y_0) * s) < thickness / 2) and (
                    -(x - x_0) * s + (y - y_0) * c > 0):
                image[x, y] = 1

    return image.flatten()


def gen_data(num_samples, side, num_bins, thickness):
    angles = 2 * np.pi * np.random.uniform(size=num_samples)
    X = [gen_train_image(angle, side, thickness) for angle in angles]
    X = np.stack(X)

    y = {"cos_sin": [], "binned": []}
    bin_size = 2 * np.pi / num_bins
    for angle in angles:
        idx = int(angle / bin_size)
        y["binned"].append(idx)
        y["cos_sin"].append(np.array([np.cos(angle), np.sin(angle)]))

    for enc in y:
        y[enc] = np.stack(y[enc])

    return (X, y, angles)


def get_model_stuff(train_y, input_size, hidden_size, output_sizes,
                    learning_rate, momentum):
    nets = {}
    optimizers = {}

    for enc in train_y:
        net = Net(input_size, hidden_size, output_sizes[enc])
        nets[enc] = net.to(device)
        optimizers[enc] = torch.optim.SGD(net.parameters(), lr=learning_rate,
                                          momentum=momentum)

    criterions = {"binned": nn.CrossEntropyLoss(), "cos_sin": nn.MSELoss()}
    return (nets, optimizers, criterions)


def get_train_loaders(train_X, train_y, batch_size):
    train_X_tensor = torch.Tensor(train_X)

    train_loaders = {}

    for enc in train_y:
        if enc == "binned":
            train_y_tensor = torch.tensor(train_y[enc], dtype=torch.long)
        else:
            train_y_tensor = torch.tensor(train_y[enc], dtype=torch.float)

        dataset = torch.utils.data.TensorDataset(train_X_tensor, train_y_tensor)
        train_loader = torch.utils.data.DataLoader(dataset=dataset,
                                                   batch_size=batch_size,
                                                   shuffle=True)
        train_loaders[enc] = train_loader

    return train_loaders


def show_image(image, side):
    img = plt.imshow(np.reshape(image, (side, side)), interpolation="nearest",
                     cmap="Greys")
    plt.show()


def main():
    side = 101
    input_size = side ** 2
    thickness = 5.0
    hidden_size = 500
    learning_rate = 0.01
    momentum = 0.9
    num_bins = 500
    bin_size = 2 * np.pi / num_bins
    half_bin_size = bin_size / 2
    batch_size = 50
    output_sizes = {"binned": num_bins, "cos_sin": 2}
    num_test = 1000

    (test_X, test_y, test_angles) = gen_data(num_test, side, num_bins,
                                             thickness)

    for num_train in [100, 1000]:

        (train_X, train_y, train_angles) = gen_data(num_train, side, num_bins,
                                                    thickness)
        train_loaders = get_train_loaders(train_X, train_y, batch_size)

        for epochs in [100, 500]:

            (nets, optimizers, criterions) = get_model_stuff(train_y, input_size,
                                                             hidden_size, output_sizes,
                                                             learning_rate, momentum)

            for enc in train_y:
                optimizer = optimizers[enc]
                net = nets[enc]
                criterion = criterions[enc]

                for epoch in range(epochs):
                    for (i, (images, ys)) in enumerate(train_loaders[enc]):
                        optimizer.zero_grad()

                        outputs = net(images.to(device))
                        loss = criterion(outputs, ys.to(device))
                        loss.backward()
                        optimizer.step()


            print("Training Size: {0}".format(num_train))
            print("Training Epochs: {0}".format(epochs))
            for enc in train_y:
                net = nets[enc]
                preds = net(torch.tensor(test_X, dtype=torch.float).to(device))
                if enc == "binned":
                    pred_bins = np.array(preds.argmax(dim=1).detach().cpu().numpy(),
                                         dtype=np.float)
                    pred_angles = bin_size * pred_bins + half_bin_size
                else:
                    pred_angles = torch.atan2(preds[:, 1], preds[:, 0]).detach().cpu().numpy()
                    pred_angles[pred_angles < 0] = pred_angles[pred_angles < 0] + 2 * np.pi

                print("Encoding: {0}".format(enc))
                print("Test Error: {0}".format(np.abs(pred_angles - test_angles).mean()))

            print()


if __name__ == "__main__":
    main()

3

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

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

ฉันสามารถรับความถูกต้องได้ค่อนข้างดีโดยใช้ binning และการเข้ารหัส "gaussian" (ชื่อที่ฉันสร้างขึ้นคล้ายกับ binning ยกเว้นว่าเวกเตอร์เอาต์พุตเป้าหมายมีรูปแบบ exp (-pi * ([1,2,3, ... , 500] - idx) ** 2) โดยที่ idx คือดัชนีที่สอดคล้องกับมุมที่ถูกต้อง) รหัสด้านล่าง; นี่คือผลลัพธ์ของฉัน:

ทดสอบข้อผิดพลาดสำหรับการเข้ารหัส (cos, sin):

ภาพฝึกอบรม 1,000 รูป, ภาพทดสอบ 1,000 ภาพ, ซ้ำ 50 ครั้ง, เอาท์พุทเชิงเส้น

  • หมายถึง: 0.0911558142071

  • ค่ามัธยฐาน: 0.0429723541743

  • ขั้นต่ำ: 2.77769843793e-06

  • สูงสุด: 6.2608513539

  • ความแม่นยำถึง 0.1: 85.2%

  • ความแม่นยำ 0.01: 11.6%

  • ความแม่นยำถึง 0.001: 1.0%

ทดสอบข้อผิดพลาดสำหรับการเข้ารหัส [-1,1]:

ภาพฝึกอบรม 1,000 รูป, ภาพทดสอบ 1,000 ภาพ, ซ้ำ 50 ครั้ง, เอาท์พุทเชิงเส้น

  • หมายถึง: 0.234181700523

  • ค่ามัธยฐาน: 0.17460197307

  • ขั้นต่ำ: 0.000473665840258

  • สูงสุด: 6.00637777237

  • ความแม่นยำ 0.1: 29.9%

  • ความแม่นยำ 0.01: 3.3%

  • ความแม่นยำถึง 0.001: 0.1%

ทดสอบข้อผิดพลาดสำหรับการเข้ารหัส 1 ถึง 500:

ภาพฝึกอบรม 1,000 รูป, ภาพทดสอบ 1,000 ภาพ, ซ้ำ 50 ภาพ, ผลงาน softmax

  • หมายถึง: 0.0298767021922

  • ค่ากลาง: 0.00388858079174

  • ขั้นต่ำ: 4.08712407829e-06

  • สูงสุด: 6.2784479965

  • ความแม่นยำถึง 0.1: 99.6%

  • ความแม่นยำ 0.01: 88.9%

  • ความแม่นยำถึง 0.001: 13.5%

ข้อผิดพลาดในการทดสอบสำหรับการเข้ารหัสแบบเกาส์:

ภาพฝึกอบรม 1,000 รูป, ภาพทดสอบ 1,000 ภาพ, ซ้ำ 50 ภาพ, ผลงาน softmax

  • หมายถึง: 0.0296905377463
  • ค่ากลาง: 0.00365867335107
  • ขั้นต่ำ: 4.08712407829e-06
  • สูงสุด: 6.2784479965
  • ความแม่นยำถึง 0.1: 99.6%
  • ความแม่นยำ 0.01: 90.8%
  • ความแม่นยำถึง 0.001: 14.3%

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

# -*- coding: utf-8 -*-
"""
Created on Mon Jun 13 16:59:53 2016

@author: Ari
"""

from numpy import savetxt, loadtxt, round, zeros, sin, cos, arctan2, clip, pi, tanh, exp, arange, dot, outer, array, shape, zeros_like, reshape, mean, median, max, min
from numpy.random import rand, shuffle
import matplotlib.pyplot as plt

###########
# Functions
###########

# Returns a B&W image of a line represented as a binary vector of length width*height
def gen_train_image(angle, width, height, thickness):
    image = zeros((height,width))
    x_0,y_0 = width/2, height/2
    c,s = cos(angle),sin(angle)
    for y in range(height):
        for x in range(width):
            if abs((x-x_0)*c + (y-y_0)*s) < thickness/2 and -(x-x_0)*s + (y-y_0)*c > 0:
                image[x,y] = 1
    return image.flatten()

# Display training image    
def display_image(image,height, width):    
    img = plt.imshow(reshape(image,(height,width)), interpolation = 'nearest', cmap = "Greys")
    plt.show()    

# Activation function
def sigmoid(X):
    return 1.0/(1+exp(-clip(X,-50,100)))

# Returns encoded angle using specified method ("binned","scaled","cossin","gaussian")
def encode_angle(angle, method):
    if method == "binned": # 1-of-500 encoding
        X = zeros(500)
        X[int(round(250*(angle/pi + 1)))%500] = 1
    elif method == "gaussian": # Leaky binned encoding
        X = array([i for i in range(500)])
        idx = 250*(angle/pi + 1)
        X = exp(-pi*(X-idx)**2)
    elif method == "scaled": # Scaled to [-1,1] encoding
        X = array([angle/pi])
    elif method == "cossin": # Oxinabox's (cos,sin) encoding
        X = array([cos(angle),sin(angle)])
    else:
        pass
    return X

# Returns decoded angle using specified method
def decode_angle(X, method):
    if method == "binned" or method == "gaussian": # 1-of-500 or gaussian encoding
        M = max(X)
        for i in range(len(X)):
            if abs(X[i]-M) < 1e-5:
                angle = pi*i/250 - pi
                break
#        angle = pi*dot(array([i for i in range(500)]),X)/500  # Averaging
    elif method == "scaled": # Scaled to [-1,1] encoding
        angle = pi*X[0]
    elif method == "cossin": # Oxinabox's (cos,sin) encoding
        angle = arctan2(X[1],X[0])
    else:
        pass
    return angle

# Train and test neural network with specified angle encoding method
def test_encoding_method(train_images,train_angles,test_images, test_angles, method, num_iters, alpha = 0.01, alpha_bias = 0.0001, momentum = 0.9, hid_layer_size = 500):
    num_train,in_layer_size = shape(train_images)
    num_test = len(test_angles)

    if method == "binned":
        out_layer_size = 500
    elif method == "gaussian":
        out_layer_size = 500
    elif method == "scaled":
        out_layer_size = 1
    elif method == "cossin":
        out_layer_size = 2
    else:
        pass

    # Initial weights and biases
    IN_HID = rand(in_layer_size,hid_layer_size) - 0.5 # IN --> HID weights
    HID_OUT = rand(hid_layer_size,out_layer_size) - 0.5 # HID --> OUT weights
    BIAS1 = rand(hid_layer_size) - 0.5 # Bias for hidden layer
    BIAS2 = rand(out_layer_size) - 0.5 # Bias for output layer

    # Initial weight and bias updates
    IN_HID_del = zeros_like(IN_HID)
    HID_OUT_del = zeros_like(HID_OUT)
    BIAS1_del = zeros_like(BIAS1)
    BIAS2_del = zeros_like(BIAS2)

    # Train
    for j in range(num_iters):
        for i in range(num_train):
            # Get training example
            IN = train_images[i]
            TARGET = encode_angle(train_angles[i],method) 

            # Feed forward and compute error derivatives
            HID = sigmoid(dot(IN,IN_HID)+BIAS1)

            if method == "binned" or method == "gaussian": # Use softmax
                OUT = exp(clip(dot(HID,HID_OUT)+BIAS2,-100,100))
                OUT = OUT/sum(OUT)
                dACT2 = OUT - TARGET
            elif method == "cossin" or method == "scaled": # Linear
                OUT = dot(HID,HID_OUT)+BIAS2 
                dACT2 = OUT-TARGET 
            else:
                print("Invalid encoding method")

            dHID_OUT = outer(HID,dACT2)
            dACT1 = dot(dACT2,HID_OUT.T)*HID*(1-HID)
            dIN_HID = outer(IN,dACT1)
            dBIAS1 = dACT1
            dBIAS2 = dACT2

            # Update the weight updates 
            IN_HID_del = momentum*IN_HID_del + (1-momentum)*dIN_HID
            HID_OUT_del = momentum*HID_OUT_del + (1-momentum)*dHID_OUT
            BIAS1_del = momentum*BIAS1_del + (1-momentum)*dBIAS1
            BIAS2_del = momentum*BIAS2_del + (1-momentum)*dBIAS2

            # Update the weights
            HID_OUT -= alpha*dHID_OUT
            IN_HID -= alpha*dIN_HID
            BIAS1 -= alpha_bias*dBIAS1
            BIAS2 -= alpha_bias*dBIAS2

    # Test
    test_errors = zeros(num_test)
    angles = zeros(num_test)
    target_angles = zeros(num_test)
    accuracy_to_point001 = 0
    accuracy_to_point01 = 0
    accuracy_to_point1 = 0

    for i in range(num_test):

        # Get training example
        IN = test_images[i]
        target_angle = test_angles[i]

        # Feed forward
        HID = sigmoid(dot(IN,IN_HID)+BIAS1)

        if method == "binned" or method == "gaussian":
            OUT = exp(clip(dot(HID,HID_OUT)+BIAS2,-100,100))
            OUT = OUT/sum(OUT)
        elif method == "cossin" or method == "scaled":
            OUT = dot(HID,HID_OUT)+BIAS2 

        # Decode output 
        angle = decode_angle(OUT,method)

        # Compute errors
        error = abs(angle-target_angle)
        test_errors[i] = error
        angles[i] = angle

        target_angles[i] = target_angle
        if error < 0.1:
            accuracy_to_point1 += 1
        if error < 0.01: 
            accuracy_to_point01 += 1
        if error < 0.001:
            accuracy_to_point001 += 1

    # Compute and return results
    accuracy_to_point1 = 100.0*accuracy_to_point1/num_test
    accuracy_to_point01 = 100.0*accuracy_to_point01/num_test
    accuracy_to_point001 = 100.0*accuracy_to_point001/num_test

    return mean(test_errors),median(test_errors),min(test_errors),max(test_errors),accuracy_to_point1,accuracy_to_point01,accuracy_to_point001

# Dispaly results
def display_results(results,method):
    MEAN,MEDIAN,MIN,MAX,ACC1,ACC01,ACC001 = results
    if method == "binned":
        print("Test error for 1-of-500 encoding:")
    elif method == "gaussian":
        print("Test error for gaussian encoding: ")
    elif method == "scaled":
        print("Test error for [-1,1] encoding:")
    elif method == "cossin":
        print("Test error for (cos,sin) encoding:")
    else:
        pass
    print("-----------")
    print("Mean: "+str(MEAN))
    print("Median: "+str(MEDIAN))
    print("Minimum: "+str(MIN))
    print("Maximum: "+str(MAX))
    print("Accuracy to 0.1: "+str(ACC1)+"%")
    print("Accuracy to 0.01: "+str(ACC01)+"%")
    print("Accuracy to 0.001: "+str(ACC001)+"%")
    print("\n\n")


##################
# Image parameters
##################
width = 100 # Image width
height = 100 # Image heigth
thickness = 5.0 # Line thickness

#################################
# Generate training and test data
#################################
num_train = 1000
num_test = 1000
test_images = []
test_angles = []
train_images = []
train_angles = []
for i in range(num_train):
    angle = pi*(2*rand() - 1)
    train_angles.append(angle)
    image = gen_train_image(angle,width,height,thickness)
    train_images.append(image)
for i in range(num_test):
    angle = pi*(2*rand() - 1)
    test_angles.append(angle)
    image = gen_train_image(angle,width,height,thickness)
    test_images.append(image)
train_angles,train_images,test_angles,test_images = array(train_angles),array(train_images),array(test_angles),array(test_images)



###########################
# Evaluate encoding schemes
###########################
num_iters = 50

# Train with cos,sin encoding
method = "cossin"
results1 = test_encoding_method(train_images, train_angles, test_images, test_angles, method, num_iters)
display_results(results1,method)

# Train with scaled encoding
method = "scaled"
results3 = test_encoding_method(train_images, train_angles, test_images, test_angles, method, num_iters)
display_results(results3,method)

# Train with binned encoding
method = "binned"
results2 = test_encoding_method(train_images, train_angles, test_images, test_angles, method, num_iters)
display_results(results2,method)

# Train with gaussian encoding
method = "gaussian"
results4 = test_encoding_method(train_images, train_angles, test_images, test_angles, method, num_iters)
display_results(results4,method)

เด็ด, แตกต่างกับคีย์ คุณเป็นเพียงการฝึกอบรมในแต่ละภาพหนึ่งครั้ง ฉันกำลังฝึกซ้อมในแต่ละภาพ 1,000 ครั้งหรือ 10,000 ครั้ง ซ้ำหลายครั้งแม้ว่าข้อมูลการฝึกอบรมเป็นเรื่องปกติโดยเฉพาะอย่างยิ่งเมื่อฝึกอบรมกับข้อมูลจำนวนเล็กน้อย (และใช้เวลาเพียงหนึ่งวิทยานิพนธ์ปริญญาตรีที่ไม่สามารถเผยแพร่ได้สำหรับฉันที่จะเรียนรู้สิ่งนี้ แต่นั่นเป็นอีกเรื่องหนึ่ง) ด้วยที่กล่าวว่าฉันควรเพิ่ม 1 คอลัมน์ iter ในตารางของฉัน นั่นจะเป็นข้อมูล
Lyndon White

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

มันคล้ายกัน แต่สำหรับงานตัวอย่างนี้มันไม่มีปัญหาที่ในที่สุดคุณจะแสดงภาพทั้งหมดที่เป็นไปได้ดังนั้นการทดสอบของคุณจะทับซ้อนกับรถไฟของคุณดังนั้นการทดสอบทั่วไปจะไม่ทำงาน มีความหมายมากกว่าที่คุณทำ 100,000 ภาพการฝึกอบรมซึ่งเป็น <1,000 * 1,000 ภาพการฝึกอบรม * การทำซ้ำ
Lyndon White

คุณถูกต้องฉันจะแก้ไขปัญหานั้น มีปัญหาที่สำคัญยิ่งกว่าในรหัสของฉัน: ฉันกำลังใช้เซลล์ประสาทลอจิสติกซึ่งไม่สามารถสร้างค่าลบที่ต้องการโดยการนำเสนอ (cos, sin) D'โอ้! ฉันจะแก้ไขรหัสของฉันและโพสต์ใหม่โดยเร็วที่สุด
Ari Herman

คุณอาจ (ถ้าคุณยังไม่ได้ดำเนินการ) ให้สนใจทำGraident Checkซึ่งคุ้มค่าเมื่อนำเครือข่ายประสาทเทียมมาใช้ตั้งแต่เริ่มต้นเนื่องจากเป็นเรื่องง่ายมากที่จะทำผิดพลาดเล็กน้อยและทำให้เครือข่ายของคุณใช้งานได้เป็นส่วนใหญ่ Re: Neuron: ใช่ฉันมีชั้นเอาท์พุทเชิงเส้นบนของชั้นซ่อน sigmoid
Lyndon White

1

อีกวิธีในการเข้ารหัสมุมคือชุดของค่าสองค่า:

y1 = สูงสุด (0, theta)

y2 = สูงสุด (0, -theta)

theta_out = y1 - y2

นี่จะมีปัญหาคล้ายกับ arctan2 ซึ่งการไล่ระดับสีไม่ได้กำหนดที่ theta = 0 ฉันไม่มีเวลาในการฝึกอบรมเครือข่ายและเปรียบเทียบกับการเข้ารหัสอื่น ๆ แต่ในบทความนี้เทคนิคดูเหมือนว่าประสบความสำเร็จอย่างสมเหตุสมผล


1
ดูเหมือนว่าคำตอบจะผสมกับคำถามอื่นในโพสต์เดียว ไซต์นี้ทำงานแตกต่างจากฟอรัมอย่างไร คำตอบที่นี่ควรเน้นการตอบคำถามต้นฉบับ และหากคุณมีคำถามอื่นหรือแสดงความคิดเห็น - ควรโพสต์เช่นนี้
Karolis Koncevičius
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.