SavedModels מ-TF Hub ב-TensorFlow 2

פורמט SavedModel של TensorFlow 2 הוא הדרך המומלצת לשתף דגמים וחלקי דגמים שעברו הכשרה מראש ב- TensorFlow Hub. הוא מחליף את הפורמט הישן יותר של TF1 Hub ומגיע עם סט חדש של ממשקי API.

דף זה מסביר כיצד לעשות שימוש חוזר ב-TF2 SavedModels בתוכנית TensorFlow 2 עם ה-API ברמה נמוכה hub.load() והעטיפה שלו 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

שימוש ב-SaveModel ב-Keras

Keras הוא ה-API ברמה גבוהה של TensorFlow לבניית מודלים של למידה עמוקה על ידי חיבור אובייקטי Keras Layer. ספריית tensorflow_hub מספקת את ה-class 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"),
])

ה- Text Classification colab הוא דוגמה מלאה כיצד לאמן ולהעריך מסווג כזה.

משקלי הדגם ב- hub.KerasLayer מוגדרים כברירת מחדל כבלתי ניתן לאימון. עיין בסעיף על כוונון עדין להלן כיצד לשנות זאת. משקולות מחולקות בין כל היישומים של אותו אובייקט שכבה, כרגיל ב-Keras.

שימוש ב-SaveModel באומד

משתמשים ב-API של Estimator של TensorFlow להדרכה מבוזרת יכולים להשתמש ב-SaveedModels מ-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 Mirror TFhub.dev מטפל בהתאם לתנאים שלנו ולרישיון המשויך לנכסי הדגם, למשל, "https://www.kaggle.com/...". ידיות מדגמי Kaggle שוות ערך לידית ה-TFhub.dev המקבילה להן.

הפונקציה hub.load(handle) מורידה ומבטלת דחיסה של SavedModel (אלא אם handle הוא כבר נתיב של מערכת קבצים) ולאחר מכן מחזירה את התוצאה של טעינתו עם הפונקציה המובנית של TensorFlow tf.saved_model.load() . לכן, hub.load() יכול להתמודד עם כל SavedModel חוקי (בניגוד ל- hub.Module קודמו עבור TF1).

נושא מתקדם: למה לצפות מה-SavedModel לאחר הטעינה

