SavedModels จาก TF Hub ใน TensorFlow 2

รูปแบบ SavedModel ของ TensorFlow 2 เป็นวิธีที่แนะนำในการแชร์โมเดลและชิ้นส่วนของโมเดลที่ได้รับการฝึกไว้ล่วงหน้าบน TensorFlow Hub โดยจะมาแทนที่ รูปแบบ TF1 Hub รุ่นเก่าและมาพร้อมกับ API ชุดใหม่

หน้านี้อธิบายวิธีนำ TF2 SavedModels มาใช้ซ้ำในโปรแกรม TensorFlow 2 ด้วย hub.load() API ระดับต่ำและ wrapper hub.KerasLayer (โดยทั่วไปแล้ว hub.KerasLayer จะรวมกับ tf.keras.layers อื่นๆ เพื่อสร้างโมเดล Keras หรือ model_fn ของ TF2 Estimator) API เหล่านี้ยังสามารถโหลดโมเดลเดิมในรูปแบบ TF1 Hub ได้ภายในขีดจำกัด โปรดดู คู่มือความเข้ากันได้

ผู้ใช้ TensorFlow 1 สามารถอัปเดตเป็น TF 1.15 แล้วใช้ API เดียวกันได้ TF1 เวอร์ชันเก่าไม่ทำงาน

ใช้ SavedModels จาก TF Hub

การใช้ SavedModel ใน Keras

Keras เป็น API ระดับสูงของ TensorFlow สำหรับการสร้างแบบจำลองการเรียนรู้เชิงลึกโดยการเขียนวัตถุ Keras Layer ไลบรารี tensorflow_hub จัดเตรียมคลาส hub.KerasLayer ที่ได้รับการเริ่มต้นด้วย URL (หรือเส้นทางระบบไฟล์) ของ SavedModel จากนั้นจัดเตรียมการคำนวณจาก SavedModel รวมถึงน้ำหนักที่ได้รับการฝึกอบรมล่วงหน้า

นี่คือตัวอย่างการใช้การฝังข้อความที่ได้รับการฝึกล่วงหน้า:

import tensorflow as tf
import tensorflow_hub as hub

hub_url = "https://tfhub.dev/google/nnlm-en-dim128/2"
embed = hub.KerasLayer(hub_url)
embeddings = embed(["A long sentence.", "single-word", "http://example.com"])
print(embeddings.shape, embeddings.dtype)

จากนี้ คุณสามารถสร้างตัวแยกประเภทข้อความได้ด้วยวิธี Keras ตามปกติ:

model = tf.keras.Sequential([
    embed,
    tf.keras.layers.Dense(16, activation="relu"),
    tf.keras.layers.Dense(1, activation="sigmoid"),
])

Colab การแยกประเภทข้อความ เป็นตัวอย่างที่สมบูรณ์ของวิธีฝึกและประเมินตัวแยกประเภทดังกล่าว

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

การใช้ SavedModel ในเครื่องมือประมาณการ

ผู้ใช้ Estimator API ของ TensorFlow สำหรับการฝึกอบรมแบบกระจายสามารถใช้ SavedModels จาก TF Hub ได้โดยการเขียน model_fn ในรูปของ hub.KerasLayer ท่ามกลาง tf.keras.layers อื่นๆ

เบื้องหลัง: การดาวน์โหลดและการแคชของ SavedModel

การใช้ SavedModel จาก TensorFlow Hub (หรือเซิร์ฟเวอร์ HTTPS อื่นๆ ที่ใช้โปรโตคอล โฮสติ้ง ) จะดาวน์โหลดและขยายขนาดไปยังระบบไฟล์ในเครื่องหากยังไม่มี ตัวแปรสภาพแวดล้อม TFHUB_CACHE_DIR สามารถตั้งค่าให้แทนที่ตำแหน่งชั่วคราวเริ่มต้นสำหรับการแคช SavedModels ที่ดาวน์โหลดและไม่บีบอัด สำหรับรายละเอียด โปรดดูที่ การแคช

การใช้ SavedModel ใน TensorFlow ระดับต่ำ

แฮนด์โมเดล

SavedModels สามารถโหลดได้จาก handle ที่ระบุ โดยที่ handle เป็นเส้นทางของระบบไฟล์ URL รุ่น TFhub.dev ที่ถูกต้อง (เช่น "https://tfhub.dev/...") URL ของโมเดล Kaggle สะท้อนการจัดการ TFhub.dev ตามข้อกำหนดของเราและใบอนุญาตที่เกี่ยวข้องกับเนื้อหาโมเดล เช่น "https://www.kaggle.com/..." แฮนเดิลจาก Kaggle Models เทียบเท่ากับแฮนเดิล TFhub.dev ที่สอดคล้องกัน

