שימוש ב-TensorFlow להסברים

כשעובדים עם מודלים של TensorFlow שעברו אימון בהתאמה אישית, יש מידע ספציפי שצריך כדי לשמור את המודל ולהגדיר הסברים.

אם רוצים להשתמש ב-Vertex AI ניתן להסברה עם מודל טבלאי של AutoML, לא צריך לבצע שום הגדרה. Vertex AI מגדיר את המודל באופן אוטומטי ל-Vertex AI ניתן להסברה. אפשר לדלג על המסמך הזה ולקרוא את המאמר בנושא קבלת הסברים.

במדריך הזה מוסבר מה צריך לעשות כשמאמנים מודל TensorFlow כדי לוודא שאפשר להשתמש בו עם Vertex AI ניתן להסברה. המדריך כולל את הנושאים הבאים:

  • מציאת שמות הטנסורים של הקלט והפלט במהלך האימון שצריך לציין כשמגדירים משאב Model עבור Vertex AI ניתן להסברה. הפעולה הזו כוללת יצירה ומציאה של טנסורים מתאימים ל-Vertex AI ניתן להסברה במקרים מיוחדים שבהם הטנסורים הרגילים לא פועלים.

  • ייצוא של מודל TensorFlow כ-TensorFlow SavedModel שתואם ל-Vertex AI ניתן להסברה.

  • איך מוצאים את שמות הטנסורים של הקלט והפלט מ-TensorFlow SavedModel שכבר יוצא. האפשרות הזו שימושית אם אין לכם גישה לקוד האימון של המודל.

איך מוצאים את השמות של טנסורים של קלט ופלט במהלך האימון

כשמשתמשים בקונטיינר מוכן מראש של TensorFlow כדי להציג תחזיות, צריך לדעת את השמות של טנסורי הקלט וטנסור הפלט של המודל. אתם מציינים את השמות האלה כחלק מהודעה ExplanationMetadata כשאתם מגדירים Model ל-Vertex AI ניתן להסברה

אם מודל TensorFlow שלכם עומד בקריטריונים הבאים, תוכלו להשתמש ב'שיטה הבסיסית' שמתוארת בקטע הבא כדי לקבוע את שמות הטנסורים האלה במהלך האימון:

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

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

השיטה הבסיסית

במהלך האימון, מדפיסים את מאפיין name של טנסורי הקלט של המודל ואת טנסורי הפלט שלו. בדוגמה הבאה, השדה name של שכבת Keras יוצר את שם הטנזור הבסיסי שנדרש ל-ExplanationMetadata:

bow_inputs = tf.keras.layers.Input(shape=(2000,))
merged_layer = tf.keras.layers.Dense(256, activation="relu")(bow_inputs)
predictions = tf.keras.layers.Dense(10, activation="sigmoid")(merged_layer)
model = tf.keras.Model(inputs=bow_inputs, outputs=predictions)
print('input_tensor_name:', bow_inputs.name)
print('output_tensor_name:', predictions.name)

הפעלת קוד Python הזה מדפיסה את הפלט הבא:

input_tensor_name: input_1:0
output_tensor_name: dense_1/Sigmoid:0

אחר כך תוכלו להשתמש ב-input_1:0 כשם טנסור הקלט וב-dense_1/Sigmod:0 כשם טנסור הפלט כשמגדירים את Model להסברים.

התאמת קוד ההדרכה ומציאת שמות של טנסורים במקרים מיוחדים

יש כמה מקרים נפוצים שבהם טנסור הקלט וטנסור הפלט של ExplanationMetadata לא צריכים להיות זהים לאלה שב-SignatureDef:

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

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

מקרים מיוחדים של טנסורים של קלט

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

קלטים סדרתיים

מודלים של TensorFlow SavedModel יכולים לקבל מגוון קלטים מורכבים, כולל:

  • הודעות tf.Example שעברו סריאליזציה
  • מחרוזות JSON
  • מחרוזות בקידוד Base64 (לייצוג נתוני תמונה)

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

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

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

בדוגמה הבאה מוצג איך מקבלים את השם של טנסור הקלט אחרי פעולת פענוח:

float_pixels = tf.map_fn(
    lambda img_string: tf.io.decode_image(
        img_string,
        channels=color_depth,
        dtype=tf.float32
    ),
    features,
    dtype=tf.float32,
    name='input_convert'
  )

print(float_pixels.name)
עיבוד מקדים של קלטים

