1. 總覽
在本實驗室中,您將使用 AI Platform Notebooks 建構及訓練模型,用於識別詐欺交易,並透過 Explainable AI SDK 瞭解模型的預測結果。詐欺偵測是專為金融服務設計的異常偵測類型,為機器學習模型帶來一些有趣的挑戰:資料集本質上不平衡,且需要說明模型的結果。
課程內容
內容如下:
- 處理不平衡的資料集
- 在 AI Platform Notebooks 中,使用 tf.keras 建構及評估詐欺偵測模型
- 在筆記本中使用 Explainable AI SDK,瞭解模型將交易分類為詐欺的原因
- 將模型連同說明部署至 AI Platform,並取得已部署模型的預測結果和說明
在 Google Cloud 上執行這個實驗室的總費用約為 $1 美元。
2. 為何要偵測詐欺行為?
異常偵測很適合採用機器學習技術,因為要編寫一系列規則式陳述,以找出資料中的離群值通常很困難。詐欺偵測是異常偵測的一種,在機器學習方面有兩項有趣的挑戰:
- 極度不平衡的資料集:由於異常狀況就是異常狀況,因此數量不多。機器學習最適合處理平衡的資料集,因此當離群值占資料的比例不到 1% 時,情況可能會變得複雜。
- 需要說明結果:如果您要尋找詐欺活動,可能想知道系統為何將某個項目標示為詐欺,而不只是相信系統的判斷。可解釋性工具可協助您完成這項作業。
3. 設定環境
您必須擁有已啟用計費功能的 Google Cloud Platform 專案,才能執行這項程式碼研究室。如要建立專案,請按照這裡的說明操作。
步驟 1:啟用 Cloud AI Platform Models API
前往 Cloud Console 的 AI Platform Models 區段,如果尚未啟用,請點選「啟用」。

步驟 2:啟用 Compute Engine API
前往「Compute Engine」,然後選取「啟用」 (如果尚未啟用)。您需要這項資訊才能建立筆記本執行個體。
步驟 3:建立 AI Platform Notebooks 執行個體
前往 Cloud Console 的 AI Platform Notebooks 專區,然後點選「建立執行個體」。然後選取「TensorFlow Enterprise 2.1」執行個體類型,且「不加入任何 GPU」:

使用預設選項,然後按一下「建立」。建立執行個體後,請選取「Open JupyterLab」:

開啟執行個體後,從啟動器選取「Python 3」筆記本:

步驟 4:匯入 Python 套件
建立新的儲存格,並匯入本程式碼研究室會用到的程式庫:
import itertools
import numpy as np
import pandas as pd
import tensorflow as tf
import json
import matplotlib as mpl
import matplotlib.pyplot as plt
import explainable_ai_sdk
from sklearn.utils import shuffle
from sklearn.metrics import confusion_matrix
from sklearn.preprocessing import StandardScaler
from tensorflow import keras
from explainable_ai_sdk.metadata.tf.v2 import SavedModelMetadataBuilder
4. 下載及處理資料
我們會使用 Kaggle 的這個合成資料集來訓練模型。原始資料集包含 630 萬列,其中 8, 000 列是詐欺交易,僅占整個資料集的 0.1%!
步驟 1:下載 Kaggle 資料集並使用 Pandas 讀取
我們已在 Google Cloud Storage 中提供 Kaggle 資料集。如要下載,請在 Jupyter 筆記本中執行下列 gsutil 指令:
!gsutil cp gs://financial_fraud_detection/fraud_data_kaggle.csv .
接著,我們將資料集讀取為 Pandas DataFrame,並預覽資料集:
data = pd.read_csv('fraud_data_kaggle.csv')
data = data.drop(columns=['type'])
data.head()
預覽畫面應如下所示:

步驟 2:考量資料不平衡問題
如上所述,目前資料集包含 99.9% 的非詐欺範例。如果我們直接使用資料訓練模型,模型很可能猜測每筆交易都不是詐欺交易,因此達到 99.9% 的準確率,因為資料中 99.9% 的案例都不是詐欺交易。
處理不平衡資料的方法有幾種,這裡會使用稱為「下採樣」的技術。降採樣是指在訓練時,只使用多數類別的一小部分。在本例中,「非詐欺」是多數類別,因為這類資料占了 99.9%。
為對資料集進行下採樣,我們會採用所有約 8,000 個詐欺範例,以及約 31,000 個非詐欺案件的隨機樣本。這樣一來,產生的資料集就會有 25% 的詐欺案件,相較於先前的 0.1% 來說,比例大幅提升。
首先,將資料分割成兩個 DataFrame,一個用於詐欺,另一個用於非詐欺 (我們會在程式碼研究室稍後部署模型時使用):
fraud = data[data['isFraud'] == 1]
not_fraud = data[data['isFraud'] == 0]
然後隨機抽取非詐欺案件的樣本。我們使用 0.005%,因為這樣可將詐欺/非詐欺交易的比例設為 25 / 75。這樣就能重組資料並隨機播放。為簡化作業,我們也會移除幾個不會用於訓練的資料欄:
# Take a random sample of non fraud rows
not_fraud_sample = not_fraud.sample(random_state=2, frac=.005)
# Put it back together and shuffle
df = pd.concat([not_fraud_sample,fraud])
df = shuffle(df, random_state=2)
# Remove a few columns (isFraud is the label column we'll use, not isFlaggedFraud)
df = df.drop(columns=['nameOrig', 'nameDest', 'isFlaggedFraud'])
# Preview the updated dataset
df.head()
現在我們有更均衡的資料集。不過,如果我們發現模型收斂的準確率約為 75%,很可能表示模型在每個案例中都猜測「非詐欺」。
步驟 3:將資料分成訓練集和測試集
建構模型前,最後一個步驟是分割資料。我們會使用 80/20 的訓練/測試分割:
train_test_split = int(len(df) * .8)
train_set = df[:train_test_split]
test_set = df[train_test_split:]
train_labels = train_set.pop('isFraud')
test_labels = test_set.pop('isFraud')
*E. A. Lopez-Rojas , A. Elmir 和 S. Axelsson。「PaySim:A financial mobile money simulator for fraud detection」。In: The 28th European Modeling and Simulation Symposium-EMSS, Larnaca, Cyprus. 2016
5. 建構、訓練及評估 tf.keras 模型
我們將使用 TensorFlow 的 tf.keras API 進行建構。本節中的模型程式碼是以 TensorFlow 說明文件中的這項教學課程為基礎。首先,我們會將資料正規化,然後使用 class_weight 參數來考量剩餘的資料不平衡問題,藉此建構及訓練模型。
步驟 1:正規化資料
以數值資料訓練模型時,請務必將資料正規化,尤其是當每個資料欄的範圍不同時。這有助於防止訓練期間損失爆炸。我們可以透過下列方式將資料常態化:
scaler = StandardScaler()
train_set = scaler.fit_transform(train_set) # Only normalize on the train set
test_set = scaler.transform(test_set)
# clip() ensures all values fall within the range [-5,5]
# useful if any outliers remain after normalizing
train_set = np.clip(train_set, -5, 5)
test_set = np.clip(test_set, -5, 5)
接著,預覽正規化資料:
train_set
步驟 2:決定類別權重
在對資料進行降採樣時,我們仍想保留一部分非詐欺交易,以免遺失這些交易的資訊,因此資料並非完全平衡。由於資料集仍不平衡,且我們最重視正確識別詐欺交易,因此希望模型更重視資料集中的詐欺範例。
Keras class_weight 參數可讓我們根據每個類別在資料集中出現的頻率,準確指定要為這些類別的範例分配多少權重:
weight_for_non_fraud = 1.0 / df['isFraud'].value_counts()[0]
weight_for_fraud = 1.0 / df['isFraud'].value_counts()[1]
class_weight = {0: weight_for_non_fraud, 1: weight_for_fraud}
我們會在下一個步驟訓練模型時使用這個變數。
步驟 3:訓練及評估模型
我們會使用 Keras Sequential Model API 建構模型,這個 API 可讓我們將模型定義為一疊層。訓練期間我們會追蹤多項指標,協助瞭解模型在資料集中每個類別的成效。
METRICS = [
keras.metrics.TruePositives(name='tp'),
keras.metrics.FalsePositives(name='fp'),
keras.metrics.TrueNegatives(name='tn'),
keras.metrics.FalseNegatives(name='fn'),
keras.metrics.BinaryAccuracy(name='accuracy'),
keras.metrics.Precision(name='precision'),
keras.metrics.Recall(name='recall'),
keras.metrics.AUC(name='auc'),
]
def make_model(metrics = METRICS):
model = keras.Sequential([
keras.layers.Dense(
16, activation='relu',
input_shape=(train_set.shape[-1],)),
keras.layers.Dropout(0.5),
keras.layers.Dense(1, activation='sigmoid'),
])
model.compile(
optimizer=keras.optimizers.Adam(lr=1e-3),
loss=keras.losses.BinaryCrossentropy(),
metrics=metrics)
return model
接著,我們會定義幾個用於訓練的全域變數,以及一些提早停止參數。
EPOCHS = 100
BATCH_SIZE = 512
early_stopping = tf.keras.callbacks.EarlyStopping(
monitor='val_auc',
verbose=1,
patience=10,
mode='max',
restore_best_weights=True)
最後,我們會呼叫上方定義的函式來建立模型:
model = make_model()
model.summary()
我們可以透過 fit() 方法訓練模型,並傳遞上述定義的參數:
results = model.fit(
train_set,
train_labels,
batch_size=BATCH_SIZE,
epochs=EPOCHS,
callbacks = [early_stopping],
validation_data=(test_set, test_labels),
class_weight=class_weight)
訓練作業會在幾分鐘內完成。
步驟 4:以視覺化方式呈現模型指標
我們已經訓練好模型,現在來繪製訓練週期中的各種指標,看看模型成效如何:
mpl.rcParams['figure.figsize'] = (12, 10)
colors = plt.rcParams['axes.prop_cycle'].by_key()['color']
def plot_metrics(history):
metrics = ['loss', 'auc', 'precision', 'recall']
for n, metric in enumerate(metrics):
name = metric.replace("_"," ").capitalize()
plt.subplot(2,2,n+1)
plt.plot(history.epoch, history.history[metric], color=colors[0], label='Train')
plt.plot(history.epoch, history.history['val_'+metric],
color=colors[0], linestyle="--", label='Val')
plt.xlabel('Epoch')
plt.ylabel(name)
if metric == 'loss':
plt.ylim([0, plt.ylim()[1]])
elif metric == 'auc':
plt.ylim([0.8,1])
else:
plt.ylim([0,1])
plt.legend()
plot_metrics(results)
圖表應類似以下內容 (但不會完全相同):

