Keras และ Convnets สมัยใหม่บน TPU

1. ภาพรวม

ในห้องทดลองนี้ คุณจะได้เรียนรู้วิธีการสร้าง ฝึก และปรับแต่งโครงข่ายระบบประสาทเทียมแบบ Convolutional ของคุณเองตั้งแต่ต้นด้วย Keras และ Tensorflow 2 ซึ่งทั้งหมดนี้สามารถทำได้ในไม่กี่นาทีโดยใช้พลังของ TPU นอกจากนี้คุณจะได้สำรวจวิธีการที่หลากหลาย ตั้งแต่การเรียนรู้แบบถ่ายโอนง่ายๆ ไปจนถึงสถาปัตยกรรมคอนโวลูชันสมัยใหม่ (Convolutional) อย่าง Squeezenet ห้องปฏิบัติการนี้มีคำอธิบายทางทฤษฎีเกี่ยวกับโครงข่ายประสาทและเป็นจุดเริ่มต้นที่ดีสำหรับนักพัฒนาซอฟต์แวร์ที่กำลังเรียนรู้เกี่ยวกับการเรียนรู้เชิงลึก

การอ่านเอกสารการเรียนรู้เชิงลึกอาจเป็นเรื่องยากและน่าสับสน มาดูตัวอย่างสถาปัตยกรรมโครงข่ายระบบประสาทเทียมแบบโมเดิร์น

ca8cc21f6838eccc.png

สิ่งที่คุณจะได้เรียนรู้

  • วิธีใช้ Keras และ Tensor Processing Unit (TPU) เพื่อสร้างโมเดลที่กำหนดเองได้เร็วขึ้น
  • เพื่อใช้ tf.data.Dataset API และรูปแบบ TFRecord เพื่อโหลดข้อมูลการฝึกอย่างมีประสิทธิภาพ
  • เพื่อโกง 😈 โดยใช้การโอนการเรียนรู้แทนการสร้างโมเดลของคุณเอง
  • เพื่อใช้รูปแบบโมเดลตามลำดับและฟังก์ชันการทำงานของ Keras
  • เพื่อสร้างตัวแยกประเภท Keras ของคุณเองที่มีเลเยอร์ซอฟต์แมกซ์และการสูญเสียครอสเอนโทรปี
  • เพื่อปรับแต่งโมเดลของคุณด้วยตัวเลือกเลเยอร์คอนโวลูชันที่ดี
  • เพื่อสำรวจแนวคิดสถาปัตยกรรม Convnet สมัยใหม่ เช่น โมดูล การรวมกลุ่มเฉลี่ยทั่วโลก ฯลฯ
  • เพื่อสร้าง Convnet ที่ทันสมัยและเรียบง่ายโดยใช้สถาปัตยกรรม Squeezenet

ความคิดเห็น

โปรดแจ้งให้เราทราบหากพบข้อผิดพลาดใน Code Lab นี้ คุณแสดงความคิดเห็นได้ผ่านปัญหาเกี่ยวกับ GitHub [ feedback link]

2. คู่มือเริ่มต้นฉบับย่อสำหรับ Google Colaboratory

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

c3df49e90e5a654f.png Welcome to Colab.ipynb

เลือกแบ็กเอนด์ TPU

8832c6208c99687d.png

ในเมนู Colab ให้เลือกรันไทม์ > เปลี่ยนประเภทรันไทม์ จากนั้นเลือก TPU ใน Code Lab นี้ คุณจะได้ใช้ TPU (Tensor Processing Unit) ที่มีประสิทธิภาพซึ่งได้รับการสนับสนุนไว้สำหรับการฝึกแบบเร่งฮาร์ดแวร์ การเชื่อมต่อกับรันไทม์จะเกิดขึ้นโดยอัตโนมัติในการดำเนินการครั้งแรก หรือคุณจะใช้การเชื่อมต่อ "เชื่อมต่อ" ก็ได้ ที่มุมบนขวา

การดำเนินการกับสมุดบันทึก

76d05caa8b4db6da.png

เรียกใช้ทีละเซลล์ด้วยการคลิกที่เซลล์แล้วกด Shift-ENTER นอกจากนี้ คุณยังเรียกใช้สมุดบันทึกทั้งหมดได้ด้วยรันไทม์ > เรียกใช้ทั้งหมด

สารบัญ

429f106990037ec4.png

สมุดบันทึกทั้งหมดมีสารบัญ คุณสามารถเปิดได้โดยใช้ลูกศรสีดำทางด้านซ้าย

เซลล์ที่ซ่อนอยู่

edc3dba45d26f12a.png

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

การตรวจสอบสิทธิ์

cdd4b41413100543.png

Colab อาจเข้าถึงที่เก็บข้อมูล Google Cloud Storage ส่วนตัวได้หากคุณตรวจสอบสิทธิ์ด้วยบัญชีที่ได้รับอนุญาต ข้อมูลโค้ดด้านบนจะทริกเกอร์ขั้นตอนการตรวจสอบสิทธิ์

3. [INFO] Tensor Processing Unit (TPU) คืออะไร

สรุป

f88cf6facfc70166.png

โค้ดสำหรับการฝึกโมเดลบน TPU ใน Keras (และกลับไปใช้ GPU หรือ CPU หากไม่มี TPU):

try: # detect TPUs
    tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
    strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
    strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines

# use TPUStrategy scope to define model
with strategy.scope():
  model = tf.keras.Sequential( ... )
  model.compile( ... )

# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)

ในวันนี้เราจะใช้ TPU เพื่อสร้างและเพิ่มประสิทธิภาพตัวแยกประเภทดอกไม้ด้วยความเร็วแบบอินเทอร์แอกทีฟ (นาทีต่อการฝึกแต่ละครั้ง)

688858c21e3beff2.png

ทำไมต้องใช้ TPU

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

8eb3e718b8e2ed08.png

ภาพประกอบ: ชั้นโครงข่ายระบบประสาทเทียมแบบคูณเมทริกซ์ โดยมีรูปภาพ 8 รูปประมวลผลผ่านโครงข่ายประสาทพร้อมกัน โปรดทำการคูณคอลัมน์ 1 บรรทัด x เพื่อยืนยันว่าเป็นการทำผลรวมแบบถ่วงน้ำหนักของค่าพิกเซลทั้งหมดของรูปภาพ เลเยอร์คอนโวลูชัน (Convolution) อาจแสดงเป็นการคูณเมทริกซ์ได้ด้วย แม้ว่าจะซับซ้อนกว่าเล็กน้อย ( มีคำอธิบายในส่วนที่ 1)

ฮาร์ดแวร์

MXU และ VPU

แกน TPU v2 สร้างขึ้นจาก Matrix Multiply Unit (MXU) ซึ่งเรียกใช้การคูณเมทริกซ์ และ Vectorประมวลผลข้อมูล Unit (VPU) สำหรับงานอื่นๆ ทั้งหมด เช่น การเปิดใช้งาน, softmax เป็นต้น VPU จะจัดการการคำนวณ Float32 และ int32 ส่วน MXU จะทำงานในรูปแบบจุดทศนิยม 16-32 บิตที่มีความแม่นยำแบบผสม

7d68944718f76b18.png

ผสมจุดทศนิยมที่มีความแม่นยำและ bFloat 16

MXU จะคำนวณการคูณเมทริกซ์โดยใช้อินพุต bfloat16 และเอาต์พุต Float32 การเก็บสะสมขั้นกลางจะเกิดขึ้นด้วยความแม่นยำ Float 32

19c5fc432840c714.png

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

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

อาร์เรย์แบบซิสโตลิก

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

