使用 TensorFlow 提供說明

使用自訂訓練的 TensorFlow 模型時,您需要提供特定資訊才能儲存模型並設定說明。

如果您想搭配 AutoML 表格型模型使用 Vertex Explainable AI,則無需執行任何設定;Vertex AI 會自動為 Vertex Explainable AI 設定模型。請略過這份文件,改為閱讀取得說明

本指南提供訓練 TensorFlow 模型時所需的資訊,確保您能將模型與 Vertex Explainable AI 搭配使用。具體來說,指南涵蓋下列主題:

  • 在訓練期間找出輸入和輸出張量名稱,您需要在為 Vertex Explainable AI 設定 Model 資源時指定這些名稱。這包括在特殊情況下 (一般情況下無法運作) 為 Vertex Explainable AI 建立及尋找適當的張量。

  • 將 TensorFlow 模型匯出為與 Vertex Explainable AI 相容的 TensorFlow SavedModel。

  • 從已匯出的 TensorFlow SavedModel 中找出輸入和輸出張量名稱。如果您無法存取模型的訓練程式碼,這項功能可能會有所幫助。

在訓練期間找出輸入和輸出張量名稱

使用 TensorFlow 預先建構的容器提供預測結果時,您必須知道模型的輸入張量和輸出張量名稱。為 Vertex Explainable AI 設定 Model時,您會在 ExplanationMetadata 訊息中指定這些名稱

如果您的 TensorFlow 模型符合下列條件,您就可以使用下一節所述的「基本方法」,在訓練期間判斷這些張量名稱:

  • 輸入內容並未以序列化格式輸入
  • 模型 SignatureDef 的每個輸入內容都直接包含功能的值 (可以是數值或字串)
  • 輸出內容是數字值,會視為數值資料。這項設定會排除課程 ID,因為課程 ID 屬於類別資料。

如果模型不符合這些條件,請參閱「在特殊情況下調整訓練程式碼和查找張量名稱」一節。

基本方法

在訓練期間,請列印模型輸入張量和輸出張量的 name 屬性。在以下範例中,Keras 層的 name 欄位會產生 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

接著,您可以設定 Model 以便解釋,使用 input_1:0 做為輸入張量名稱,並使用 dense_1/Sigmod:0 做為輸出張量名稱。

調整訓練程式碼,並在特殊情況下尋找張量名稱

在以下幾種常見情況下,ExplanationMetadata 的輸入和輸出張量「不應」與服務 SignatureDef 中的相同:

  • 您已序列化輸入內容
  • 圖表包含預先處理作業
  • 您的服務輸出不是機率、邏輯值或其他類型的浮點張量

在這種情況下,您應使用其他方法找出正確的輸入和輸出張量。整體目標是找出與您要解釋的輸入特徵值相關的張量,以及與對數 (預先啟用)、機率 (後續啟用) 或任何其他輸出表示法相關的張量。

輸入張量的特殊情況

如果您使用序列化的輸入內容來提供模型,或是圖表包含預先處理作業,說明中繼資料中的輸入內容就會與服務 SignatureDef 中的輸入內容不同。

已序列化的輸入內容

TensorFlow SavedModel 可接受各種複雜的輸入內容,包括:

  • 序列化的 tf.Example 訊息
  • JSON 字串
  • 已編碼的 Base64 字串 (用於代表圖片資料)

如果模型接受這類序列化的輸入內容,直接將這些張量做為說明的輸入內容可能會失敗,或產生毫無意義的結果。您應該要找出後續輸入張量,這些張量會饋送至模型中的特徵欄。

匯出模型時,您可以在服務輸入函式中呼叫剖析函式,藉此將剖析作業新增至 TensorFlow 圖表。您可以在 tf.io 模組中找到解析函式。這些剖析函式通常會傳回張量做為回應,而這些張量是說明中繼資料的最佳選擇。

舉例來說,您可以在匯出模型時使用 tf.parse_example()。它會擷取已序列化的 tf.Example 訊息,並輸出張量字典,將其餵入特徵欄。您可以使用該工具的輸出內容填入說明中繼資料。如果其中部分輸出內容是 tf.SparseTensor,也就是由 3 個張量組成的命名元組,則您應取得索引、值和 dense_shape 張量的名稱,並填入中繼資料中的對應欄位。

以下範例說明如何在解碼作業後取得輸入張量的名稱:

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)
預先處理輸入內容

如果模型圖包含一些預處理運算,您可能會想在預處理步驟之後取得張量的說明。在這種情況下,您可以使用 tf.Tensor 的 name 屬性取得這些張量的名稱,並將這些名稱放入說明中繼資料:

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 中的輸出值為機率或對數比。

如果模型會歸因於機率,但您想改為解釋對數比值,則必須找出對應對數比值的適當輸出張量名稱。

