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

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

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

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

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

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

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

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

כשמשתמשים בקונטיינר מוכן מראש של 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 שבה אתם משתמשים: TensorFlow 2 או TensorFlow 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 Explainable 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.

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