使用 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 不可微分。如果模型也會預先處理這項資料,以取得郵遞區號的 one-hot 編碼表示法,那麼預先處理後的輸入張量就是可微分的。為與原始輸入張量區別,您可以將其命名為 zip_codes_embedding:0

如要在說明要求中使用兩個輸入張量的資料,請在為說明Model設定 ExplanationMetadata 時,將 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 可解釋 AI 支援的編碼清單

如果是 COMBINED_EMBEDDING 編碼,輸入張量會編碼為 1D 陣列。

例如:

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

匯出 TensorFlow SavedModel,供 Vertex Explainable AI 使用

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

如要確保 SavedModel 與 Vertex Explainable AI 相容,請按照下列其中一個章節的說明操作,具體取決於您使用的是 TensorFlow 2 還是 TensorFlow 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 做為輸出張量名稱。

後續步驟