使用 TensorFlow 企業版和 BigQuery 在 Cloud AI 平台上建立詐欺偵測模型

1. 總覽

在本研究室中,您將直接擷取 BigQuery 資料集,並在 Google Cloud AI 平台中使用 TensorFlow Enterprise 訓練詐欺偵測模型。

課程內容

學習重點:

  • 在 BigQuery 上分析資料
  • 使用 TensorFlow 企業版中的 BigQuery 連接器擷取資料
  • 建構深度學習模型,以不均衡的資料集偵測詐欺

2. 在 BigQuery 中分析資料

您需要已啟用計費功能的 Google Cloud Platform 專案,才能執行這個程式碼研究室。如要建立專案,請按照這裡的操作說明進行。

步驟 1:存取 BigQuery 公開資料集

請點選這個連結,在 Google Cloud 控制台中存取 BigQuery 公開資料集。

左下角的「資源樹狀結構」會顯示資料集清單。瀏覽可用資料集,直到找到 ml-datasets 為止,然後選取當中的 ulb-fraud-detection 資料表:

d5e78261514a90ef.png

點選各個分頁標籤,進一步瞭解資料集:

  • 「結構定義」分頁會說明資料類型。
  • 「Details」分頁說明該資料集含有 284,407 筆交易,其中含有 492 筆是詐欺交易,因此是不對稱的資料集。
  • 「Preview」分頁會顯示資料集的記錄。

步驟 2:查詢資料表

詳細資料分頁會提供資料的下列資訊:

  • 「Time」是資料集中的第一筆交易和所選交易時間之間的秒數。
  • V1-V28 是透過名為 PCA 的維度縮減技術轉換的資料欄,資料經過去識別化。
  • 金額是交易金額。

現在讓我們進一步點選 [查詢資料表] 來執行查詢:

581e596426a98383.png

更新陳述式,新增 * 以查看所有資料欄,然後按一下「Run」

SELECT * FROM `bigquery-public-data.ml_datasets.ulb_fraud_detection` LIMIT 1000

步驟 3:分析資料

BigQuery 提供多種統計資料函式。接著來看看資料和目標變數「Class」之間的關聯。

SELECT CORR(Time,Class) as TimeCorr, CORR(V1,Class) as V1Corr, CORR(V2,Class) as V2Corr, CORR(Amount,Class) as AmountCorr FROM `bigquery-public-data.ml_datasets.ulb_fraud_detection`

e1e98a8315b62e9e.png

關聯會提供介於 -1 (負相關) 到 1 之間的範圍 (相關性),0 則代表獨立。

請注意,V1V2 與目標變數稍有相關 (分別介於 -0.1 和 .1 之間)。

我們看到的結果與「Time」沒有太多相關。如果關聯程度稍微降低,可能表示資料集內的詐欺交易數量較少。

「金額」的相關性甚至較低,代表詐欺交易在較高的交易金額中很有可能略高。

步驟 4:計算特徵縮放的平均值

將特徵值正規化有助於加快類神經網路的收縮作業。常見做法是將值置中,並將標準差設為 1。下列查詢會擷取平均值。這些結果並非必要,因為我們稍後都會提供程式碼片段。

您也會發現查詢中包含有趣的 WHERE 子句。下一節將介紹如何在訓練集和測試集之間分割資料。

SELECT
   AVG(Time), AVG(V1), AVG(V2), AVG(V3), AVG(V4), AVG(V5), AVG(V6), AVG(V7), AVG(V8),
   AVG(V9), AVG(V10),AVG(V11), AVG(V12), AVG(V13), AVG(V14), AVG(V15), AVG(V16),
   AVG(V17), AVG(V18), AVG(V19), AVG(V20), AVG(V21), AVG(V22), AVG(V23), AVG(V24),
   AVG(V25), AVG(V26), AVG(V27),AVG(V28), AVG(Amount)
FROM
   `bigquery-public-data.ml_datasets.ulb_fraud_detection`
WHERE
   MOD(ABS(FARM_FINGERPRINT(CONCAT(SAFE_CAST(Time AS STRING),
   SAFE_CAST(Amount AS STRING)))),10) < 8

步驟 5:分割資料

建構機器學習模型時,常見的做法是使用 3 個資料集

  • 訓練:透過反覆調整參數來建構模型
  • 驗證:可在訓練過程中驗證獨立資料,藉此評估模型是否過度配適。
  • 測試:在建立模型後用於評估準確率

在本程式碼研究室中,我們會使用 80/10/10 的訓練/驗證/測試分割。

我們會將每個資料集放入 BigQuery 對應的資料表內。第一步是建立 BigQuery「資料集」是相關資料表的容器。選取專案後,選取「建立資料集」

1084d9f5edbf760b.png

然後建立名為 tfe_codelab 的資料集,並包含訓練、驗證和測試資料表。

e5b8646ebdf5f272.png