步驟 5:列印混淆矩陣
混淆矩陣是呈現模型在測試資料集效能的絕佳方式。針對每個類別,這項指標會顯示模型正確和錯誤預測的測試樣本百分比。Scikit Learn 提供一些公用程式,可建立及繪製混淆矩陣,我們將在此使用這些公用程式。
在筆記本開頭,我們匯入了 confusion_matrix 公用程式。如要使用這項指標,請先建立模型預測清單。在這裡,我們會將模型傳回的值四捨五入,讓這個清單與實際資料標籤清單相符:
predicted = model.predict(test_set)
y_pred = []
for i in predicted.tolist():
y_pred.append(int(round(i[0])))
現在,我們準備將這項資料連同實際資料標籤,一併提供給 confusion_matrix 方法:
cm = confusion_matrix(test_labels.values, y_pred)
print(cm)
這會顯示模型在測試集上正確和不正確預測的絕對數字。左上方的數字表示模型正確預測為非詐欺的測試集樣本數。右下方的數字表示系統正確預測為詐欺的次數 (這是我們最重視的數字)。您會發現模型正確預測了各類別的大多數樣本。
為方便您以視覺化方式呈現,我們已改編 Scikit Learn 文件中的 plot_confusion_matrix 函式。請在此定義該函式:
def plot_confusion_matrix(cm, classes,
normalize=False,
title='Confusion matrix',
cmap=plt.cm.Blues):
"""
This function prints and plots the confusion matrix.
Normalization can be applied by setting `normalize=True`.
"""
plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(title)
plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes, rotation=45)
plt.yticks(tick_marks, classes)
if normalize:
cm = np.round(cm.astype('float') / cm.sum(axis=1)[:, np.newaxis], 3)
thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, cm[i, j],
horizontalalignment="center",
color="white" if cm[i, j] > thresh else "black")
plt.tight_layout()
plt.ylabel('True label')
plt.xlabel('Predicted label')
然後將模型中的資料傳遞給繪圖函式,即可建立繪圖。我們在此將 normalize 設為 True,混淆矩陣就會以百分比顯示正確和錯誤的預測數量:
classes = ['not fraud', 'fraud']
plot_confusion_matrix(cm, classes, normalize=True)
畫面應如下所示 (確切數字會有所不同):