องค์ประกอบพื้นฐานของการคูณเมทริกซ์คือผลคูณระหว่างเส้นจากเมทริกซ์หนึ่งและคอลัมน์จากเมทริกซ์อีกตัวหนึ่ง (ดูภาพประกอบที่ด้านบนของส่วนนี้) สำหรับการคูณเมทริกซ์ Y=X*W องค์ประกอบหนึ่งของผลลัพธ์จะเป็นดังนี้

Y[2,0] = X[2,0]*W[0,0] + X[2,1]*W[1,0] + X[2,2]*W[2,0] + ... + X[2,n]*W[n,0]

บน GPU จะมีการเขียนโปรแกรมผลิตภัณฑ์จุดนี้เป็น "แกน" ของ GPU แล้วดำเนินการกับ "แกน" ได้มากเท่าที่ต้องการ ที่มีอยู่ควบคู่กันไป เพื่อลองคำนวณทุกค่าของเมทริกซ์ผลลัพธ์พร้อมกัน หากเมทริกซ์ผลลัพธ์ใหญ่ 128x128 ต้องใช้ 128x128=16K "แกน" ไม่พร้อมใช้งานซึ่งโดยทั่วไปแล้วเป็นไปไม่ได้ โดย GPU ขนาดใหญ่ที่สุดจะมีแกนประมาณ 4,000 แกน ส่วน TPU จะใช้ฮาร์ดแวร์ขั้นต่ำเพียงเล็กน้อยสำหรับหน่วยประมวลผลใน MXU โดยมีเพียง bfloat16 x bfloat16 => float32 ตัวสะสมแบบทวีคูณเท่านั้น ไม่ใช่อย่างอื่น ซึ่ง TPU เหล่านี้มีขนาดเล็กมากจนทำให้ TPU ขนาด 16K นำไปใช้ในขนาด 128x128 MXU และประมวลผลการคูณเมทริกซ์ได้ในคราวเดียว

f1b283fc45966717.gif

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

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

Cloud TPU

เมื่อคุณขอ " Cloud TPU v2" บน Google Cloud Platform คุณจะได้รับเครื่องเสมือน (VM) ที่มีกระดาน TPU ติด PCI กระดาน TPU มีชิป TPU แบบ Dual-core 4 ชิป แกน TPU แต่ละแกนมี VPU (Vector Workflow Unit) และ 128x128 MXU (MatriXส่งต่อหน่วย) "Cloud TPU" นี้ จากนั้นมักจะเชื่อมต่อผ่านเครือข่ายกับ VM ที่ขอ ภาพรวมทั้งหมดจะมีลักษณะดังนี้

dfce5522ed644ece.png

ภาพประกอบ: VM ที่มี "Cloud TPU" แนบกับเครือข่าย Accelerator "Cloud TPU" สร้างจาก VM ที่มีบอร์ด TPU ประกอบ PCI ซึ่งมีชิป TPU แบบ Dual-core 4 ชิปอยู่

พ็อด TPU

ในศูนย์ข้อมูลของ Google นั้น TPU จะเชื่อมต่อกับการเชื่อมต่อระหว่างการประมวลผลประสิทธิภาพสูง (HPC) ซึ่งทำให้ปรากฏเป็น Accelerator ขนาดใหญ่มากตัวเดียว Google เรียกอุปกรณ์นี้ว่าพ็อดซึ่งสามารถครอบคลุมแกน TPU v2 ได้สูงสุด 512 แกน หรือแกน TPU v3 2048 แกน

2ec1e0d341e7fc34.jpeg

ภาพประกอบ: พ็อด TPU v3 บอร์ดและชั้นวาง TPU เชื่อมต่อกันผ่านการเชื่อมต่อถึงกัน HPC

ในระหว่างการฝึก ระบบจะแลกเปลี่ยนการไล่ระดับสีระหว่างแกน TPU โดยใช้อัลกอริทึม All-reduce ( มีคำอธิบายที่ดีของ all-reduce ที่นี่) โมเดลที่กำลังฝึกจะใช้ประโยชน์จากฮาร์ดแวร์ได้ด้วยการฝึกในแบบกลุ่มขนาดใหญ่

d97b9cc5d40fdb1d.gif

ภาพประกอบ: การซิงค์การไล่ระดับสีระหว่างการฝึกโดยใช้อัลกอริทึม All-Reduce ในเครือข่าย HPC แบบ Toroidal Mesh แบบ 2 มิติของ Google TPU

ซอฟต์แวร์

การฝึกอบรมแบบกลุ่มขนาดใหญ่

ขนาดกลุ่มที่เหมาะที่สุดสำหรับ TPU คือรายการข้อมูล 128 ครั้งต่อแกน TPU แต่ฮาร์ดแวร์สามารถแสดงการใช้งานที่ดีจากรายการข้อมูล 8 ครั้งต่อแกน TPU ได้แล้ว โปรดทราบว่า Cloud TPU 1 แกนมี 8 แกน

เราจะใช้ Keras API ใน Code Lab นี้ ใน Keras แบทช์ที่คุณระบุคือขนาดกลุ่มทั่วโลกสำหรับ TPU ทั้งหมด แบทช์จะแยกเป็น 8 โดยอัตโนมัติและทำงานบน 8 แกนของ TPU

da534407825f01e3.png

สำหรับเคล็ดลับด้านประสิทธิภาพเพิ่มเติม โปรดดูคู่มือประสิทธิภาพของ TPU สำหรับชุดอาหารที่มีขนาดใหญ่มาก อาจต้องมีการดูแลเป็นพิเศษในบางรุ่น ดูรายละเอียดเพิ่มเติมได้ที่ LARSOptimizer

ขั้นสูง: XLA

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

edce61112cd57972.png

ภาพ: หากต้องการเรียกใช้บน TPU กราฟการคำนวณที่กำหนดโดยโปรแกรม Tensorflow จะได้รับการแปลเป็นการนำเสนอแบบ XLA (Accelerated Linear Algebra) ก่อน จากนั้นจึงคอมไพล์ด้วย XLA ลงในโค้ดเครื่อง TPU

การใช้ TPU ใน Keras

TPU ได้รับการสนับสนุนผ่าน Keras API ใน Tensorflow 2.1 การรองรับ Keras ทำงานบน TPU และพ็อด TPU ต่อไปนี้คือตัวอย่างที่ทำงานได้บน TPU, GPU และ CPU

try: # detect TPUs
    tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
    strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
    strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines

# use TPUStrategy scope to define model
with strategy.scope():
  model = tf.keras.Sequential( ... )
  model.compile( ... )

# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)

ในข้อมูลโค้ดนี้

  • TPUClusterResolver().connect() พบ TPU ในเครือข่าย ซึ่งทำงานโดยไม่ต้องใช้พารามิเตอร์ในระบบ Google Cloud ส่วนใหญ่ (งาน AI Platform, Colaboratory, Kubeflow, VM ของ Deep Learning ที่สร้างผ่านยูทิลิตี "ctpu up") ระบบเหล่านี้จะทราบว่า TPU ของตนอยู่ที่ใดด้วยตัวแปรสภาพแวดล้อม TPU_NAME หากคุณสร้าง TPU ด้วยตนเอง ให้ตั้งค่าสภาพแวดล้อม TPU_NAME ตัวแปร ใน VM ที่คุณใช้ หรือเรียกใช้ TPUClusterResolver ด้วยพารามิเตอร์ที่ชัดแจ้ง: TPUClusterResolver(tp_uname, zone, project)
  • TPUStrategy เป็นส่วนที่ใช้การกระจายและ "ลดทั้งหมด" อัลกอริทึมการซิงค์แบบไล่ระดับสี
  • นำกลยุทธ์ไปใช้ผ่านขอบเขต ต้องกำหนดโมเดลภายใน strategy scope()
  • ฟังก์ชัน tpu_model.fit คาดหวังออบเจ็กต์ tf.data.Dataset สำหรับอินพุตสำหรับการฝึก TPU