現在,我們會針對訓練、測試和驗證執行 3 項查詢,然後將資料儲存在新的 tfe_codelab 資料集。

在查詢編輯器中執行查詢,產生訓練資料:

SELECT *
FROM `bigquery-public-data.ml_datasets.ulb_fraud_detection`
WHERE MOD(ABS(FARM_FINGERPRINT(CONCAT(SAFE_CAST(Time AS STRING),SAFE_CAST(Amount AS STRING)))),10) < 8

查詢完成後,將結果儲存至 BigQuery 資料表。

49d20c9b4b62f6a7.png

在剛建立的 tfe_codelab 資料集中,將資料表命名為 ulb_fraud_detection_train,然後儲存資料。

6d83cf113a0682e1.png

WHERE 子句會先對幾個資料欄計算雜湊,藉此分割資料。然後,選取雜湊值除以 10 低於 80 的資料列,得出 80%。

現在,請針對相似查詢選取 10% 的資料,重複相同程序來進行驗證和測試集。

驗證

SELECT *
FROM `bigquery-public-data.ml_datasets.ulb_fraud_detection`
WHERE MOD(ABS(FARM_FINGERPRINT(CONCAT(SAFE_CAST(Time AS STRING),SAFE_CAST(Amount AS STRING)))),10) = 8

將這項查詢的結果儲存至名為 ulb_fraud_detection_val 的資料表。

測試

SELECT *
FROM `bigquery-public-data.ml_datasets.ulb_fraud_detection`
WHERE MOD(ABS(FARM_FINGERPRINT(CONCAT(SAFE_CAST(Time AS STRING),SAFE_CAST(Amount AS STRING)))),10) = 9

將這項查詢的結果儲存至名為 ulb_fraud_detection_test 的資料表。

3. 設定筆記本環境

既然我們已大致瞭解一下資料,接著就來設定模型開發環境。

步驟 1:啟用 API

BigQuery 連接器會使用 BigQuery Storage API。在控制台中搜尋 BigQuery Storage API,並啟用這個 API (如果目前已停用)。

9895a2fd3cdf8f8c.png

步驟 2:建立 AI 平台筆記本執行個體

前往 Cloud 控制台的 AI 平台筆記本專區,然後按一下「新增執行個體」。接著選取最新的「TensorFlow 企業版 1.x」執行個體類型,但「不含 GPU」

35301141e9fd3f44.png

使用預設選項,然後點選「建立」。執行個體建立完成後,請選取「Open JupyterLab」

3b801f8ff3db0f2f.png

接著,從 JupyterLab 建立 Python 3 筆記本:

58523671a252b95a.png

4. 從 BigQuery 擷取記錄

步驟 1:匯入 Python 套件

在筆記本的第一個儲存格中新增下列匯入項目,然後執行儲存格。按下頂端選單中的向右箭頭按鈕,或按下 Command 鍵,即可開啟模式:

import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers

from tensorflow_io.bigquery import BigQueryClient

import functools

tf.enable_eager_execution()

步驟 2:定義常數

接下來,我們要定義一些常數,以便在專案中使用。將 GCP_PROJECT_ID 變更為您使用的實際專案 ID。請直接在建立儲存格時執行新儲存格。

GCP_PROJECT_ID = '<YOUR_PROJECT_ID>'
DATASET_GCP_PROJECT_ID = GCP_PROJECT_ID # A copy of the data is saved in the user project
DATASET_ID = 'tfe_codelab'
TRAIN_TABLE_ID = 'ulb_fraud_detection_train'
VAL_TABLE_ID = 'ulb_fraud_detection_val'
TEST_TABLE_ID = 'ulb_fraud_detection_test'

FEATURES = ['Time','V1','V2','V3','V4','V5','V6','V7','V8','V9','V10','V11','V12','V13','V14','V15','V16','V17','V18','V19','V20','V21','V22','V23','V24','V25','V26','V27','V28','Amount']
LABEL='Class'
DTYPES=[tf.float64] * len(FEATURES) + [tf.int64]

步驟 3:定義輔助函式

現在,讓我們定義幾個函式。read_session() 讀取 BigQuery 資料表中的資料。extract_labels() 是輔助函式,可將標籤欄與其他標籤區隔開來,讓資料集採用稍後的 keras.model_fit() 預期格式。

client = BigQueryClient()

def read_session(TABLE_ID):
    return client.read_session(
        "projects/" + GCP_PROJECT_ID, DATASET_GCP_PROJECT_ID, TABLE_ID, DATASET_ID,
        FEATURES + [LABEL], DTYPES, requested_streams=2
)

def extract_labels(input_dict):
  features = dict(input_dict)
  label = tf.cast(features.pop(LABEL), tf.float64)
  return (features, label)

步驟 4:擷取資料

