กำลังย้ายข้อมูลการใช้งาน tf.summary ไปยัง TF 2.x

ดูบน TensorFlow.org ทำงานใน Google Colab ดูแหล่งที่มาบน GitHub ดาวน์โหลดโน๊ตบุ๊ค
import tensorflow as tf

TensorFlow 2.x รวมถึงการเปลี่ยนแปลงที่สำคัญในการ tf.summary API ที่ใช้ในการเขียนข้อมูลสรุปสำหรับการแสดงใน TensorBoard

สิ่งที่เปลี่ยนไป

มันมีประโยชน์ที่จะคิดว่าของ tf.summary API เป็นย่อยสอง APIs:

  • ชุดปฏิบัติการสำหรับการบันทึกสรุปของแต่ละบุคคล - summary.scalar() , summary.histogram() , summary.image() , summary.audio() และ summary.text() - ซึ่งจะเรียกว่าอินไลน์จากโค้ดรูปแบบของคุณ
  • ตรรกะการเขียนที่รวบรวมบทสรุปแต่ละรายการเหล่านี้และเขียนลงในล็อกไฟล์ที่มีรูปแบบพิเศษ (ซึ่ง TensorBoard จะอ่านเพื่อสร้างการแสดงข้อมูล)

ใน TF 1.x

ทั้งสองส่วนได้ที่จะสายด้วยตนเองร่วมกัน - โดยการเรียกผลสรุป op ผ่าน Session.run() และเรียก FileWriter.add_summary(output, step) v1.summary.merge_all() op ทำนี้ได้ง่ายขึ้นโดยใช้คอลเลกชันกราฟเพื่อรวมทุกผลสรุป op แต่วิธีการนี้ยังคงทำงานได้ไม่ดีสำหรับการดำเนินการความกระตือรือร้นและการควบคุมการไหลทำให้มันโดยเฉพาะอย่างยิ่งไม่เหมาะสำหรับ TF 2.x.

ใน TF 2.X

ทั้งสองส่วนมีการบูรณาการอย่างแน่นหนาและตอนนี้แต่ละ tf.summary Ops เขียนข้อมูลของพวกเขาทันทีเมื่อดำเนินการ การใช้ API จากโค้ดโมเดลของคุณน่าจะยังดูคุ้นเคย แต่ตอนนี้มันเป็นมิตรกับการดำเนินการที่กระตือรือร้นในขณะที่ยังคงเข้ากันได้กับโหมดกราฟ การบูรณาการทั้งสองของ API หมายถึง summary.FileWriter ตอนนี้เป็นส่วนหนึ่งของการดำเนินการบริบท TensorFlow และได้รับการเข้าถึงได้โดยตรงโดย tf.summary Ops ดังนั้นนักเขียนกำหนดค่าเป็นส่วนหลักที่ลักษณะแตกต่างกัน

ตัวอย่างการใช้งานด้วยการดำเนินการอย่างกระตือรือร้น ค่าเริ่มต้นใน TF 2.x:

writer = tf.summary.create_file_writer("/tmp/mylogs/eager")

with writer.as_default():
  for step in range(100):
    # other model code would go here
    tf.summary.scalar("my_metric", 0.5, step=step)
    writer.flush()
ls /tmp/mylogs/eager
events.out.tfevents.1633086727.kokoro-gcp-ubuntu-prod-1386032077.31590.0.v2

ตัวอย่างการใช้งานด้วยการดำเนินการกราฟ tf.function:

writer = tf.summary.create_file_writer("/tmp/mylogs/tf_function")

@tf.function
def my_func(step):
  with writer.as_default():
    # other model code would go here
    tf.summary.scalar("my_metric", 0.5, step=step)

for step in tf.range(100, dtype=tf.int64):
  my_func(step)
  writer.flush()
ls /tmp/mylogs/tf_function
events.out.tfevents.1633086728.kokoro-gcp-ubuntu-prod-1386032077.31590.1.v2

ตัวอย่างการใช้งานกับการประมวลผลกราฟ TF 1.x แบบเดิม:

g = tf.compat.v1.Graph()
with g.as_default():
  step = tf.Variable(0, dtype=tf.int64)
  step_update = step.assign_add(1)
  writer = tf.summary.create_file_writer("/tmp/mylogs/session")
  with writer.as_default():
    tf.summary.scalar("my_metric", 0.5, step=step)
  all_summary_ops = tf.compat.v1.summary.all_v2_summary_ops()
  writer_flush = writer.flush()


with tf.compat.v1.Session(graph=g) as sess:
  sess.run([writer.init(), step.initializer])

  for i in range(100):
    sess.run(all_summary_ops)
    sess.run(step_update)
    sess.run(writer_flush)
ls /tmp/mylogs/session
events.out.tfevents.1633086728.kokoro-gcp-ubuntu-prod-1386032077.31590.2.v2

กำลังแปลงรหัสของคุณ