งานการย้าย TPU ทั่วไป

  • แม้ว่าการโหลดข้อมูลในรูปแบบ Tensorflow จะมีหลายวิธี แต่สำหรับ TPU จำเป็นต้องมีการใช้ API ของ tf.data.Dataset
  • TPU ทำงานเร็วมากและการส่งผ่านข้อมูลมักกลายเป็นจุดคอขวดเมื่อทำงานบน TPU คุณสามารถใช้เครื่องมือในการตรวจหาจุดคอขวดของข้อมูลและเคล็ดลับด้านประสิทธิภาพอื่นๆ ได้ในคู่มือประสิทธิภาพ TPU
  • หมายเลข int8 หรือ int16 จะถือว่าเป็น int32 TPU ไม่มีฮาร์ดแวร์จำนวนเต็มที่ทํางานน้อยกว่า 32 บิต
  • ไม่รองรับการดำเนินการบางอย่างของ Tensorflow ดูรายชื่อได้ที่นี่ ข่าวดีคือข้อจำกัดนี้จะใช้กับโค้ดการฝึกเท่านั้น เช่น การส่งผ่านไปข้างหน้าและข้างหลังผ่านโมเดลของคุณ คุณยังคงใช้การดำเนินการ Tensorflow ทั้งหมดในไปป์ไลน์อินพุตข้อมูลได้เนื่องจากการดำเนินการดังกล่าวจะเกิดขึ้นบน CPU
  • ไม่รองรับ tf.py_func บน TPU

4. กำลังโหลดข้อมูล

c0ecb860e4cad0a9.jpeg cc4781a7739c49ae.jpeg 81236b00f8bbf39e.jpeg 961e2228974076bb.jpeg 7517dc163bdffcd5.jpeg 96392df4767f566d.png

เราจะใช้ชุดข้อมูลของภาพดอกไม้ เป้าหมายคือการจัดหมวดหมู่ดอกไม้ออกเป็น 5 ชนิด การโหลดข้อมูลดำเนินการโดยใช้ API ของ tf.data.Dataset ก่อนอื่น มาทำความรู้จักกับ API กัน

ลงมือปฏิบัติ

โปรดเปิดสมุดบันทึกต่อไปนี้ เรียกใช้เซลล์ (Shift-ENTER) และทำตามคำแนะนำที่เห็นข้อความ "ต้องดำเนินการ" ป้ายกำกับ

c3df49e90e5a654f.png Fun with tf.data.Dataset (playground).ipynb

ข้อมูลเพิ่มเติม

เกี่ยวกับ "ดอกไม้" ชุดข้อมูล

ระบบจะจัดระเบียบชุดข้อมูลใน 5 โฟลเดอร์ แต่ละโฟลเดอร์จะมีดอกไม้ชนิดเดียว โฟลเดอร์มีชื่อว่า ทานตะวัน เดซี่ แดนดิไลออน ทิวลิป และกุหลาบ ข้อมูลจะโฮสต์ในที่เก็บข้อมูลสาธารณะบน Google Cloud Storage ข้อความที่ตัดตอนมา:

gs://flowers-public/sunflowers/5139971615_434ff8ed8b_n.jpg
gs://flowers-public/daisy/8094774544_35465c1c64.jpg
gs://flowers-public/sunflowers/9309473873_9d62b9082e.jpg
gs://flowers-public/dandelion/19551343954_83bb52f310_m.jpg
gs://flowers-public/dandelion/14199664556_188b37e51e.jpg
gs://flowers-public/tulips/4290566894_c7f061583d_m.jpg
gs://flowers-public/roses/3065719996_c16ecd5551.jpg
gs://flowers-public/dandelion/8168031302_6e36f39d87.jpg
gs://flowers-public/sunflowers/9564240106_0577e919da_n.jpg
gs://flowers-public/daisy/14167543177_cd36b54ac6_n.jpg

เหตุใดจึงควรใช้ tf.data.Dataset

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

dataset = ... # load something (see below)
dataset = dataset.shuffle(1000) # shuffle the dataset with a buffer of 1000
dataset = dataset.cache() # cache the dataset in RAM or on disk
dataset = dataset.repeat() # repeat the dataset indefinitely
dataset = dataset.batch(128) # batch data elements together in batches of 128
AUTOTUNE = tf.data.AUTOTUNE
dataset = dataset.prefetch(AUTOTUNE) # prefetch next batch(es) while training

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

ข้อมูลเบื้องต้นเกี่ยวกับ tf.data.Dataset

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

filenames_dataset = tf.data.Dataset.list_files('gs://flowers-public/*/*.jpg')
# The parameter is a "glob" pattern that supports the * and ? wildcards.

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

def decode_jpeg(filename):
  bits = tf.io.read_file(filename)
  image = tf.io.decode_jpeg(bits)
  return image

image_dataset = filenames_dataset.map(decode_jpeg)
# this is now a dataset of decoded images (uint8 RGB format)

วิธีทำซ้ำในชุดข้อมูล

for data in my_dataset:
  print(data)

ชุดข้อมูลของ Tuples

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

def decode_jpeg_and_label(filename):
  bits = tf.read_file(filename)
  image = tf.io.decode_jpeg(bits)
  label = ... # extract flower name from folder name
  return image, label

image_dataset = filenames_dataset.map(decode_jpeg_and_label)
# this is now a dataset of (image, label) pairs 

for image, label in dataset:
  print(image.numpy().shape, label.numpy())

สรุป:การโหลดรูปภาพทีละรายการช้า!

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

โซลูชัน

นี่คือสมุดบันทึกโซลูชัน คุณสามารถใช้รหัสผ่านนี้ได้หากติดขัด

c3df49e90e5a654f.png Fun with tf.data.Dataset (solution).ipynb

หัวข้อที่ครอบคลุม

  • 🤔 tf.data.Dataset.list_files
  • 🤔 tf.data.Dataset.map
  • 🤔 ชุดข้อมูลของ Tuples
  • 😀 เป็นการทำซ้ำผ่านชุดข้อมูล

โปรดใช้เวลาสักครู่เพื่อทบทวนรายการตรวจสอบนี้

5. การโหลดข้อมูลเร็ว

ตัวเร่งฮาร์ดแวร์ Tensor Compute Unit (TPU) ที่เราจะใช้ในห้องทดลองนี้ทำงานเร็วมาก ความท้าทายคือการให้ข้อมูลแก่นักเรียนให้เร็วพอที่จะทำให้นักเรียนไม่ว่าง Google Cloud Storage (GCS) มีความสามารถในการคงอัตราการส่งข้อมูลที่สูงมาก แต่เช่นเดียวกับระบบพื้นที่เก็บข้อมูลระบบคลาวด์อื่นๆ การเริ่มเชื่อมต่อมีค่าใช้จ่ายระหว่างบางเครือข่าย ดังนั้น การจัดเก็บข้อมูลของเราเป็นไฟล์จำนวนหลายพันไฟล์จึงไม่ใช่วิธีที่ดีที่สุด เราจะจัดกลุ่มไฟล์เหล่านั้นให้เป็นไฟล์จำนวนน้อยลงและใช้พลังของ tf.data.Dataset เพื่ออ่านจากไฟล์หลายไฟล์พร้อมกัน

อ่าน

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

c3df49e90e5a654f.png Flower pictures to TFRecords.ipynb

เลย์เอาต์ข้อมูลที่เหมาะสำหรับอัตราการส่งข้อมูล GCS ที่เหมาะสมที่สุด

รูปแบบไฟล์ TFRecord