最後,我們要建立每個資料集,然後從訓練資料集中輸出第一組批次。請注意,我們已將 BATCH_SIZE 定義為 32。這項重要參數會影響訓練的速度和準確率。

BATCH_SIZE = 32

raw_train_data = read_session(TRAIN_TABLE_ID).parallel_read_rows().map(extract_labels).batch(BATCH_SIZE)
raw_val_data = read_session(VAL_TABLE_ID).parallel_read_rows().map(extract_labels).batch(BATCH_SIZE)
raw_test_data = read_session(TEST_TABLE_ID).parallel_read_rows().map(extract_labels).batch(BATCH_SIZE)

next(iter(raw_train_data)) # Print first batch

5. 建構模型

步驟 1:預先處理資料

我們來為資料集中的每個特徵建立特徵欄。在這個特定資料集中,所有資料欄都是 numeric_column,但還有一些其他資料欄類型 (例如類別欄)。

正如先前討論的,我們也會以零為中心來設定資料中心,加快網路聚合速度。而各項特徵的意義已預先計算在這項計算中。

MEANS = [94816.7387536405, 0.0011219465482001268, -0.0021445914636999603, -0.002317402958335562,
         -0.002525792169927835, -0.002136576923287782, -3.7586818983702984, 8.135919975738768E-4,
         -0.0015535579268265718, 0.001436137140461279, -0.0012193712736681508, -4.5364970422902533E-4,
         -4.6175444671576083E-4, 9.92177789685366E-4, 0.002366229151475428, 6.710217226762278E-4,
         0.0010325807119864225, 2.557260815835395E-4, -2.0804190062322664E-4, -5.057391100818653E-4,
         -3.452114767842334E-6, 1.0145936326270006E-4, 3.839214074518535E-4, 2.2061197469126577E-4,
         -1.5601580596677608E-4, -8.235017846415852E-4, -7.298316615408554E-4, -6.898459943652376E-5,
         4.724125688297753E-5, 88.73235686453587]

def norm_data(mean, data):
  data = tf.cast(data, tf.float32) * 1/(2*mean)
  return tf.reshape(data, [-1, 1])

numeric_columns = []

for i, feature in enumerate(FEATURES):
  num_col = tf.feature_column.numeric_column(feature, normalizer_fn=functools.partial(norm_data, MEANS[i]))
  numeric_columns.append(num_col)

numeric_columns

步驟 2:建構模型

現在準備好建立模型了。我們會將剛建立的欄動態饋給到聯播網中。接著,我們會編譯模型。我們提供精確度/喚回度 AUC 指標,對於資料集不平衡的資料集來說相當實用

model = keras.Sequential([
    tf.keras.layers.DenseFeatures(numeric_columns),
    layers.Dense(64, activation='relu'),
    layers.Dense(64, activation='relu'),
    layers.Dense(1, activation='sigmoid')
])

model.compile(loss='binary_crossentropy',
              optimizer='adam',
              metrics=['accuracy', tf.keras.metrics.AUC(curve='PR')])

步驟 3:訓練模型

有很多技術可以處理不平衡的資料,包括過度取樣 (在少數類別中產生新資料) 和低取樣 (減少大多數類別中的資料)。

在本程式碼研究室中,我們將使用一項技巧,在將少數類別分類錯誤時,對損失進行超量加權。我們在訓練和權重「1」時,指定 class_weight 參數(詐欺) 較高,因為這樣較不盛行。

本研究室將使用 3 個週期 (通過資料),讓訓練速度更快。在現實生活中,我們希望執行的時間要夠長,直到停靠站顯示驗證集的準確率增加為止。

CLASS_WEIGHT = {
    0: 1,
    1: 100
}
EPOCHS = 3

train_data = raw_train_data.shuffle(10000)
val_data = raw_val_data
test_data = raw_test_data

model.fit(train_data, validation_data=val_data, class_weight=CLASS_WEIGHT, epochs=EPOCHS)

步驟 4:評估模型

評估() 函式可以套用至模型從未看過的資料,藉此提供客觀評估。幸好,我們在此提供了一些測試資料!

model.evaluate(test_data)

步驟 5:探索

在本研究室中,我們展示瞭如何將 BigQuery 大型資料集直接擷取至 TensorFlow Keras 模型。我們也完成了建立模型的所有步驟。最後,我們學到如何處理不平衡的分類問題,

您可以繼續嘗試不同的架構和方法,以使用不均衡的資料集,看看是否能提高準確率!

6. 清除

如要繼續使用這個筆記本,建議您在未使用時將其關閉。在 Cloud 控制台的「Notebooks」(筆記本) UI 中,依序選取筆記本和「Stop」(停止)

57213ef2edad9257.png

如要刪除在本研究室中建立的所有資源,只要刪除筆記本執行個體即可,不必停止執行個體。

使用 Cloud 控制台中的導覽選單前往「儲存空間」,然後刪除您為了儲存模型資產而建立的兩個值區。