แปลงที่มีอยู่ tf.summary การใช้งานกับ TF 2.x API ไม่สามารถเชื่อถือได้โดยอัตโนมัติดังนั้น tf_upgrade_v2 สคริปต์ เพียงแค่ปรับเปลี่ยนทุกอย่างให้ tf.compat.v1.summary ในการย้ายไปยัง TF 2.x คุณจะต้องปรับโค้ดของคุณดังนี้:

  1. ชุดเริ่มต้นเขียนผ่าน .as_default() จะต้องนำเสนอที่จะใช้ปฏิบัติการสรุป

    • ซึ่งหมายความว่าดำเนินการ ops อย่างกระตือรือร้นหรือใช้ ops ในการสร้างกราฟ
    • หากไม่มีตัวเขียนเริ่มต้น การดำเนินการสรุปจะกลายเป็นแบบไม่ต้องดำเนินการใดๆ
    • นักเขียนเริ่มต้นทำไม่ได้ (ยัง) การเผยแพร่ทั่ว @tf.function ขอบเขตการดำเนินการ - พวกเขามีการตรวจพบก็ต่อเมื่อมีฟังก์ชั่นที่มีการตรวจสอบ - ดังนั้นวิธีที่ดีที่สุดคือการเรียก writer.as_default() ภายในร่างกายทำงานและเพื่อให้แน่ใจว่าวัตถุนักเขียน ยังคงมีอยู่ตราบใดที่ @tf.function จะถูกใช้
  2. "ขั้นตอน" ค่าจะต้องผ่านเข้าไปในแต่ละ op ผ่านที่ step การโต้แย้ง

    • TensorBoard ต้องการค่าขั้นตอนเพื่อแสดงข้อมูลเป็นอนุกรมเวลา
    • การส่งผ่านที่ชัดเจนเป็นสิ่งจำเป็นเนื่องจากขั้นตอนสากลจาก TF 1.x ถูกลบออก ดังนั้น op แต่ละคนจะต้องทราบตัวแปรขั้นตอนที่ต้องการในการอ่าน
    • เพื่อลดสำเร็จรูป, สนับสนุนการทดลองสำหรับการลงทะเบียนเป็นค่าเริ่มต้นขั้นตอนที่สามารถใช้ได้เป็น tf.summary.experimental.set_step() แต่นี่คือการทำงานชั่วคราวที่อาจจะมีการเปลี่ยนแปลงโดยไม่ต้องแจ้งให้ทราบล่วงหน้า
  3. ลายเซ็นฟังก์ชันของการดำเนินการสรุปแต่ละรายการมีการเปลี่ยนแปลง

    • ค่าที่ส่งคืนตอนนี้เป็นบูลีน (แสดงว่ามีการเขียนสรุปจริงหรือไม่)
    • ชื่อพารามิเตอร์ที่สอง (ถ้าใช้) มีการเปลี่ยนแปลงจาก tensor ไปยัง data
    • collections พารามิเตอร์ได้ถูกลบออก; คอลเลกชันเป็น TF 1.x เท่านั้น
    • family พารามิเตอร์ได้ถูกลบออก; เพียงแค่ใช้ tf.name_scope()
  4. [สำหรับผู้ใช้โหมดกราฟเดิม / การดำเนินการเซสชันเท่านั้น]

    • แรกเริ่มต้นเขียนด้วย v1.Session.run(writer.init())

    • ใช้ v1.summary.all_v2_summary_ops() จะได้รับทั้งหมด Ops TF 2.x สรุปรูปแบบของกราฟในปัจจุบันเช่นการดำเนินการพวกเขาผ่านทาง Session.run()

    • ล้างนักเขียนที่มี v1.Session.run(writer.flush()) และเช่นเดียวกันสำหรับ close()

ถ้ารหัส 1.x TF ของคุณแทนการใช้ tf.contrib.summary API ก็มากขึ้นคล้ายกับ TF 2.x API เพื่อ tf_upgrade_v2 สคริปต์จะอัตโนมัติมากที่สุดของขั้นตอนการย้ายถิ่น (และเปล่งคำเตือนหรือข้อผิดพลาดสำหรับการใช้งานใด ๆ ที่ไม่สามารถ อพยพได้อย่างเต็มที่) ส่วนใหญ่มันเป็นเพียงแค่ปรับเปลี่ยนสาย API เพื่อ tf.compat.v2.summary ; ถ้าคุณต้องการเพียงเข้ากันได้กับ TF 2.x คุณสามารถวาง compat.v2 และอ้างอิงเพียงว่ามันเป็น tf.summary

เคล็ดลับเพิ่มเติม

นอกจากประเด็นสำคัญข้างต้นแล้ว ยังมีการเปลี่ยนแปลงด้านเสริมบางประการด้วย:

  • การบันทึกแบบมีเงื่อนไข (เช่น "บันทึกทุกๆ 100 ขั้นตอน") มีรูปลักษณ์ใหม่

    • การปฏิบัติการควบคุมและรหัสที่เกี่ยวข้องห่อไว้ในปกติถ้ามีคำสั่ง (ซึ่งทำงานในโหมดความกระตือรือร้นและ @tf.function ผ่านลายเซ็น ) หรือ tf.cond
    • ในการควบคุมเพียงสรุปใช้ใหม่ tf.summary.record_if() ผู้จัดการบริบทและผ่านมันสภาพบูลที่คุณเลือก
    • สิ่งเหล่านี้แทนที่รูปแบบ TF 1.x:

      if condition:
        writer.add_summary()
      
  • ไม่มีการเขียนโดยตรงของ tf.compat.v1.Graph - แทนฟังก์ชั่นการใช้งานการติดตาม

    • การดำเนินการในการใช้กราฟ TF 2.x @tf.function แทนอย่างชัดเจนกราฟ
    • ใน TF 2.x, ใช้ API ใหม่การติดตามสไตล์ tf.summary.trace_on() และ tf.summary.trace_export() เพื่อบันทึกดำเนินกราฟฟังก์ชั่น
  • ไม่มีแคชนักเขียนระดับโลกมากขึ้นต่อ logdir กับ tf.summary.FileWriterCache

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

    • TensorBoard 1.x รองรับรูปแบบใหม่แล้ว ความแตกต่างนี้มีผลกับผู้ใช้ที่แยกวิเคราะห์ข้อมูลสรุปจากไฟล์เหตุการณ์ด้วยตนเองเท่านั้น
    • ข้อมูลสรุปถูกจัดเก็บเป็นเทนเซอร์ไบต์ คุณสามารถใช้ tf.make_ndarray(event.summary.value[0].tensor) เพื่อแปลงเป็น numpy