รูปแบบไฟล์ที่ Tensorflow ต้องการสำหรับการจัดเก็บข้อมูลคือรูปแบบ TFRecord ที่ใช้ protobuf รูปแบบอนุกรมอื่นๆ ก็ใช้ได้เช่นกัน แต่คุณสามารถโหลดชุดข้อมูลจากไฟล์ TFRecord โดยตรงได้โดยเขียนข้อความต่อไปนี้

filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...) # do the TFRecord decoding here - see below

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

AUTOTUNE = tf.data.AUTOTUNE
ignore_order = tf.data.Options()
ignore_order.experimental_deterministic = False

filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE)
dataset = dataset.with_options(ignore_order)
dataset = dataset.map(...) # do the TFRecord decoding here - see below

ข้อมูลสรุปของ TFRecord

คุณจัดเก็บข้อมูลได้ 3 ประเภทใน TFRecord ได้แก่ สตริงแบบไบต์ (รายการไบต์) จำนวนเต็ม 64 บิต และแบบลอย 32 บิต โดยจะจัดเก็บเป็นลิสต์รายการเสมอ โดยองค์ประกอบข้อมูลเดี่ยวจะเป็นรายการขนาด 1 คุณใช้ฟังก์ชันตัวช่วยต่อไปนี้เพื่อจัดเก็บข้อมูลลงใน TFRecord ได้

การเขียนสตริงไบต์

# warning, the input is a list of byte strings, which are themselves lists of bytes
def _bytestring_feature(list_of_bytestrings):
  return tf.train.Feature(bytes_list=tf.train.BytesList(value=list_of_bytestrings))

การเขียนจำนวนเต็ม

def _int_feature(list_of_ints): # int64
  return tf.train.Feature(int64_list=tf.train.Int64List(value=list_of_ints))

การลอยตัวในการเขียน

def _float_feature(list_of_floats): # float32
  return tf.train.Feature(float_list=tf.train.FloatList(value=list_of_floats))

การเขียน TFRecord โดยใช้ตัวช่วยข้างต้น

# input data in my_img_bytes, my_class, my_height, my_width, my_floats
with tf.python_io.TFRecordWriter(filename) as out_file:
  feature = {
    "image": _bytestring_feature([my_img_bytes]), # one image in the list
    "class": _int_feature([my_class]),            # one class in the list
    "size": _int_feature([my_height, my_width]),  # fixed length (2) list of ints
    "float_data": _float_feature(my_floats)       # variable length  list of floats
  }
  tf_record = tf.train.Example(features=tf.train.Features(feature=feature))
  out_file.write(tf_record.SerializeToString())

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

อ่านข้อมูลจาก TFRecord

def read_tfrecord(data):
  features = {
    # tf.string = byte string (not text string)
    "image": tf.io.FixedLenFeature([], tf.string), # shape [] means scalar, here, a single byte string
    "class": tf.io.FixedLenFeature([], tf.int64),  # shape [] means scalar, i.e. a single item
    "size": tf.io.FixedLenFeature([2], tf.int64),  # two integers
    "float_data": tf.io.VarLenFeature(tf.float32)  # a variable number of floats
  }

  # decode the TFRecord
  tf_record = tf.io.parse_single_example(data, features)

  # FixedLenFeature fields are now ready to use
  sz = tf_record['size']

  # Typical code for decoding compressed images
  image = tf.io.decode_jpeg(tf_record['image'], channels=3)

  # VarLenFeature fields require additional sparse.to_dense decoding
  float_data = tf.sparse.to_dense(tf_record['float_data'])

  return image, sz, float_data

# decoding a tf.data.TFRecordDataset
dataset = dataset.map(read_tfrecord)
# now a dataset of triplets (image, sz, float_data)

ข้อมูลโค้ดที่มีประโยชน์

การอ่านองค์ประกอบข้อมูลเดี่ยว

tf.io.FixedLenFeature([], tf.string)   # for one byte string
tf.io.FixedLenFeature([], tf.int64)    # for one int
tf.io.FixedLenFeature([], tf.float32)  # for one float

การอ่านรายการองค์ประกอบที่มีขนาดคงที่

tf.io.FixedLenFeature([N], tf.string)   # list of N byte strings
tf.io.FixedLenFeature([N], tf.int64)    # list of N ints
tf.io.FixedLenFeature([N], tf.float32)  # list of N floats

การอ่านจำนวนตัวแปรของรายการข้อมูล

tf.io.VarLenFeature(tf.string)   # list of byte strings
tf.io.VarLenFeature(tf.int64)    # list of ints
tf.io.VarLenFeature(tf.float32)  # list of floats

VarLenFeature แสดงผลเวกเตอร์บางส่วน และจำเป็นต้องมีขั้นตอนเพิ่มเติมหลังจากถอดรหัส TFRecord ดังนี้

dense_data = tf.sparse.to_dense(tf_record['my_var_len_feature'])

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

tf.io.FixedLenFeature([], tf.int64, default_value=0) # this field is optional

หัวข้อที่ครอบคลุม

  • 🤔 ชาร์ดดิ้งไฟล์ข้อมูลเพื่อเข้าถึงจาก GCS ได้อย่างรวดเร็ว
  • 😓 วิธีเขียน TFRecord (คุณลืมไวยากรณ์แล้วหรือยัง ไม่เป็นไร บุ๊กมาร์กหน้านี้เป็นข้อมูลสรุป)
  • 🤔 กำลังโหลดชุดข้อมูลจาก TFRecord โดยใช้ TFRecordDataset

โปรดใช้เวลาสักครู่เพื่อทบทวนรายการตรวจสอบนี้

6. [INFO] ตัวแยกประเภทโครงข่ายระบบประสาทเทียม 101

สรุป

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

สำหรับโมเดลที่สร้างเป็นลำดับของเลเยอร์ Keras จะมี Sสัมผัสประสบการณ์ API ตัวอย่างเช่น ตัวแยกประเภทรูปภาพที่ใช้เลเยอร์แบบหนาแน่น 3 เลเยอร์สามารถเขียนด้วย Keras ดังนี้

model = tf.keras.Sequential([
    tf.keras.layers.Flatten(input_shape=[192, 192, 3]),
    tf.keras.layers.Dense(500, activation="relu"),
    tf.keras.layers.Dense(50, activation="relu"),
    tf.keras.layers.Dense(5, activation='softmax') # classifying into 5 classes
])

# this configures the training of the model. Keras calls it "compiling" the model.
model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy']) # % of correct answers

# train the model
model.fit(dataset, ... )

688858c21e3beff2.png

โครงข่ายประสาทแบบหนาแน่น

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

c21bae6dade487bc.png

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

ประสาท, การเปิดใช้งาน, RELU

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

644f4213a4ee70e5.png

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

การเปิดใช้งาน Softmax

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

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

ef0d98c0952c262d.png d51252f75894479e.gif

การสูญเสียครอสเอนโทรปี

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

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

7bdf8753d20617fb.png

การไล่ระดับสี

"การฝึก" โครงข่ายประสาทหมายถึงการใช้ภาพและป้ายกำกับการฝึกเพื่อปรับน้ำหนักและน้ำหนัก เพื่อลดฟังก์ชันการสูญเสียครอสเอนโทรปี วิธีการทำงานมีดังนี้

ครอสเอนโทรปีเป็นฟังก์ชันของน้ำหนัก การให้น้ำหนักพิเศษ พิกเซลของรูปภาพที่ใช้ในการฝึก และคลาสที่รู้จัก

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

การไล่ระดับสี 2.png

แบบมินิแบตช์และโมเมนตัม

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

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

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

52e824fe4716c4a0.png

ภาพประกอบ: จุดตัด การไล่ระดับสีมีค่า 0 แต่ไม่ได้มีค่าต่ำสุดในทุกทิศทาง (การระบุแหล่งที่มาของรูปภาพ Wikimedia: โดย Nicoguaro - ผลงานของตัวเอง CC BY 3.0)

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

