SavedModels מ- TF Hub ב- TensorFlow 2

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

דף זה מסביר כיצד לעשות שימוש חוזר TF2 SavedModels בתוכנית TensorFlow 2 עם ברמה נמוכה hub.load() API שלה hub.KerasLayer מעטפת. (בדרך כלל, hub.KerasLayer משולב עם אחרים tf.keras.layers לבנות מודל Keras או model_fn של הערכת TF2.) אלה APIs גם יכולה לטעון את הדגמים המורשים בפורמט Hub TF1, בגבולות, ראי מדריך התאימות .

משתמשי TensorFlow 1 יכולים לעדכן ל-TF 1.15 ולאחר מכן להשתמש באותם ממשקי API. גרסאות ישנות יותר של TF1 לא עובדות.

שימוש ב- SavedModels מ- TF Hub

שימוש ב-SaveModel ב-Keras

Keras הוא API ברמה גבוהה של TensorFlow לבניית מודלים עמוק למידה ידי להלחין חפצים Layer Keras. tensorflow_hub הספרייה מספקת הכיתה hub.KerasLayer שמקבל אותחל עם כתובת האתר (או נתיב הקבצים) של 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.

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

משתמשים של TensorFlow ההערכה API לאימונים מופצים יכולים להשתמש SavedModels מרכזת TF ידי כתיבה שלהם model_fn מבחינת hub.KerasLayer בקרב אחרים tf.keras.layers .

מאחורי הקלעים: SavedModel הורדה ושמירה במטמון

באמצעות SavedModel מרכזת TensorFlow (או שרתי HTTPS אחרים המיישמים שלה אירוח פרוטוקול) הורדות decompresses אותה מערכת הקבצים המקומיים אם לא קיים כבר. משתנה סביבת TFHUB_CACHE_DIR ניתן להגדיר כדי לעקוף את מיקום ברירת המחדל זמן אחסון במטמון של SavedModels שהורד דחוס. לפרטים ראה הטמנה .

שימוש ב- SavedModel ב-TensorFlow ברמה נמוכה

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

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

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

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

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

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

ייתכן שחלק מה- 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 ומתאמים דומים עבור APIs ברמה גבוהה אחרת כפי שהם מתפרסמים.

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

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

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

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

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