ฟังก์ชัน hub.load(handle) ดาวน์โหลดและขยายขนาด SavedModel (เว้นแต่ว่า handle นั้นเป็นเส้นทางของระบบไฟล์อยู่แล้ว) จากนั้นส่งคืนผลลัพธ์ของการโหลดด้วยฟังก์ชันในตัวของ TensorFlow tf.saved_model.load() ดังนั้น hub.load() จึงสามารถจัดการ SavedModel ที่ถูกต้องได้ (ไม่เหมือนกับ hub.Module รุ่นก่อนสำหรับ TF1)

หัวข้อขั้นสูง: สิ่งที่คาดหวังจาก SavedModel หลังจากโหลด

ขึ้นอยู่กับเนื้อหาของ SavedModel ผลลัพธ์ของ obj = hub.load(...) สามารถเรียกใช้ได้หลายวิธี (ดังที่อธิบายในรายละเอียดที่มากขึ้นใน SavedModel Guide ของ TensorFlow :

  • ลายเซ็นการให้บริการของ SavedModel (ถ้ามี) แสดงเป็นพจนานุกรมของฟังก์ชันที่เป็นรูปธรรมและสามารถเรียกได้เช่น tensors_out = obj.signatures["serving_default"](**tensors_in) โดยมีพจนานุกรมของเทนเซอร์ที่คีย์โดยอินพุตและเอาต์พุตที่เกี่ยวข้อง ชื่อและขึ้นอยู่กับรูปร่างของลายเซ็นและข้อจำกัดประเภท

  • วิธีการ @tf.function - ตกแต่งของวัตถุที่บันทึกไว้ (ถ้ามี) จะถูกกู้คืนเป็นวัตถุ tf.function ที่สามารถเรียกได้โดยการรวมกันของอาร์กิวเมนต์ Tensor และไม่ใช่ Tensor ทั้งหมดซึ่งมี การติดตาม tf.function ก่อนที่จะบันทึก โดยเฉพาะอย่างยิ่ง หากมีเมธอด obj.__call__ ที่มีการติดตามที่เหมาะสม ตัว obj ก็สามารถถูกเรียกได้เหมือนกับฟังก์ชัน Python ตัวอย่างง่ายๆ อาจมีลักษณะเช่น output_tensor = obj(input_tensor, training=False)

สิ่งนี้ทำให้มีอิสระอย่างมากในอินเทอร์เฟซที่ SavedModels สามารถใช้งานได้ อินเทอร์เฟซที่ใช้ซ้ำได้ SavedModels สำหรับ obj กำหนดแบบแผนเพื่อให้โค้ดไคลเอ็นต์ รวมถึงอะแดปเตอร์ เช่น hub.KerasLayer รู้วิธีใช้ SavedModel

SavedModel บางตัวอาจไม่เป็นไปตามแบบแผนดังกล่าว โดยเฉพาะอย่างยิ่งทั้งโมเดลที่ไม่ควรใช้ซ้ำในโมเดลขนาดใหญ่ และเพียงจัดเตรียมลายเซ็นต์ที่ให้บริการ

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

การสร้าง SavedModels สำหรับ TF Hub

ภาพรวม

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

บันทึกจาก Keras

เริ่มต้นด้วย TensorFlow 2, tf.keras.Model.save() และ tf.keras.models.save_model() มีค่าเริ่มต้นเป็นรูปแบบ SavedModel (ไม่ใช่ HDF5) SavedModels ผลลัพธ์ที่สามารถใช้กับ hub.load() , hub.KerasLayer และอะแดปเตอร์ที่คล้ายกันสำหรับ API ระดับสูงอื่นๆ เมื่อพร้อมใช้งาน

หากต้องการแชร์โมเดล Keras ที่สมบูรณ์ เพียงบันทึกด้วย include_optimizer=False

หากต้องการแบ่งปันชิ้นส่วนของ Keras Model ให้สร้างชิ้นส่วนนั้นเป็น Model ในตัวมันเอง จากนั้นจึงบันทึกสิ่งนั้น คุณสามารถวางโค้ดแบบนั้นได้ตั้งแต่เริ่มต้น....

piece_to_share = tf.keras.Model(...)
full_model = tf.keras.Sequential([piece_to_share, ...])
full_model.fit(...)
piece_to_share.save(...)

...หรือตัดชิ้นส่วนออกเพื่อแบ่งปันภายหลัง (หากสอดคล้องกับเลเยอร์ของโมเดลเต็มของคุณ):

full_model = tf.keras.Model(...)
sharing_input = full_model.get_layer(...).get_output_at(0)
sharing_output = full_model.get_layer(...).get_output_at(0)
piece_to_share = tf.keras.Model(sharing_input, sharing_output)
piece_to_share.save(..., include_optimizer=False)

โมเดล TensorFlow บน GitHub ใช้วิธีการเดิมสำหรับ BERT (ดู nlp/tools/export_tfhub_lib.py สังเกตการแยกระหว่าง core_model สำหรับการส่งออกและ pretrainer สำหรับการกู้คืนจุดตรวจสอบ) และวิธีการหลังสำหรับ ResNet (ดู มรดก/image_classification/tfhub_export.py ).

บันทึกจาก TensorFlow ระดับต่ำ

สิ่งนี้ต้องอาศัยความคุ้นเคยเป็นอย่างดีกับ SavedModel Guide ของ TensorFlow

หากคุณต้องการให้มากกว่าแค่ลายเซ็นการให้บริการ คุณควรใช้ อินเทอร์เฟซ Reusable SavedModel ตามแนวคิดแล้วดูเหมือนว่านี้

class MyMulModel(tf.train.Checkpoint):
  def __init__(self, v_init):
    super().__init__()
    self.v = tf.Variable(v_init)
    self.variables = [self.v]
    self.trainable_variables = [self.v]
    self.regularization_losses = [
        tf.function(input_signature=[])(lambda: 0.001 * self.v**2),
    ]

  @tf.function(input_signature=[tf.TensorSpec(shape=None, dtype=tf.float32)])
  def __call__(self, inputs):
    return tf.multiply(inputs, self.v)

tf.saved_model.save(MyMulModel(2.0), "/tmp/my_mul")

layer = hub.KerasLayer("/tmp/my_mul")
print(layer([10., 20.]))  # [20., 40.]
layer.trainable = True
print(layer.trainable_weights)  # [2.]
print(layer.losses)  # 0.004

การปรับแต่งแบบละเอียด

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

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

สำหรับผู้บริโภค SavedModel

การสร้าง hub.KerasLayer เช่น KerasLayer

layer = hub.KerasLayer(..., trainable=True)

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

Colab การจัดหมวดหมู่รูปภาพ มีตัวอย่างตั้งแต่ต้นจนจบพร้อมการปรับแต่งแบบละเอียด (ไม่บังคับ)

ส่งออกผลลัพธ์การปรับแต่งอย่างละเอียดอีกครั้ง

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

loaded_obj = hub.load("https://tfhub.dev/...")
hub_layer = hub.KerasLayer(loaded_obj, trainable=True, ...)

model = keras.Sequential([..., hub_layer, ...])
model.compile(...)
model.fit(...)

export_module_dir = os.path.join(os.getcwd(), "finetuned_model_export")
tf.saved_model.save(loaded_obj, export_module_dir)

สำหรับผู้สร้าง SavedModel

เมื่อสร้าง SavedModel สำหรับการแชร์บน TensorFlow Hub ให้คิดล่วงหน้าว่าผู้บริโภคควรปรับแต่งหรือไม่ และอย่างไร และให้คำแนะนำในเอกสารประกอบ

การบันทึกจากโมเดล Keras ควรทำให้กลไกทั้งหมดของงานปรับแต่งอย่างละเอียด (บันทึกการสูญเสียการทำให้น้ำหนักเป็นมาตรฐาน การประกาศตัวแปรที่ฝึกได้ การติดตาม __call__ สำหรับทั้ง training=True และ training=False ฯลฯ )

เลือกอินเทอร์เฟซแบบจำลองที่ทำงานได้ดีกับโฟลว์การไล่ระดับสี เช่น การบันทึกเอาท์พุต แทนที่จะเป็นความน่าจะเป็นแบบ softmax หรือการคาดคะเนแบบ top-k

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

ตัวปรับน้ำหนักในแต่ละเลเยอร์จะถูกบันทึกไว้ (ด้วยค่าสัมประสิทธิ์ความแข็งแกร่งของการทำให้เป็นมาตรฐาน) แต่การทำให้น้ำหนักเป็นมาตรฐานจากภายในตัวเพิ่มประสิทธิภาพ (เช่น tf.keras.optimizers.Ftrl.l1_regularization_strength=...) ) จะหายไป แนะนำผู้บริโภคของ SavedModel ของคุณตามลำดับ