如果您的服務 SignatureDef 輸出不是機率或對數比對,您應參考訓練圖表中的機率運算。這種情況不太可能發生在 Keras 模型中。如果發生這種情況,您可以使用 TensorBoard (或其他圖表視覺化工具) 來找出正確的輸出張量名稱。

積分梯度的特別注意事項

如果您想使用 Vertex Explainable AI 的整合梯度功能歸因方法,則必須確保輸入內容相對於輸出內容可區分。

解釋中繼資料會在邏輯上將模型的特徵與輸入內容區隔開來。當您使用整合梯度,且輸入張量相對於輸出張量無法區分時,您必須提供該功能的已編碼 (且可區分) 版本。

如果您有無法微分輸入張量,或圖表中含有無法微分運算,請使用下列方法:

  1. 將不可微分的輸入內容編碼為可微分的輸入內容。
  2. input_tensor_name 設為原始的非可微分輸入張量名稱,並將 encoded_tensor_name 設為其已編碼的可微分版本名稱。

說明含有編碼的中繼資料檔案

舉例來說,假設模型含有類別特徵,且輸入張量名為 zip_codes:0。由於輸入資料包含郵遞區號字串,因此輸入張量 zip_codes:0 無法區分。如果模型也對這項資料進行預先處理,以便取得郵遞區號的單熱編碼表示法,則預先處理後的輸入張量可進行微分。為了與原始輸入張量的名稱有所區別,您可以將其命名為 zip_codes_embedding:0

如要在說明要求中使用兩個輸入張量的資料,請在設定用於說明的 Model 時,將 ExplanationMetadata 設為以下值:

  • 將輸入功能鍵設為有意義的名稱,例如 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 Explainable AI 支援的編碼清單

對於 COMBINED_EMBEDDING 編碼,輸入張量會編碼為 1D 陣列。

例如:

  • 輸入:["This", "is", "a", "test"]
  • 已編碼的輸入內容:[0.1, 0.2, 0.3, 0.4]

為 Vertex Explainable AI 匯出 TensorFlow SavedModel

訓練完 TensorFlow 模型後,請將模型匯出為 SavedModel。TensorFlow SavedModel 包含經過訓練的 TensorFlow 模型,以及執行圖形所需的序列化簽名、變數和其他資產。SavedModel 中的每個 SignatureDef 都會標示圖表中的函式,該函式會接受張量輸入內容並產生張量輸出內容。

為確保 SavedModel 與 Vertex Explainable AI 相容,請根據您使用的 TensorFlow 版本 (2 或 1),按照下列任一節的操作說明進行。

TensorFlow 2

如果您使用的是 TensorFlow 2.x,請使用 tf.saved_model.save 儲存模型。您可以在儲存模型時指定輸入簽名。如果您有一個輸入簽名,Vertex Explainable AI 會使用預設的服務函式來處理說明要求。如果您有多個輸入簽章,請在儲存模型時指定服務預設函式的簽章:

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

在這種情況下,Vertex Explainable AI 會使用您為說明要求儲存的 xai_model 鍵所對應的模型函式簽章。請使用 xai_model 這個字串做為鍵。

如果您使用預先處理函式,也必須為預先處理函式和模型函式指定簽名。您必須使用字串 xai_preprocessxai_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 Explainable AI 會使用預處理函式和模型函式來處理說明要求。請確認預處理函式的輸出內容,符合模型函式預期的輸入內容。

進一步瞭解如何在 TensorFlow 中指定服務簽章

TensorFlow 1.15

如果您使用的是 TensorFlow 1.15,請不要使用 tf.saved_model.save。Vertex Explainable AI 不支援以這種方式儲存的 TensorFlow 1 模型

如果您在 Keras 中建構及訓練模型,必須將模型轉換為 TensorFlow Estimator,然後匯出至 SavedModel。本節將著重於儲存模型。

建構、編譯、訓練及評估 Keras 模型後,您必須:

  • 使用 tf.keras.estimator.model_to_estimator 將 Keras 模型轉換為 TensorFlow Estimator
  • 使用 tf.estimator.export.build_raw_serving_input_receiver_fn 提供服務輸入函式
  • 使用 tf.estimator.export_saved_model 將模型匯出為 SavedModel。
# 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)

從 SavedModel 的 SignatureDef 取得張量名稱

您可以使用 TensorFlow SavedModel 的 SignatureDef 準備說明中繼資料,前提是該資料必須符合上一節所述「基本方法」的條件。如果您無法存取產生模型的訓練程式碼,這項功能可能會有所幫助。

如要檢查 SavedModel 的 SignatureDef,您可以使用 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 以便說明時,請在 ExplanationMetadata 訊息中使用 x:0 做為輸入張量名稱,並使用 dense/Softmax:0 做為輸出張量名稱。

後續步驟