อภิธานศัพท์

กลุ่มหรือกลุ่มขนาดเล็ก: การฝึกจะดำเนินการกับกลุ่มของข้อมูลและป้ายกำกับการฝึกเสมอ ซึ่งจะช่วยให้อัลกอริทึมบรรจบกัน "กลุ่ม" ตามปกติแล้วเป็นมิติข้อมูลแรกของ Tensor ข้อมูล เช่น Tensor ของรูปร่าง [100, 192, 192, 3] จะมีภาพขนาด 192x192 พิกเซล 100 ภาพที่มี 3 ค่าต่อพิกเซล (RGB)

การสูญเสียการครอสเอนโทรปี: ฟังก์ชันการสูญเสียพิเศษที่มักใช้ในตัวแยกประเภท

ชั้นที่หนาแน่น: ชั้นของเซลล์ประสาทที่เซลล์ประสาทแต่ละเซลล์เชื่อมต่อกับเซลล์ประสาททั้งหมดในชั้นก่อนหน้านี้

features: อินพุตของโครงข่ายประสาทบางครั้งเรียกว่า "ฟีเจอร์" ศิลปะในการพิจารณาว่าส่วนใดของชุดข้อมูล (หรือการรวมส่วนต่างๆ) ที่จะป้อนลงในโครงข่ายระบบประสาทเทียมเพื่อรับการคาดการณ์ที่ดีเรียกว่า "Feature Engineering"

labels: อีกชื่อหนึ่งของ "ชั้นเรียน" หรือคำตอบที่ถูกต้องในโจทย์การจัดประเภทภายใต้การควบคุมดูแล

อัตราการเรียนรู้: เศษส่วนของการไล่ระดับสีที่มีการอัปเดตน้ำหนักและน้ำหนักพิเศษในแต่ละการวนซ้ำการฝึก

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

loss: ฟังก์ชันข้อผิดพลาดที่เปรียบเทียบเอาต์พุตของโครงข่ายระบบประสาทเทียมกับคำตอบที่ถูกต้อง

เซลล์ประสาท: คำนวณผลรวมถ่วงน้ำหนักของอินพุต จะเพิ่มการให้น้ำหนักพิเศษ และป้อนผลลัพธ์ผ่านฟังก์ชันการเปิดใช้งาน

การเข้ารหัสแบบ One-Hot: คลาส 3 จาก 5 ได้รับการเข้ารหัสเป็นเวกเตอร์ขององค์ประกอบ 5 โดยค่า 0 ทั้งหมดยกเว้นค่าตัวที่ 3 ซึ่งก็คือ 1

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

sigmoid: ฟังก์ชันเปิดใช้งานอีกอย่างที่เคยได้รับความนิยมและยังคงมีประโยชน์ในกรณีพิเศษ

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

tensor: A "tensor" คล้ายกับเมทริกซ์ แต่มีจำนวนมิติข้อมูลที่กำหนดเอง tensor 1 มิติคือเวกเตอร์ Tensor 2 มิติคือเมทริกซ์ และจากนั้นคุณสามารถมี Tensor ที่มีมิติข้อมูล 3, 4, 5 หรือมากกว่าได้

7. ถ่ายทอดการเรียนรู้

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

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

การลงมือปฏิบัติ

โปรดเปิดสมุดบันทึกต่อไปนี้ เรียกใช้เซลล์ (Shift-ENTER) และทำตามคำแนะนำที่เห็นข้อความ "ต้องดำเนินการ" ป้ายกำกับ

c3df49e90e5a654f.png Keras Flowers transfer learning (playground).ipynb

ข้อมูลเพิ่มเติม

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

b8fc1efd2001f072.png

ภาพ: โครงข่ายระบบประสาทเทียมแบบ Convolutional ที่ซับซ้อน ซึ่งได้รับการฝึกแล้ว ให้เป็นกล่องดำ โดยฝึกเฉพาะหัวการจัดประเภทอีกครั้ง นี่คือการโอนการเรียนรู้ เราจะดูว่าการจัดเรียงเลเยอร์คอนโวลูชัน (Convolutional) ที่ซับซ้อนเหล่านี้ทำงานอย่างไรในภายหลัง ส่วนตอนนี้ปัญหามันเป็นของคนอื่น

โอนการเรียนรู้ใน Keras

ใน Keras คุณสามารถสร้างอินสแตนซ์โมเดลก่อนการฝึกจากคอลเล็กชัน tf.keras.applications.* ตัวอย่างเช่น MobileNet V2 เป็นสถาปัตยกรรมแบบ Convolution ที่ดีมาก แต่ยังคงขนาดเหมาะสม เมื่อเลือก include_top=False คุณจะได้รับโมเดลที่ฝึกล่วงหน้าโดยไม่มีเลเยอร์ Softmax ขั้นสุดท้ายของโมเดล คุณจึงเพิ่มโมเดลของตัวเองได้

pretrained_model = tf.keras.applications.MobileNetV2(input_shape=[*IMAGE_SIZE, 3], include_top=False)
pretrained_model.trainable = False

model = tf.keras.Sequential([
    pretrained_model,
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(5, activation='softmax')
])

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

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

วิธีนี้น่าจะมีความแม่นยำเกือบ 75%

โซลูชัน

นี่คือสมุดบันทึกโซลูชัน คุณสามารถใช้รหัสผ่านนี้ได้หากติดขัด

c3df49e90e5a654f.png Keras Flowers transfer learning (solution).ipynb

หัวข้อที่ครอบคลุม

  • 🤔 วิธีเขียนตัวแยกประเภทใน Keras
  • 🤓 กำหนดค่าด้วยเลเยอร์สุดท้ายของซอฟต์แม็กซ์ และการสูญเสียครอสเอนโทรปี
  • 😈 ถ่ายทอดการเรียนรู้
  • 🤔 ฝึกโมเดลแรก
  • 🧐 หลังการสูญเสียและความถูกต้องแม่นยำระหว่างการฝึก

โปรดใช้เวลาสักครู่เพื่อทบทวนรายการตรวจสอบนี้

8. [INFO] โครงข่ายระบบประสาทเทียมแบบ Convolutional

สรุป

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

convolutional.gif

ภาพประกอบ: การกรองรูปภาพด้วยฟิลเตอร์ต่อเนื่อง 2 รายการซึ่งมีน้ำหนัก 4x4x3=48 ที่เรียนรู้ได้ แต่ละตัวกรอง

นี่คือลักษณะของโครงข่ายประสาทแบบคอนโวลูชัน (Convolutional) แบบง่ายๆ ใน Keras

model = tf.keras.Sequential([
  # input: images of size 192x192x3 pixels (the three stands for RGB channels)
  tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu', input_shape=[192, 192, 3]),
  tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=12, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=6, padding='same', activation='relu'),
  tf.keras.layers.Flatten(),
  # classifying into 5 categories
  tf.keras.layers.Dense(5, activation='softmax')
])

model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy'])

688858c21e3beff2.png

โครงข่ายประสาทแบบ Convolutional 101

