หน้านี้ได้รับการแปลโดย Cloud Translation API
Switch to English

การโอนย้ายการใช้งาน tf.summary ไปยัง TF 2.0

ดูใน TensorFlow.org เรียกใช้ใน Google Colab ดูแหล่งที่มาบน GitHub
import tensorflow as tf

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

มีอะไรเปลี่ยนแปลง

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

  • ชุดตัวเลือกสำหรับการบันทึกสรุปแต่ละรายการ - 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.0

ใน TF 2.X

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

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

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.1599908770.kokoro-gcp-ubuntu-prod-1849198075.22428.5.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.1599908771.kokoro-gcp-ubuntu-prod-1849198075.22428.1013.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.1599908771.kokoro-gcp-ubuntu-prod-1849198075.22428.1446.v2

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

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

  1. ต้องมีตัวเขียนเริ่มต้นที่ตั้งค่าผ่าน. .as_default() เพื่อใช้ตัวเลือกสรุป

    • ซึ่งหมายถึงการดำเนินการ ops อย่างกระตือรือร้นหรือใช้ ops ในการสร้างกราฟ
    • หากไม่มีตัวเขียนเริ่มต้นการดำเนินการสรุปจะกลายเป็น no-ops แบบเงียบ
    • ตัวเขียนเริ่มต้นไม่ (ยัง) เผยแพร่ข้ามขอบเขตการดำเนินการ @tf.function - จะตรวจพบเมื่อมีการติดตามฟังก์ชันเท่านั้นดังนั้นแนวทางปฏิบัติที่ดีที่สุดคือการเรียก writer.as_default() ภายในเนื้อความของฟังก์ชันและเพื่อให้แน่ใจว่าวัตถุตัวเขียน ยังคงมีอยู่ตราบเท่าที่มีการใช้ @tf.function
  2. ต้องส่งค่า "step" ไปยังแต่ละ 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() เพื่อรับตัวเลือกสรุป TF 2.0 ทั้งหมดสำหรับกราฟปัจจุบันเช่นเรียกใช้งานผ่าน Session.run()

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

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

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

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

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

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

    • การเรียกใช้กราฟใน TF 2.0 ใช้ @tf.function แทนการใช้กราฟอย่างชัดเจน
    • ใน TF 2.0 ใช้ 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