אם גרף המודל מכיל כמה פעולות של עיבוד מקדים, יכול להיות שתרצו לקבל הסברים על הטנסורים אחרי שלב העיבוד המקדים. במקרה כזה, אפשר לקבל את השמות של הטנסורים האלה באמצעות המאפיין name של tf.Tensor ולהוסיף אותם למטא-נתונים של ההסבר:

item_one_hot = tf.one_hot(item_indices, depth,
    on_value=1.0, off_value=0.0,
    axis=-1, name="one_hot_items:0")
print(item_one_hot.name)

שם הטנזור המפוענח הופך ל-input_pixels:0.

מקרים מיוחדים של טנסורים של פלט

ברוב המקרים, התוצאות בהצגת המודעות SignatureDef הן הסתברויות או לוגיטים.

אם המודל שלכם משייך הסתברויות אבל אתם רוצים להסביר את ערכי הלוגיט, אתם צריכים למצוא את שמות טנסור הפלט המתאימים שמתאימים ללוגיטים.

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

שיקולים מיוחדים לגבי מעברי צבע משולבים

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

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

אם יש לכם טנסורים של קלט שאי אפשר לגזור מהם, או אם יש לכם פעולות שאי אפשר לגזור מהן בגרף, אתם יכולים להשתמש בגישה הבאה:

  1. קידוד של ערכי קלט לא גזירים כערכי קלט גזירים.
  2. מגדירים את input_tensor_name לשם של טנסור הקלט המקורי שלא ניתן לגזירה, ואת encoded_tensor_name לשם של הגרסה המקודדת שלו שניתן לגזירה.

קובץ מטא-נתונים של הסבר עם קידוד

לדוגמה, נניח שיש מודל עם מאפיין קטגוריאלי עם טנסור קלט בשם zip_codes:0. מכיוון שנתוני הקלט כוללים מיקודים כמחרוזות, טנסור הקלט zip_codes:0 לא ניתן לגזירה. אם המודל גם מבצע עיבוד מקדים של הנתונים האלה כדי לקבל ייצוג של המיקודים באמצעות קידוד one-hot, אז טנסור הקלט אחרי העיבוד המקדים הוא דיפרנציאבילי. כדי להבדיל אותו מטנזור הקלט המקורי, אפשר לתת לו את השם zip_codes_embedding:0.

כדי להשתמש בנתונים משני טנסורים של קלט בבקשת ההסברים, צריך להגדיר את ExplanationMetadata באופן הבא כשמגדירים את Model להסברים:

  • מגדירים למפתח של תכונת הקלט שם בעל משמעות, כמו zip_codes.
  • מגדירים את input_tensor_name לשם של הטנסור המקורי, zip_codes:0.
  • מגדירים את encoded_tensor_name לשם הטנסור אחרי קידוד one-hot, zip_codes_embedding:0.
  • מגדירים את encoding להיות COMBINED_EMBEDDING.
{
    "inputs": {
      "zip_codes": {
        "input_tensor_name": "zip_codes:0",
        "encoded_tensor_name": "zip_codes_embedding:0",
        "encoding": "COMBINED_EMBEDDING"
      }
    },
    "outputs": {
      "probabilities": {
        "output_tensor_name": "dense/Softmax:0"
      }
    }
}

לחלופין, אפשר להגדיר את input_tensor_name לשם של טנסור הקלט המקודד והניתן לגזירה, ולהשמיט את הטנסור המקורי שלא ניתן לגזירה. היתרון בציון שני הטנסורים הוא שאפשר לבצע שיוכים לערכים ספציפיים של מיקודים, ולא לייצוג של קידוד one-hot. בדוגמה הזו, מחריגים את הטנזור המקורי (zip_codes:0) ומגדירים את input_tensor_name ל-zip_codes_embedding:0. לא מומלץ להשתמש בגישה הזו, כי יהיה קשה להבין את שיוך התכונות שיתקבל.

קידוד

כדי להפעיל קידוד עבור Model, צריך לציין הגדרות קידוד כמו שמוצג בדוגמה הקודמת.

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

בקידוד COMBINED_EMBEDDING, טנסור הקלט מקודד למערך חד-ממדי.

לדוגמה:

  • קלט: ["This", "is", "a", "test"]
  • קלט מקודד: [0.1, 0.2, 0.3, 0.4]

ייצוא של מודלים שמורים של TensorFlow ל-Vertex AI ניתן להסברה

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