ในเลเยอร์ของเครือข่ายคอนโวลูชัน (Convolutional Network) จะมี "เซลล์ประสาท" 1 เซลล์ เป็นผลรวมถ่วงน้ำหนักของพิกเซลที่อยู่ด้านบนในพื้นที่เล็กๆ ของภาพเท่านั้น เซลล์นี้จะเพิ่มการให้น้ำหนักพิเศษและป้อนผลรวมผ่านฟังก์ชันเปิดใช้งาน เช่นเดียวกับที่เซลล์ประสาทในชั้นที่หนาแน่นปกติสามารถทำ การดำเนินการนี้จะทำซ้ำในทั้งรูปภาพโดยใช้น้ำหนักเดียวกัน อย่าลืมว่าในชั้นที่หนาแน่น เซลล์ประสาทแต่ละเซลล์มีน้ำหนักของตัวเอง ตรงนี้ เรามี "การแก้ไข" เพียงครั้งเดียว ของน้ำหนักที่เลื่อนผ่านภาพทั้ง 2 ทิศทาง ("Conversion") เอาต์พุตจะมีค่าเท่ากับจำนวนพิกเซลในรูปภาพ (แต่ต้องมีระยะห่างจากขอบบางจุด) เป็นการดำเนินการกรองโดยใช้ตัวกรองน้ำหนัก 4x4x3=48

อย่างไรก็ตาม น้ำหนัก 48 อาจไม่เพียงพอ หากต้องการเพิ่มองศาอิสระ เราจะดำเนินการซ้ำเดิมด้วยน้ำหนักชุดใหม่ ซึ่งจะสร้างเอาต์พุตตัวกรองชุดใหม่ ขอเรียกว่า "ช่อง" ของเอาต์พุตโดยการเปรียบเทียบกับช่อง R,G,B ในภาพอินพุต

Screen Shot 29-07-2016 ที่ 16.02.37.png

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

d1b557707bcd1cb9.png

ภาพ: โครงข่ายประสาทแบบคอนโวลูชัน (Convolutional) เปลี่ยนรูปแบบ "ลูกบาศก์" ของข้อมูลลงใน "ลูกบาศก์" อื่นๆ อีกด้วย

คอนโวลูชันแบบมีโครงสร้าง การรวมกันสูงสุด

การทำ Conversion ด้วยระยะก้าว 2 หรือ 3 ช่วยให้เราย่อลูกบาศก์ข้อมูลที่ได้ให้อยู่ในขนาดแนวนอนได้ วิธีทั่วไปมี 2 วิธีดังนี้

  • Strided Convolution: ตัวกรองแบบเลื่อนตามด้านบนแต่มีระยะก้าว >1
  • การรวมกลุ่มสูงสุด: หน้าต่างเลื่อนที่ใช้การดำเนินการ MAX (โดยปกติจะเป็นแพตช์ 2x2 ทำซ้ำทุก 2 พิกเซล)

2b2d4263bb8470b.gif

ภาพ: การเลื่อนหน้าต่างการประมวลผลทีละ 3 พิกเซลจะทำให้ค่าเอาต์พุตลดลง Convolution ระยะก้าวหรือการรวมกันสูงสุด (สูงสุดในการเลื่อนหน้าต่างขนาด 2x2 ด้วยระยะก้าวที่ 2) เป็นวิธีย่อลูกบาศก์ข้อมูลในขนาดแนวนอน

ตัวแยกประเภทเชิงปฏิสัมพันธ์

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

4a61aaffb6cba3d1.png

ภาพ: ตัวแยกประเภทรูปภาพที่ใช้เลเยอร์ Convolutional และ softmax ใช้ตัวกรอง 3x3 และ 1x1 โดยเลเยอร์สูงสุดคือกลุ่มจุดข้อมูลขนาด 2x2 ส่วนหัวการแยกประเภทมีการใช้งานด้วยเลเยอร์ที่หนาแน่นที่มีการเปิดใช้งาน Softmax

ใน Keras

สแต็ก Convolutional ที่แสดงด้านบนสามารถเขียนด้วยภาษา Keras ดังนี้

model = tf.keras.Sequential([
  # input: images of size 192x192x3 pixels (the three stands for RGB channels)    
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu', input_shape=[192, 192, 3]),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=16, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=8, padding='same', activation='relu'),
  tf.keras.layers.Flatten(),
  # classifying into 5 categories
  tf.keras.layers.Dense(5, activation='softmax')
])

model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy'])

9. Convnet ที่กําหนดเอง

การลงมือปฏิบัติ

ให้เราสร้างและฝึกโครงข่ายประสาทแบบ Convolutional ตั้งแต่เริ่มต้น การใช้ TPU จะช่วยให้เราปรับปรุงได้เร็วขึ้น โปรดเปิดสมุดบันทึกต่อไปนี้ เรียกใช้เซลล์ (Shift-ENTER) และทำตามคำแนะนำที่เห็นข้อความ "ต้องดำเนินการ" ป้ายกำกับ

c3df49e90e5a654f.png Keras_Flowers_TPU (playground).ipynb

เป้าหมายคือการเอาชนะความแม่นยำ 75% ของโมเดลการเรียนรู้การโอน โมเดลนี้มีข้อดีคือได้รับการฝึกล่วงหน้าด้วยชุดข้อมูลของรูปภาพหลายล้านรูป แต่ที่นี่เรามีรูปภาพเพียง 3, 670 รูป อย่างน้อยคุณจับคู่ได้ไหม

ข้อมูลเพิ่มเติม

มีกี่เลเยอร์ ใหญ่แค่ไหน

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

Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 192, 192, 16)      448       
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 192, 192, 30)      4350      
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 96, 96, 30)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 96, 96, 60)        16260     
_________________________________________________________________
 ... 
