เจาะลึก cuda-convnet: เลเยอร์ AlexNet แบบ GPU คู่และยุค ImageNet

จุดเปลี่ยนของ AlexNet ในปี 2012 อาศัยวิศวกรรม GPU ระดับต่ำ (cuda-convnet) และสถาปัตยกรรมแบบแยก GPU คู่ ซึ่งจุดชนวนการแข่งขันอย่างรวดเร็วเพื่อสร้างโมเดลคอมพิวเตอร์วิทัศน์ที่ลึกขึ้นและมีประสิทธิภาพมากขึ้นโดยตรง
1. cuda-convnet ทำงานเบื้องหลังอย่างไร
ก่อนที่ NVIDIA จะสร้าง cuDNN นั้น Alex Krizhevsky เขียน cuda-convnet ด้วย CUDA C++ แบบดิบเพื่อรีดความเร็วสูงสุดจาก GPU สถาปัตยกรรม Fermi รุ่นแรก (GTX 580) ไลบรารีสมัยใหม่มักคลี่การคอนโวลูชันออกเป็นการคูณเมทริกซ์ขนาดยักษ์ (im2col) ซึ่งกินหน่วยความจำมหาศาล เนื่องจาก GTX 580 แต่ละตัวมี VRAM เพียง 3 GB Krizhevsky จึงออกแบบรูทีน GPU แบบตรงที่ประหยัดหน่วยความจำ
- เลย์เอาต์หน่วยความจำแบบ Batch-First (CHWN) เฟรมเวิร์กสมัยใหม่ใช้ NCHW (Batch, Channels, Height, Width) เป็นค่าเริ่มต้น ซึ่งวางพิกเซลทั้งหมดของภาพเดียวไว้ติดกันในหน่วยความจำ Krizhevsky เก็บเทนเซอร์ตามลำดับ CHWN โดยวางมิติแบตช์ (N) ไว้สุดท้าย เมื่อเธรด GPU 32 เธรดใน warp ประมวลผลภาพ 32 ภาพที่ตำแหน่งพิกเซลเดียวกันพอดี การอ่านหน่วยความจำของเธรดเหล่านั้นจึงต่อเนื่องกันทั้งหมด (coalesced) ทำให้ใช้แบนด์วิดท์ VRAM ได้สูงสุด
- การทำ Shared Memory Tiling การอ่านจาก VRAM ส่วนกลางใช้เวลาหลายร้อยรอบสัญญาณนาฬิกา ในขณะที่ Shared Memory บนชิป (มีเพียง 48 KB ต่อ Streaming Multiprocessor บน GTX 580) ใช้เพียงไม่กี่รอบ เธรดบล็อกโหลดแพตช์ 2 มิติขนาดเล็กของพิกเซลภาพและน้ำหนักฟิลเตอร์เข้าไปใน Shared Memory แล้วคำนวณดอตโปรดักต์หลายสิบครั้งก่อนเขียนผลลัพธ์สุดท้ายกลับไปยัง VRAM
- การนำรีจิสเตอร์ระดับ Warp กลับมาใช้ซ้ำ Krizhevsky มอบหมายให้แต่ละเธรดบล็อกคำนวณไทล์ของพิกเซลเอาต์พุตข้ามหลายฟิลเตอร์พร้อมกัน เมื่อเก็บน้ำหนักฟิลเตอร์ไว้ในรีจิสเตอร์ GPU ที่เร็ว แพตช์ภาพหนึ่งชิ้นที่โหลดจาก Shared Memory จึงถูกใช้ซ้ำกับหลายฟิลเตอร์ในคราวเดียว ช่วยลดปริมาณการรับส่งข้อมูลหน่วยความจำลงอย่างมาก
2. เลเยอร์เฉพาะของ AlexNet และการแบ่งการทำงานบน GPU คู่
AlexNet มีเลเยอร์ที่เรียนรู้ได้ 8 เลเยอร์ (คอนโวลูชัน 5 และ fully connected 3) รวมพารามิเตอร์ประมาณ 60 ล้านตัว เนื่องจาก GTX 580 เพียงตัวเดียวมี VRAM ไม่ถึง 3 GB ขึ้นไปที่ต้องใช้สำหรับ activation น้ำหนัก และ gradient Krizhevsky จึงแบ่งเครือข่ายในแนวตั้งออกเป็นสองสตรีมที่ทำงานขนานกัน
| เลเยอร์ | ประเภท | จำนวนฟิลเตอร์ / นิวรอนทั้งหมด | การแบ่งต่อ GPU | การสื่อสารข้าม GPU |
|---|---|---|---|---|
| อินพุต | ภาพ RGB | 224 × 224 × 3 | คัดลอกไปยัง GPU ทั้งสองตัว | ไม่มี |
| Conv 1 | คอนโวลูชัน 11×11 (stride 4) + MaxPool | ฟิลเตอร์ 96 ตัว | ฟิลเตอร์ 48 ตัวต่อ GPU | แยกอิสระ (ไม่ซิงก์) |
| Conv 2 | คอนโวลูชัน 5×5 + MaxPool | ฟิลเตอร์ 256 ตัว | ฟิลเตอร์ 128 ตัวต่อ GPU | แยกอิสระ (อ่านเฉพาะ Conv 1 ของ GPU ตัวเอง) |
| Conv 3 | คอนโวลูชัน 3×3 | ฟิลเตอร์ 384 ตัว | ฟิลเตอร์ 192 ตัวต่อ GPU | ซิงก์เต็มรูปแบบ (อ่านแผนที่ฟีเจอร์ทั้ง 256 แผนที่จาก GPU ทั้งสอง) |
| Conv 4 | คอนโวลูชัน 3×3 | ฟิลเตอร์ 384 ตัว | ฟิลเตอร์ 192 ตัวต่อ GPU | แยกอิสระ (อ่านเฉพาะ Conv 3 ของ GPU ตัวเอง) |
| Conv 5 | คอนโวลูชัน 3×3 + MaxPool | ฟิลเตอร์ 256 ตัว | ฟิลเตอร์ 128 ตัวต่อ GPU | แยกอิสระ (อ่านเฉพาะ Conv 4 ของ GPU ตัวเอง) |
| FC 6 | Fully Connected + Dropout | นิวรอน 4,096 ตัว | นิวรอน 2,048 ตัวต่อ GPU | ซิงก์เต็มรูปแบบ (เชื่อมต่อกับเอาต์พุต Conv 5 ทั้งหมด) |
| FC 7 | Fully Connected + Dropout | นิวรอน 4,096 ตัว | นิวรอน 2,048 ตัวต่อ GPU | ซิงก์เต็มรูปแบบ (เชื่อมต่อกับนิวรอน FC 6 ทั้งหมด) |
| FC 8 | Fully Connected (Softmax) | 1,000 คลาส | 1,000 คลาส (รวมกัน) | ซิงก์เต็มรูปแบบ (ส่งออกผลทำนาย ImageNet ขั้นสุดท้าย) |
- ความเชี่ยวชาญของฟีเจอร์ที่เกิดขึ้นเอง น่าสนใจที่เพราะเลเยอร์ 1 และ 2 ไม่เคยสื่อสารข้าม GPU การ์ดทั้งสองใบจึงพัฒนาบทบาทเฉพาะทางขึ้นมาอย่างสม่ำเสมอ GPU ตัวหนึ่งเรียนรู้ตัวตรวจจับขอบและพื้นผิวที่ไม่ขึ้นกับสี (ฟิลเตอร์แบบ Gabor ระดับสีเทา) ส่วน GPU อีกตัวเชี่ยวชาญด้านก้อนสีและเฉดสีโดยเฉพาะ
- การลดคอขวดของ PCIe การส่งข้อมูลผ่านบัส PCIe ของเมนบอร์ดนั้นช้า Krizhevsky จำกัดการสื่อสารข้าม GPU ไว้เฉพาะ Conv 3 และเลเยอร์ Fully Connected เท่านั้น ทำให้ GPU คำนวณได้เต็มความเร็วโดยไม่ต้องหยุดรอการถ่ายโอนข้อมูล
3. สิ่งที่เกิดขึ้นต่อมาในยุค ImageNet
ชัยชนะของ AlexNet จุดประกายการแข่งขันประจำปีในงานประกวด ImageNet ผลักดันให้เครือข่ายเพิ่มจาก 8 เลเยอร์เป็นมากกว่า 150 เลเยอร์ภายในเวลาเพียงสามปี
- 2013 – ZFNet (การมองเห็นภาพและการปรับแต่ง) Matthew Zeiler และ Rob Fergus นำเทคนิคดีคอนโวลูชันมาใช้เพื่อแสดงภาพว่า AlexNet "มองเห็น" อะไรอยู่ภายในเลเยอร์ซ่อน ด้วยการลดขนาดฟิลเตอร์ของเลเยอร์แรกของ AlexNet จาก 11×11 เหลือ 7×7 และลด stride ทำให้ ZFNet ลดอัตราความผิดพลาด top-5 ของ ImageNet จาก 15.3% เหลือ 14.8%
- 2014 – VGGNet (ความลึกด้วยฟิลเตอร์ 3×3 ที่เหมือนกันทั้งหมด) นักวิจัยจากออกซ์ฟอร์ดพิสูจน์ว่าการซ้อนคอนโวลูชัน 3×3 ขนาดเล็กจำนวนมาก (สูงสุด 16 หรือ 19 เลเยอร์) ให้ผลดีกว่าการใช้ฟิลเตอร์ขนาดใหญ่เพียงตัวเดียว (เช่น 11×11 หรือ 5×5) เลเยอร์ 3×3 ที่ซ้อนกันสองชั้นครอบคลุมพื้นที่การมองเห็น 5×5 เท่ากัน โดยใช้พารามิเตอร์น้อยกว่าและมี ReLU activation แบบไม่เชิงเส้นเพิ่มขึ้น ทำให้อัตราความผิดพลาดลดลงเหลือ 7.3%
- 2014 – GoogLeNet / Inception (ประสิทธิภาพหลายสเกล) Google นำเสนอโมดูล Inception ซึ่งรันคอนโวลูชัน 1×1, 3×3 และ 5×5 แบบขนานภายในเลเยอร์เดียวกันแล้วรวมเอาต์พุตเข้าด้วยกัน ด้วยการใช้คอนโวลูชัน 1×1 ราคาถูกบีบอัดความลึกของแชนเนลก่อนการคำนวณที่แพง GoogLeNet จึงมีถึง 22 เลเยอร์ และมีอัตราความผิดพลาด 6.7% โดยใช้พารามิเตอร์น้อยกว่า AlexNet 12 เท่า
- 2015 – ResNet (Skip Connection และ 152 เลเยอร์) การซ้อนเลเยอร์เพิ่มขึ้นเรื่อย ๆ ในที่สุดทำให้ความแม่นยำในการฝึกลดลง เพราะ gradient หายไประหว่างการแพร่ย้อนกลับ Microsoft Research แก้ปัญหานี้ด้วย Residual Connection (skip connection) ซึ่งให้ข้อมูลข้ามเลเยอร์ผ่านทางลัดแบบ identity โดยตรง ทำให้สร้างเครือข่าย 152 เลเยอร์ได้ และได้อัตราความผิดพลาด top-5 ที่ 3.57% ซึ่งเหนือกว่าประสิทธิภาพเกณฑ์เทียบมนุษย์ (~5%) เป็นครั้งแรก