בהתאם לתוכן של SavedModel, ניתן להפעיל את התוצאה של obj = hub.load(...) בדרכים שונות (כפי שהוסבר בפירוט רב יותר במדריך SavedModel של TensorFlow:

  • חתימות ההגשה של SavedModel (אם יש כאלה) מיוצגות כמילון של פונקציות קונקרטיות וניתן לקרוא אותן כמו tensors_out = obj.signatures["serving_default"](**tensors_in) , עם מילוני טנסורים הממוקמים על ידי הקלט והפלט המתאימים. שמות ובכפוף לצורת החתימה ולאילוצי dtype.

  • שיטות ה- @tf.function -מעוטרות של האובייקט השמור (אם יש) משוחזרות כאובייקטי tf.function שניתן לקרוא להם על ידי כל השילובים של ארגומנטים Tensor ולא-Tensor שעבורם הפונקציה tf. עוקבה לפני השמירה. בפרט, אם יש שיטת obj.__call__ עם עקבות מתאימות, ניתן לקרוא obj עצמו כמו פונקציית Python. דוגמה פשוטה יכולה להיראות כמו output_tensor = obj(input_tensor, training=False) .

זה משאיר חופש עצום בממשקים ש-SavedModels יכולים ליישם. ממשק SavedModels לשימוש חוזר עבור obj קובע מוסכמות כך שקוד לקוח, כולל מתאמים כמו hub.KerasLayer , יודעים להשתמש ב-SaveedModel.

ייתכן שחלק מה- SavedModels לא יפעלו בהתאם למוסכמה הזו, במיוחד דגמים שלמים שלא מיועדים לשימוש חוזר בדגמים גדולים יותר, ורק מספקים חתימות הגשה.

המשתנים הניתנים לאימון ב- SavedModel נטענים מחדש כניתנים לאימון, ו- tf.GradientTape יצפה בהם כברירת מחדל. עיין בסעיף על כוונון עדין להלן לכמה אזהרות, ושקול להימנע מכך בתור התחלה. גם אם אתה רוצה לכוונן עדין, אולי תרצה לראות אם obj.trainable_variables מייעץ לאמן מחדש רק תת-קבוצה של המשתנים הניתנים לאימון במקור.

יצירת SavedModels עבור TF Hub

סקירה כללית

SavedModel הוא פורמט ההסדרה הסטנדרטי של TensorFlow עבור דגמים או חלקי מודל מאומנים. הוא מאחסן את המשקולות המאומנות של הדגם יחד עם פעולות TensorFlow המדויקות לביצוע החישוב שלו. ניתן להשתמש בו באופן עצמאי מהקוד שיצר אותו. בפרט, ניתן לעשות בו שימוש חוזר על פני ממשקי API שונים לבניית מודלים ברמה גבוהה כמו Keras, מכיוון שפעולות TensorFlow הן השפה הבסיסית המשותפת שלהם.

חוסך מקרס

החל מ-TensorFlow 2, tf.keras.Model.save() ו- tf.keras.models.save_model() כברירת מחדל לפורמט SavedModel (לא HDF5). SavedModels המתקבלים שניתן להשתמש בהם עם hub.load() , hub.KerasLayer ומתאמים דומים עבור ממשקי API ברמה גבוהה אחרים כאשר הם הופכים לזמינים.

כדי לשתף דגם שלם של Keras, פשוט שמור אותו עם include_optimizer=False .

כדי לשתף חלק מדגם Keras, הפוך את היצירה לדגם בפני עצמו ואז שמור את זה. אתה יכול לפרוס את הקוד כך מההתחלה....

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 Models ב- GitHub משתמשת בגישה הקודמת עבור BERT (ראה nlp/tools/export_tfhub_lib.py , שים לב לפיצול בין core_model לייצוא וה- pretrainer לשחזור המחסום) והגישה השנייה עבור ResNet (ראה legacy/image_classification/tfhub_export.py ).

חיסכון מ-TensorFlow ברמה נמוכה

זה מצריך היכרות טובה עם SavedModel Guide של TensorFlow.

אם אתה רוצה לספק יותר מסתם חתימת הגשה, עליך ליישם את ממשק 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. זה יכול להביא לאיכות טובה יותר, אבל לעתים קרובות הופך את האימון ליותר תובעני (עשוי לקחת יותר זמן, להיות תלוי יותר במייעל ובפרמטרים שלו, להגביר את הסיכון להתאמת יתר ולדרוש הגדלת מערך נתונים, במיוחד עבור CNNs). אנו ממליצים לצרכנים של SavedModel לבחון כוונון עדין רק לאחר שקבעו משטר אימונים טוב, ורק אם המוציא לאור של SavedModel ממליץ על כך.

כוונון עדין משנה את פרמטרי המודל ה"רציפים" שמאומנים. זה לא משנה טרנספורמציות מקודדות קשיחות, כגון הוספת קלט טקסט ומיפוי אסימונים לערכים התואמים שלהם במטריצת הטמעה.

עבור צרכני SavedModel

יצירת hub.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 או תחזיות מובילות.

אם המודל משתמש בנשירה, נורמליזציה של אצווה או טכניקות אימון דומות הכוללות היפרפרמטרים, הגדר אותם לערכים הגיוניים על פני בעיות יעד צפויות וגדלי אצווה רבים. (נכון לכתיבת שורות אלה, חיסכון מ-Keras לא מקל על מתן אפשרות לצרכנים להתאים אותם.)

מסדרי משקל בשכבות בודדות נשמרים (עם מקדמי חוזק הסידור שלהם), אך הסדרת המשקל מתוך המייעל (כמו tf.keras.optimizers.Ftrl.l1_regularization_strength=...) ) אובדת. ייעץ לצרכנים של SavedModel שלך בהתאם.