_________________________________________________________________
global_average_pooling2d (Gl (None, 130)               0         
_________________________________________________________________
dense (Dense)                (None, 90)                11790     
_________________________________________________________________
dense_1 (Dense)              (None, 5)                 455       
=================================================================
Total params: 300,033
Trainable params: 300,033
Non-trainable params: 0
_________________________________________________________________

เคล็ดลับ 2 ข้อมีดังนี้

  • การมีเลเยอร์หลายชั้นทำให้ "ดูลึก" โครงข่ายประสาทที่มีประสิทธิภาพ สำหรับปัญหาการจดจำดอกไม้ง่ายๆ นี้ ควรใช้ 5 ถึง 10 เลเยอร์ซึ่งเหมาะสมที่สุด
  • ใช้ตัวกรองขนาดเล็ก ปกติแล้วตัวกรอง 3x3 จะใช้ได้ในทุกที่
  • ฟิลเตอร์ 1x1 ก็ใช้ได้เช่นกันและมีราคาถูก แต่ไม่ได้ "กรอง" จริงๆ ยกเว้นการคำนวณ การผสมแชแนลเชิงเส้น สลับผู้ชมด้วยฟิลเตอร์จริง (ดูข้อมูลเพิ่มเติมเกี่ยวกับ "Convolutions 1x1" ได้ในส่วนถัดไป)
  • สำหรับปัญหาการจัดประเภทเช่นนี้ การลดลงของตัวอย่างมักมีเลเยอร์พูลสูงสุด (หรือคอนโวลูชันที่มีระยะก้าว >1) คุณไม่จำเป็นต้องสนใจว่าดอกไม้อยู่ตรงไหน เพียงแค่เป็นดอกกุหลาบหรือดอกแดนดิไลออน การสูญเสียข้อมูล x และ y ก็ไม่สำคัญ และการกรองพื้นที่เล็กๆ จะมีราคาถูกกว่า
  • โดยทั่วไปจำนวนตัวกรองจะใกล้เคียงกับจำนวนคลาสเมื่อสิ้นสุดเครือข่าย (เพราะเหตุใด ลองดูเคล็ดลับ "การรวมค่าเฉลี่ยทั่วโลก" ด้านล่าง) หากคุณแยกประเภทเป็นหลายร้อยคลาส ให้เพิ่มจำนวนตัวกรองทีละน้อยในเลเยอร์ที่ต่อเนื่องกัน สำหรับชุดข้อมูลดอกไม้ที่มี 5 คลาส การกรองด้วยตัวกรองเพียง 5 รายการจึงไม่เพียงพอ คุณสามารถใช้จำนวนตัวกรองเดียวกันในเลเยอร์ส่วนใหญ่ เช่น 32 และลดจำนวนเลเยอร์ลงในตอนท้าย
  • ชั้นที่หนาแน่นสุดท้ายมีราคาสูง อาจมีน้ำหนักมากกว่าชั้นคอนโวลูชัน (Convolutional) ทั้งหมดรวมกัน ตัวอย่างเช่น แม้ว่าจะมีผลลัพธ์ที่สมเหตุสมผลมากจากจุดข้อมูลขนาด 24x24x10 รายการสุดท้าย แต่เลเยอร์ความหนาแน่นของเซลล์ประสาท 100 เลเยอร์จะมีค่าใช้จ่าย 24x24x10x100=น้ำหนัก 576,000 !!! โปรดใช้ความรอบคอบ หรือลองรวบรวมข้อมูลเฉลี่ยทั่วโลก (ดูด้านล่าง)

การรวมเฉลี่ยทั่วโลก

คุณสามารถแยก "ลูกบาศก์" ของข้อมูลที่เข้ามาใหม่ แทนที่จะใช้ชั้นที่มีความหนาแน่นราคาแพงที่ตอนท้ายของโครงข่ายระบบประสาทเทียมแบบ Convolutional แบ่งเป็นส่วนต่างๆ ตามคลาสที่คุณมี หาค่าเฉลี่ยและค่าฟีดเหล่านี้ด้วยฟังก์ชันการเปิดใช้งาน softmax วิธีสร้างส่วนหัวการแยกประเภทในลักษณะนี้จะมีน้ำหนักเป็น 0 ใน Keras ไวยากรณ์คือ tf.keras.layers.GlobalAveragePooling2D().

93240029f59df7c2.png

โซลูชัน

นี่คือสมุดบันทึกโซลูชัน คุณสามารถใช้รหัสผ่านนี้ได้หากติดขัด

c3df49e90e5a654f.png Keras_Flowers_TPU (solution).ipynb

หัวข้อที่ครอบคลุม

  • 🤔 เล่นกับเลเยอร์คอนโวลูชัน (Convolutional)
  • 🤓 ทดสอบกับการรวมกลุ่มสูงสุด ก้าวเดิน การรวมกลุ่มค่าเฉลี่ยทั่วโลก ...
  • 😀 ทำซ้ำบนโมเดลในชีวิตจริงได้อย่างรวดเร็วบน TPU

โปรดใช้เวลาสักครู่เพื่อทบทวนรายการตรวจสอบนี้

10. [INFO] สถาปัตยกรรมคอนโวลูชันสมัยใหม่

สรุป

7968830b57b708c0.png

ภาพ: "โมดูล" Convolutional อะไรคือวิธีที่ดีที่สุดในจุดนี้ เลเยอร์พูลสูงสุดตามด้วยเลเยอร์ Convolutional 1x1 หรือเลเยอร์หลายๆ แบบรวมกัน ลองทดสอบทั้งหมด เชื่อมโยงผลลัพธ์ แล้วปล่อยให้เครือข่ายตัดสินใจ ทางด้านขวา: " inception" สถาปัตยกรรมแบบ Convolution ที่ใช้โมดูลดังกล่าว

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

l = tf.keras.layers # syntax shortcut

y = l.Conv2D(filters=32, kernel_size=3, padding='same',
             activation='relu', input_shape=[192, 192, 3])(x) # x=input image

# module start: branch out
y1 = l.Conv2D(filters=32, kernel_size=1, padding='same', activation='relu')(y)
y3 = l.Conv2D(filters=32, kernel_size=3, padding='same', activation='relu')(y)
y = l.concatenate([y1, y3]) # output now has 64 channels
# module end: concatenation

# many more layers ...

# Create the model by specifying the input and output tensors.
# Keras layers track their connections automatically so that's all that's needed.
z = l.Dense(5, activation='softmax')(y)
model = tf.keras.Model(x, z)

688858c21e3beff2.png

เคล็ดลับการใช้ราคาถูกอื่นๆ

ฟิลเตอร์ขนาดเล็ก 3x3

40a7b15fb7dbe75c.png

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

คอนโวลูชัน 1x1

fd7cac16f8ecb423.png

ในทางคณิตศาสตร์ "1x1" Convolution เป็นการคูณกับค่าคงที่ ไม่ใช่แนวคิดที่เป็นประโยชน์มาก อย่างไรก็ตาม ในโครงข่ายระบบประสาทเทียมแบบ Convolutional อย่าลืมว่าตัวกรองนั้นจะใช้กับ Data Cube ไม่ใช่แค่ภาพ 2 มิติเท่านั้น ดังนั้น "1x1" ตัวกรองจะคำนวณผลรวมถ่วงน้ำหนักของคอลัมน์ข้อมูลขนาด 1x1 (ดูภาพประกอบ) และเมื่อคุณเลื่อนไปยังข้อมูล คุณจะได้พบกับชุดค่าผสมของแชแนลต่างๆ ของอินพุตแบบเชิงเส้น ซึ่งมีประโยชน์จริงๆ หากคุณคิดว่าแชแนลเป็นผลลัพธ์ของการดำเนินการกรองแต่ละรายการ เช่น ตัวกรองสำหรับ "หูชี้" อีกตัวกรองหนึ่งสำหรับ "เส้นหนวด" ชิ้นที่ 3 สำหรับ "ตากรีด" ตามด้วย "1x1" ชั้น Convolutional จะคํานวณชุดค่าผสมเชิงเส้นที่เป็นไปได้ของฟีเจอร์เหล่านี้ ซึ่งอาจเป็นประโยชน์เมื่อค้นหา "แมว" นอกจากนี้ เลเยอร์ 1x1 ยังใช้น้ำหนักน้อยกว่าอีกด้วย

11. แบบบีบ

วิธีง่ายๆ ในการรวบรวมไอเดียเหล่านี้เข้าด้วยกันได้รับการแสดงไว้ใน "Squeezenet" กระดาษ ผู้เขียนแนะนำการออกแบบโมดูล Convolutional ที่เรียบง่ายมาก โดยใช้เพียงเลเยอร์คอนโวลูชัน 1x1 และ 3x3 เท่านั้น

1730ac375379269b.png

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

การลงมือปฏิบัติ

ดำเนินการต่อในสมุดบันทึกก่อนหน้าและสร้างโครงข่ายระบบประสาทเทียมแบบ Convolutional แบบบีบ คุณจะต้องเปลี่ยนรหัสโมเดลเป็น "ลักษณะการใช้งาน" ของ Keras

c3df49e90e5a654f.png Keras_Flowers_TPU (playground).ipynb

ข้อมูลเพิ่มเติม

การกำหนดฟังก์ชันตัวช่วยสำหรับโมดูลรีดน้ำจะเป็นประโยชน์สำหรับแบบฝึกหัดนี้ ดังนี้

def fire(x, squeeze, expand):
  y = l.Conv2D(filters=squeeze, kernel_size=1, padding='same', activation='relu')(x)
  y1 = l.Conv2D(filters=expand//2, kernel_size=1, padding='same', activation='relu')(y)
  y3 = l.Conv2D(filters=expand//2, kernel_size=3, padding='same', activation='relu')(y)
  return tf.keras.layers.concatenate([y1, y3])

# this is to make it behave similarly to other Keras layers
def fire_module(squeeze, expand):
  return lambda x: fire(x, squeeze, expand)

# usage:
x = l.Input(shape=[192, 192, 3])
y = fire_module(squeeze=24, expand=48)(x) # typically, squeeze is less than expand
y = fire_module(squeeze=32, expand=64)(y)
...
model = tf.keras.Model(x, y)

เป้าหมายในครั้งนี้คือทำให้ได้ความถูกต้อง 80%

สิ่งที่ควรลอง

เริ่มต้นด้วยเลเยอร์ Convolutional ชั้นเดียว จากนั้นตามด้วย "fire_modules" สลับกับเลเยอร์ MaxPooling2D(pool_size=2) คุณสามารถทดสอบเลเยอร์ในการรวมกลุ่มสูงสุด 2 ถึง 4 เลเยอร์ในเครือข่าย และยังมีโมดูลการเริ่มทำงานต่อเนื่องกัน 1, 2 หรือ 3 เลเยอร์ระหว่างเลเยอร์ร่วมสูงสุดได้อีกด้วย

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

มีตัวอย่างดังต่อไปนี้

x = tf.keras.layers.Input(shape=[*IMAGE_SIZE, 3]) # input is 192x192 pixels RGB

y = tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu')(x)
y = fire_module(24, 48)(y)
y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
y = fire_module(24, 48)(y)
y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
y = fire_module(24, 48)(y)
y = tf.keras.layers.GlobalAveragePooling2D()(y)
y = tf.keras.layers.Dense(5, activation='softmax')(y)

model = tf.keras.Model(x, y)

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

การปรับให้เป็นมาตรฐานแบบกลุ่ม

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

y = tf.keras.layers.BatchNormalization(momentum=0.9)(y)
# please adapt the input and output "y"s to whatever is appropriate in your context

พารามิเตอร์โมเมนตัมจะต้องลดลงจากค่าเริ่มต้น 0.99 เป็น 0.9 เนื่องจากชุดข้อมูลมีขนาดเล็ก ยังไม่ต้องสนใจรายละเอียดนี้

การเสริมข้อมูล

คุณจะได้รับจุดเปอร์เซ็นต์เพิ่มขึ้นอีก 2-3 เปอร์เซ็นต์โดยการเพิ่มข้อมูลด้วยการเปลี่ยนรูปแบบที่ทำได้ง่ายๆ เช่น การพลิกความอิ่มตัวแบบซ้าย-ขวา ดังนี้

4ed2958e09b487ca.png

ad795b70334e0d6b.png

ซึ่งทำได้ง่ายมากใน Tensorflow ด้วย tf.data.Dataset API กำหนดฟังก์ชันการเปลี่ยนรูปแบบใหม่สำหรับข้อมูลของคุณ

def data_augment(image, label):
    image = tf.image.random_flip_left_right(image)
    image = tf.image.random_saturation(image, lower=0, upper=2)
    return image, label

จากนั้นใช้ในการเปลี่ยนรูปแบบข้อมูลขั้นสุดท้าย (เซลล์ "ชุดข้อมูลการฝึกและการตรวจสอบ", ฟังก์ชัน "get_batched_dataset"):

dataset = dataset.repeat() # existing line
# insert this
if augment_data:
  dataset = dataset.map(data_augment, num_parallel_calls=AUTO)
dataset = dataset.shuffle(2048) # existing line

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

ตอนนี้ความแม่นยํา 80% ใน 35 Epoch ควรอยู่แค่เอื้อม

โซลูชัน

นี่คือสมุดบันทึกโซลูชัน คุณสามารถใช้รหัสผ่านนี้ได้หากติดขัด

c3df49e90e5a654f.png Keras_Flowers_TPU_squeezenet.ipynb

หัวข้อที่ครอบคลุม

  • 🤔 Keras "สไตล์การใช้งาน" รุ่น
  • 🤓 สถาปัตยกรรม Squeezenet
  • 🤓 การเสริมข้อมูลด้วย tf.data.datset

โปรดใช้เวลาสักครู่เพื่อทบทวนรายการตรวจสอบนี้

12. การปรับแต่ง Xception

คอนโวลูชันแบบแยกแยะได้

เมื่อไม่นานมานี้ การใช้เลเยอร์คอนโวลูชัน (Convolutional) วิธีนี้ได้รับความนิยมไม่มาก นั่นก็คือ Convolution ที่แยกความลึกได้ พูดง่ายๆ ก็คือพูดง่ายๆ แต่แนวคิดนี้ค่อนข้างเรียบง่าย โดยติดตั้งใช้งานใน Tensorflow และ Keras เป็น tf.keras.layers.SeparableConv2D

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

615720b803bf8dda.gif

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

Convolution ที่แยกกันได้นั้นใช้ในสถาปัตยกรรมเครือข่าย Convolutional ล่าสุด ซึ่งได้แก่ MobileNetV2, Xception, EfficientNet ลืมบอกไปว่า MobileNetV2 เป็นฟีเจอร์ที่คุณใช้เพื่อโอนการเรียนรู้ไปก่อนหน้านี้

โดยมีค่าใช้จ่ายที่ถูกกว่าคอนโวลูชันทั่วไป (Convolution) ทั่วไปและพบว่ามีประสิทธิผลพอๆ กันในทางปฏิบัติ น้ำหนักของตัวอย่างที่แสดงด้านบนมีดังนี้

ชั้น Convolution: 4 x 4 x 3 x 5 = 240

ชั้น Convolutional ที่แยกกันได้: 4 x 4 x 3 + 3 x 5 = 48 + 15 = 63

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

การลงมือปฏิบัติ

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

c3df49e90e5a654f.png Keras Flowers transfer learning (playground).ipynb

เป้าหมาย: ความแม่นยำ > 95% (ไม่ เป็นไปได้จริงๆ)

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

ข้อมูลเพิ่มเติมเกี่ยวกับการปรับแต่ง

Xception มีอยู่ในโมเดลมาตรฐานก่อนการฝึกใน tf.keras.application* อย่าลืมทิ้งน้ำหนักที่ฝึกได้ทั้งหมดในครั้งนี้

pretrained_model = tf.keras.applications.Xception(input_shape=[*IMAGE_SIZE, 3],
                                                  include_top=False)
pretrained_model.trainable = True

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

9b1af213b2b36d47.png

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

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

def lr_fn(epoch):
  lr = ...
  return lr

lr_callback = tf.keras.callbacks.LearningRateScheduler(lr_fn, verbose=True)

model.fit(..., callbacks=[lr_callback])

โซลูชัน

นี่คือสมุดบันทึกโซลูชัน คุณสามารถใช้รหัสผ่านนี้ได้หากติดขัด

c3df49e90e5a654f.png 07_Keras_Flowers_TPU_xception_fine_tuned_best.ipynb

หัวข้อที่ครอบคลุม

  • 🤔 คอนโวลูชัน (Convolution) ที่แยกความลึกได้
  • 🤓 ตารางอัตราการเรียนรู้
  • 😈 ปรับแต่งโมเดลก่อนการฝึก

โปรดใช้เวลาสักครู่เพื่อทบทวนรายการตรวจสอบนี้

13. ยินดีด้วย

คุณได้สร้างโครงข่ายระบบประสาทเทียมแบบคอนโวลูชัน (Convolutional) ที่ทันสมัยแห่งแรกและฝึกให้เครือข่ายมีความแม่นยำมากกว่า 90% โดยสามารถดำเนินการซ้ำแบบฝึกต่อเนื่องได้ในไม่กี่นาทีด้วย TPU

TPU ในทางปฏิบัติ

TPU และ GPU พร้อมใช้งานใน Vertex AI ของ Google Cloud ดังนี้

สุดท้ายนี้ เราให้ความสำคัญกับความคิดเห็น โปรดแจ้งให้เราทราบ หากคุณพบสิ่งที่ควรปรับปรุงในห้องทดลองนี้ หรือคุณคิดว่าเราควรปรับปรุง คุณแสดงความคิดเห็นได้ผ่านปัญหาเกี่ยวกับ GitHub [ feedback link]

HR.png

Martin Görner ID large.jpg
ผู้เขียน: Martin Görner
Twitter: @martin_gorner