ไปป์ไลน์ข้อมูลความเร็ว TPU: tf.data.Dataset และ TFRecords

1. ภาพรวม

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

แล็บนี้เป็นส่วนที่ 1 ของชุด "Keras บน TPU" คุณจะทำตามลำดับต่อไปนี้หรือจะทำแยกกันก็ได้

ca8cc21f6838eccc.png

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

  • หากต้องการใช้ tf.data.Dataset API เพื่อโหลดข้อมูลการฝึก
  • หากต้องการใช้รูปแบบ TFRecord เพื่อโหลดข้อมูลการฝึกจาก GCS อย่างมีประสิทธิภาพ

ความคิดเห็น

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

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

โดยแล็บนี้ใช้ Google Collaboratory และคุณไม่จำเป็นต้องตั้งค่าใดๆ Colaboratory เป็นแพลตฟอร์มสมุดบันทึกออนไลน์เพื่อการศึกษา โดยมีหลักสูตรการฝึกอบรม CPU, GPU และ TPU ฟรี

688858c21e3beff2.png

คุณสามารถเปิด Notebook ตัวอย่างนี้และเรียกใช้ 2-3 เซลล์เพื่อทำความคุ้นเคยกับ Colaboratory

c3df49e90e5a654f.png Welcome to Colab.ipynb

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

8832c6208c99687d.png

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

การดำเนินการ Notebook

76d05caa8b4db6da.png

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

สารบัญ

429f106990037ec4.png

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

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

edc3dba45d26f12a.png

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

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

cdd4b41413100543.png

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

8eb3e718b8e2ed08.png

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

ฮาร์ดแวร์

MXU และ VPU

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

7d68944718f76b18.png

จุดลอยแบบความแม่นยำผสมและ bfloat16

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

19c5fc432840c714.png

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

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

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

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 สามารถติดตั้งใช้งานได้ถึง 16,000 รายการใน MXU ขนาด 128x128 และประมวลผลการคูณเมทริกซ์นี้ได้ในครั้งเดียว

f1b283fc45966717.gif

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

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

Cloud TPU

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

dfce5522ed644ece.png

ภาพประกอบ: VM ของคุณที่มีตัวเร่ง "Cloud TPU" ที่เชื่อมต่อกับเครือข่าย "Cloud TPU" เองประกอบด้วย VM ที่มีบอร์ด TPU ที่เชื่อมต่อ PCI ซึ่งมีชิป TPU แบบดูอัลคอร์ 4 ตัว

พ็อด TPU

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

2ec1e0d341e7fc34.jpeg

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

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

d97b9cc5d40fdb1d.gif

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

ซอฟต์แวร์

การฝึกที่มีขนาดกลุ่มใหญ่

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

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

da534407825f01e3.png

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

กลไกภายใน: XLA

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

edce61112cd57972.png

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

การใช้ TPU ใน Keras

TPU รองรับผ่าน Keras API ตั้งแต่ TensorFlow 2.1 เป็นต้นไป การรองรับ Keras ใช้ได้กับ TPU และ TPU Pod ต่อไปนี้คือตัวอย่างที่ใช้ได้กับ 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 เป็นส่วนที่ใช้การกระจายและอัลกอริทึมการซิงค์การไล่ระดับสี "all-reduce"
  • กลยุทธ์นี้ใช้ผ่านขอบเขต ต้องกำหนดโมเดลภายในขอบเขตกลยุทธ์()
  • ฟังก์ชัน tpu_model.fit ต้องการออบเจ็กต์ tf.data.Dataset เป็นอินพุตสำหรับการฝึก TPU

งานทั่วไปในการพอร์ต TPU

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

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

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

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

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

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

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

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

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

ชุดข้อมูลจัดระเบียบไว้ใน 5 โฟลเดอร์ แต่ละโฟลเดอร์จะมีดอกไม้ 1 ชนิด โฟลเดอร์มีชื่อว่า sunflowers, daisy, dandelion, tulips และ roses โดยข้อมูลจะโฮสต์อยู่ใน Bucket สาธารณะใน 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)

ชุดข้อมูลของทูเพิล

ในการเรียนรู้แบบมีผู้ดูแล ชุดข้อมูลการฝึกมักประกอบด้วยคู่ของข้อมูลการฝึกและคำตอบที่ถูกต้อง หากต้องการอนุญาตให้ทำเช่นนี้ ฟังก์ชันการถอดรหัสจะแสดงผลเป็นทูเพิลได้ จากนั้นคุณจะมีชุดข้อมูลของ Tuple และระบบจะแสดง Tuple เมื่อคุณทำซ้ำในชุดข้อมูล ค่าที่ส่งคืนคือเทนเซอร์ TensorFlow ที่พร้อมให้โมเดลของคุณใช้ คุณเรียกใช้ .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 รูปต่อวินาที ช้าเกินไป ตัวเร่งฮาร์ดแวร์ที่เราจะใช้ในการฝึกสามารถรองรับอัตรานี้ได้หลายเท่า ไปที่ส่วนถัดไปเพื่อดูวิธีที่เราจะทำสิ่งนี้ให้สำเร็จ

Solution

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

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

สิ่งที่เราได้พูดถึง

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

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

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

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

การอ่านบท

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

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'])

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

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

สิ่งที่เราได้พูดถึง

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

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

6. ยินดีด้วย

ตอนนี้คุณป้อนข้อมูลให้กับ TPU ได้แล้ว โปรดไปที่แล็บถัดไป

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

TPU และ GPU พร้อมให้บริการใน Cloud AI Platform

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

HR.png

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