כדי לוודא ש-SavedModel תואם ל-Vertex AI ניתן להסברה, צריך לפעול לפי ההוראות באחד מהקטעים הבאים, בהתאם לגרסת TensorFlow שבה אתם משתמשים (גרסה 2 או גרסה 1).

‫TensorFlow 2

אם אתם עובדים עם TensorFlow 2.x, אתם יכולים להשתמש בפקודה tf.saved_model.save כדי לשמור את המודל. אפשר לציין חתימות קלט כששומרים את המודל. אם יש לכם חתימת קלט אחת, Vertex AI ניתן להסברה משתמש בפונקציית ברירת המחדל להצגת נתונים עבור בקשות ההסברים שלכם. אם יש לכם יותר מחתימת קלט אחת, אתם צריכים לציין את החתימה של פונקציית ברירת המחדל שלכם להצגת מודל כשאתם שומרים את המודל:

tf.saved_model.save(m, model_dir, signatures={
    'serving_default': serving_fn,
    'xai_model': model_fn # Required for XAI
    })

במקרה הזה, Vertex AI ניתן להסברה משתמש בחתימת הפונקציה של המודל ששמרתם עם המפתח xai_model לבקשת ההסברים. משתמשים במחרוזת המדויקת xai_model למפתח.

אם משתמשים בפונקציית עיבוד מקדים, צריך לציין גם את החתימות של פונקציית העיבוד המקדים ושל פונקציית המודל. חובה להשתמש במחרוזות המדויקות xai_preprocess ו-xai_model כמפתחות:

tf.saved_model.save(m, model_dir, signatures={
    'serving_default': serving_fn,
    'xai_preprocess': preprocess_fn, # Required for XAI
    'xai_model': model_fn # Required for XAI
    })

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

מידע נוסף על הגדרת חתימות להצגת מודעות ב-TensorFlow

‫TensorFlow 1.15

אם אתם עובדים עם TensorFlow 1.15, אל תשתמשו ב-tf.saved_model.save. ‫Vertex AI ניתן להסברה לא תומך במודלים של TensorFlow 1 שנשמרו בשיטה הזו

אם אתם בונים ומאמנים את המודל שלכם ב-Keras, אתם צריכים להמיר את המודל ל-TensorFlow Estimator, ואז לייצא אותו ל-SavedModel. בקטע הזה נתמקד בשמירת מודל.

אחרי שיוצרים, מהדרים, מאמנים ומעריכים את מודל Keras, צריך:

  • ממירים את מודל Keras ל-TensorFlow Estimator באמצעות הפקודה tf.keras.estimator.model_to_estimator
  • צריך לספק פונקציית קלט להצגת מודעות, באמצעות tf.estimator.export.build_raw_serving_input_receiver_fn
  • מייצאים את המודל כ-SavedModel באמצעות tf.estimator.export_saved_model.
# Build, compile, train, and evaluate your Keras model
model = tf.keras.Sequential(...)
model.compile(...)
model.fit(...)
model.predict(...)

## Convert your Keras model to an Estimator
keras_estimator = tf.keras.estimator.model_to_estimator(keras_model=model, model_dir='export')

## Define a serving input function appropriate for your model
def serving_input_receiver_fn():
  ...
  return tf.estimator.export.ServingInputReceiver(...)

## Export the SavedModel to Cloud Storage, using your serving input function
export_path = keras_estimator.export_saved_model(
  'gs://' + 'YOUR_BUCKET_NAME',
  serving_input_receiver_fn
).decode('utf-8')

print("Model exported to: ", export_path)

קבלת שמות של טנסורים מ-SignatureDef של SavedModel

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

כדי לבדוק את SignatureDef של SavedModel, אפשר להשתמש ב-SavedModel CLI. מידע נוסף על השימוש ב-SavedModel CLI

דוגמה SignatureDef:

The given SavedModel SignatureDef contains the following input(s):
  inputs['my_numpy_input'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1)
      name: x:0
The given SavedModel SignatureDef contains the following output(s):
  outputs['probabilities'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1)
      name: dense/Softmax:0
Method name is: tensorflow/serving/predict

לגרף יש טנסור קלט בשם x:0 וטנסור פלט בשם dense/Softmax:0. כשמגדירים את Model לקבלת הסברים, צריך להשתמש ב-x:0 כשם טנסור הקלט וב-dense/Softmax:0 כשם טנסור הפלט בהודעה ExplanationMetadata.

המאמרים הבאים