從這裡可以看出,模型從測試集中的 1,594 筆詐欺交易中,正確預測了約 85%。請注意,本實驗室的重點並非模型品質。如果您要在正式環境中部署詐欺偵測模型,詐欺類別的準確率可能需要高於 85%。本實驗室的目標是介紹相關工具,協助您說明以不平衡資料集訓練的模型。
接著,我們將使用 Explainable AI SDK,瞭解模型是根據哪些特徵進行預測。
6. 使用 Explainable AI SDK
Explainable AI SDK 提供實用方法,可取得模型說明。Tensorflow AI Platform Notebook 執行個體已預先安裝此套件,請注意,我們在實驗室一開始就在筆記本中匯入了這個套件。有了 SDK,我們就能在筆記本執行個體中從模型取得特徵歸因,也就是說,我們不需要將模型部署到雲端即可使用。
在本節中,我們會將剛訓練的模型匯出為 TensorFlow SavedModel,然後將 SDK 指向儲存的模型資產,以取得說明。
步驟 1:匯出訓練好的模型
首先,請將模型儲存至筆記本執行個體中的目錄:
model_dir = 'fraud_model'
tf.saved_model.save(model, model_dir)
如果重新整理筆記本左側邊欄的資料夾檢視畫面,應該會看到名為 fraud_model/ 的新目錄。
步驟 2:使用 SDK 取得說明中繼資料
接著,我們會將 Explainable AI SDK 指向該目錄。這樣做會產生取得模型說明所需的中繼資料。get_metadata() 方法會顯示 SDK 從模型推斷的中繼資料,例如輸入名稱:
model_builder = SavedModelMetadataBuilder(model_dir)
metadata = model_builder.get_metadata()
print(metadata)
可解釋性有助於回答「為什麼模型認為這是詐欺?」這個問題。
步驟 3:指定模型基準
對於表格型資料,Explainable AI 服務會傳回每項特徵的歸因值。這些值代表特定特徵對預測結果的影響程度。假設某筆交易的金額導致模型預測的詐欺機率增加 0.2%。您可能會想「相較於什麼的 0.2%?」這帶我們來到基準的概念。
模型的基準基本上就是比較對象。我們會為模型中的每個特徵選取基準值,而基準預測值隨即會成為模型在特徵設為基準時預測的值。
選擇基準取決於您要解決的預測任務。如果是數值特徵,通常會使用資料集中每個特徵的中位數值做為基準。但就詐欺偵測而言,這並非我們想要的結果。我們最重視的是說明模型將交易標示為詐欺時的情況。也就是說,我們要比較的基準案例是不含詐欺的交易。
為此,我們會使用資料集中非詐欺交易的中位數值做為基準。我們可以運用上述擷取的 not_fraud_sample DataFrame 取得中位數,並調整中位數的比例,使其符合模型預期的輸入內容:
not_fraud_sample = not_fraud_sample.drop(columns=['nameOrig', 'nameDest', 'isFlaggedFraud', 'isFraud'])
baseline = scaler.transform(not_fraud_sample.values)
baseline = np.clip(baseline, -5, 5)
baseline_values = np.median(baseline, axis=0)
請注意,我們不需要指定基準。如果沒有,SDK 會將 0 設為模型預期每個輸入值的基準。在詐欺偵測用途中,指定基準是合理的做法,我們將在下文說明:
input_name = list(metadata['inputs'])[0]
model_builder.set_numeric_metadata(input_name, input_baselines=[baseline_values.tolist()], index_feature_mapping=df.columns.tolist()[:6])
model_builder.save_metadata(model_dir)
執行上述 save_metadata() 方法後,模型目錄中會建立名為 explanation_metadata.json 的檔案。在筆記本中,前往 fraud_model/ 目錄,確認檔案已建立。其中包含 SDK 用於產生特徵歸因的中繼資料。
步驟 4:取得模型說明
現在,我們已準備好取得個別範例的特徵歸因。為此,我們首先要使用 SDK 建立模型的本機參照:
local_model = explainable_ai_sdk.load_model_from_local_path(
model_dir,
explainable_ai_sdk.SampledShapleyConfig()
)
接著,讓我們從應分類為「詐欺」的交易範例中,取得模型的預測和說明:
fraud_example = [0.722,0.139,-0.114,-0.258,-0.271,-0.305]
response = local_model.explain([{input_name: fraud_example}])
response[0].visualize_attributions()
執行這項操作後,系統應會建立類似下方的圖表:

在本例中,帳戶在交易前的初始餘額是最大的詐欺指標,將模型的預測結果從基準線向上推升超過 0.5。交易金額、目的地帳戶的結餘和步驟是接下來最重要的指標。在資料集中,「步驟」代表時間單位 (1 步驟為 1 小時)。歸因值也可能為負值。
視覺化內容上方的「近似值誤差」會顯示說明的可信度。一般而言,如果錯誤率超過 5%,表示您可能無法依據功能歸因。請注意,說明品質取決於您使用的訓練資料和模型。改善訓練資料、模型或嘗試其他模型基準,可以減少近似誤差。
您也可以增加說明方法中使用的步驟數量,藉此減少這項錯誤。您可以使用 SDK 變更這項設定,方法是在說明設定中加入 path_count 參數 (如未指定,預設值為 10):
local_model = explainable_ai_sdk.load_model_from_local_path(
model_dir,
explainable_ai_sdk.SampledShapleyConfig(path_count=20)
)
您還可以在這個模型上使用「可解釋 AI」執行許多其他操作。例如:
- 將多個範例傳送至模型,並計算歸因值的平均值,判斷特定特徵是否整體而言更重要。我們可以運用這項資訊改善模型,並移除不重要的特徵
- 找出模型標示為詐欺但並非詐欺的交易,並檢查其歸因值
- 使用不同的基準,看看這對歸因值有何影響
🎉 恭喜!🎉
您已瞭解如何處理不平衡的資料、訓練 TensorFlow 模型來偵測詐欺交易,以及使用 Explainable AI SDK 查看模型最依賴哪些特徵進行個別預測。你可以視需要停止操作。在筆記本中使用 SDK,可讓您在部署模型前取得說明,簡化模型開發程序。建構出滿意的模型後,您可能會想部署模型,大規模取得預測結果。如果符合上述情況,請繼續進行下一個選用步驟。完成後,請跳到「清除」步驟。
7. 選用:將模型部署至 AI Platform Prediction
在本步驟中,您將瞭解如何將模型部署至 AI Platform Prediction。
步驟 1:將儲存的模型目錄複製到 Cloud Storage 值區。
透過先前執行的 SDK 步驟,您已具備將模型部署至 AI Platform 的所有必要條件。如要準備部署作業,您必須將 SavedModel 資產和說明中繼資料放入 Explainable AI 服務可讀取的 Cloud Storage bucket。
為此,我們將定義一些環境變數。在下方填入 Google Cloud 專案名稱和要建立的 bucket 名稱 (必須是全域不重複的名稱)。
# Update these to your own GCP project and model
GCP_PROJECT = 'your-gcp-project'
MODEL_BUCKET = 'gs://storage_bucket_name'
現在,我們準備建立儲存空間 bucket,用來儲存匯出的 TensorFlow 模型資產。部署模型時,我們會將 AI Platform 指向這個值區。
在筆記本中執行下列 gsutil 指令,建立 bucket:
!gsutil mb -l 'us-central1' $MODEL_BUCKET
然後將本機模型目錄複製到該值區:
!gsutil -m cp -r ./$model_dir/* $MODEL_BUCKET/explanations
步驟 2:部署模型
接著,我們會定義一些變數,用於部署指令:
MODEL = 'fraud_detection'
VERSION = 'v1'
model_path = MODEL_BUCKET + '/explanations'
我們可以使用下列 gcloud 指令建立模型:
!gcloud ai-platform models create $MODEL --region=us-central1
現在,我們準備使用 gcloud 部署這個模型的第一個版本。版本部署作業約需 5 到 10 分鐘:
!gcloud beta ai-platform versions create $VERSION \
--model $MODEL \
--origin $model_path \
--runtime-version 2.1 \
--framework TENSORFLOW \
--python-version 3.7 \
--machine-type n1-standard-4 \
--explanation-method 'sampled-shapley' \
--num-paths 10 \
--region=us-central1
在 origin 標記中,我們傳遞已儲存模型和中繼資料檔案的 Cloud Storage 位置。可解釋 AI 目前提供兩種不同的表格模型說明方法。這裡我們使用取樣 Shapley 值。num-paths 參數表示每個輸入特徵的取樣路徑數。一般來說,模型越複雜,達到合理收斂所需的近似步驟就越多。
如要確認模型是否已正確部署,請執行下列 gcloud 指令:
!gcloud ai-platform versions describe $VERSION --model $MODEL --region=us-central1
狀態應為 READY。
步驟 3:取得已部署模型的預測結果和說明
就可解釋性而言,我們最重視的是說明模型預測詐欺的案例。我們會將 5 個測試範例傳送至模型,這些範例全都是詐欺交易。
我們會使用 Google Cloud CLI 取得預測結果。執行下列程式碼,從測試集取得所有詐欺範例的索引:
fraud_indices = []
for i,val in enumerate(test_labels):
if val == 1:
fraud_indices.append(i)
接著,我們會以模型預期的格式儲存 5 個範例,並將這些範例寫入檔案:
num_test_examples = 5
instances = []
for i in range(num_test_examples):
ex = test_set[fraud_indices[i]]
instances.append({input_name: ex.tolist()})
with open('prediction.json', 'a') as outputfile:
json.dump({"instances": instances}, outputfile)
我們可以使用 gcloud 將這五個範例傳送至模型:
!gcloud beta ai-platform explain \
--model=$MODEL \
--version=$VERSION \
--region='us-central1' \
--json-request=prediction.json
在回應 JSON 中,您會看到這些範例中每項功能的歸因值。每個範例的 example_score 鍵都包含模型的預測結果,在本例中,也就是特定交易為詐欺的百分比可能性。
8. 清除
如要繼續使用這部筆電,建議在不使用時關機。在 Cloud 控制台的 Notebooks 使用者介面中,選取筆記本,然後選取「停止」:

如要刪除在本實驗室中建立的所有資源,請直接刪除筆記本執行個體,而不是停止執行個體。
使用 Cloud 控制台的導覽選單瀏覽至「儲存空間」,然後刪除您建立的兩個 bucket,以儲存模型資產。