返回文章列表

TensorFlow 模型持續評估與線上預測

本文探討 TensorFlow 模型佈署後的持續評估與線上預測方法,涵蓋評估指標監控、模型重新訓練策略、TensorFlow Serving 佈署、多重輸入簽章處理、以及使用 Apache Beam 進行批次與串流預測的最佳實務。文章提供程式碼範例與詳細說明,幫助讀者理解並應用於實際專案。

機器學習 Web 開發

模型佈署後,需要持續監控其效能並適時調整。這包含追蹤評估指標、設定警示閾值,以及決定何時重新訓練或微調模型。考量新資料量與評估指標變化,選擇從頭訓練或微調模型,確保模型維持最佳狀態。線上預測則需載入模型並透過 serving_fn 進行預測。匯出模型時可定義服務簽名,方便客戶端呼叫。客戶端載入模型後,即可使用服務函式進行預測。

持續評估是機器學習模型上線後的重要環節,用於監控模型效能並及時發現問題。透過收集實際資料、計算評估指標、設定警示閾值,可以有效追蹤模型表現。當指標低於預設閾值或資料分佈發生變化時,需要重新訓練或微調模型,以保持模型的預測準確性。重新訓練的頻率和方式取決於應用場景和資料特性,可以根據固定時間間隔、新資料量或效能指標變化來觸發。

持續評估與模型預測

持續評估的重要性

在模型佈署後,持續評估是確保模型表現穩定的關鍵步驟。持續評估能夠幫助我們及早發現潛在問題,例如預測漂移或資料分佈的變化。持續評估通常包含七個步驟:

  1. 隨機抽樣並儲存傳送給模型進行預測的資料,例如儲存1%的輸入影像。
  2. 使用模型進行預測,並儲存模型的預測結果。
  3. 將抽樣資料傳送給標註服務或稍後根據實際結果進行標註。
  4. 計算抽樣資料的評估指標,包括切片評估指標。
  5. 繪製評估指標的移動平均值,例如過去七天的Hubert損失平均值。
  6. 監控評估指標的變化或特定閾值的超限,例如如果某個監控段的準確率低於95%或本週準確率比上週低1%以上,則發出警示。
  7. 根據需要重新訓練或微調模型,將新標註的資料新增到訓練資料集中。

何時重新訓練模型

重新訓練模型的時機取決於評估指標的表現或新資料的數量。常見的選擇包括當評估指標低於某個閾值時重新訓練、每隔X天重新訓練或當收集到X個新的標註樣本時重新訓練。

是否從頭開始訓練或微調模型

另一個需要做出的決定是是否從頭開始訓練模型或僅微調現有模型。如果新樣本佔原始訓練資料的比例較小,通常選擇微調模型;當新樣本接近原始資料集的10%時,則考慮從頭開始訓練。

模型預測

載入模型並進行預測

要使用訓練好的模型進行預測,需要載入模型並呼叫服務簽名。可以使用TensorFlow的load_model方法載入模型,並透過signatures['serving_default']取得預設的服務函式。

serving_fn = tf.keras.models.load_model(MODEL_LOCATION).signatures['serving_default']

匯出模型

匯出模型時,可以指定服務簽名。例如:

model.save('export/flowers_model',
           signatures={
               'serving_default': predict_flower_type
           })

使用記憶體中的模型

客戶端程式可以載入模型並呼叫服務函式進行預測:

predictions = serving_fn(filenames)

內容解密:

  1. tf.keras.models.load_model(MODEL_LOCATION):這行程式碼的作用是從指定的MODEL_LOCATION路徑載入已經儲存的TensorFlow Keras模型。載入模型後,可以用於進行預測或其他操作。
  2. .signatures['serving_default']:取得模型的預設服務簽名。服務簽名定義了模型的輸入和輸出格式,使得模型可以被用於服務佈署。
  3. serving_fn(filenames):將檔名列表傳遞給服務函式,獲得對應的預測結果。這裡假設serving_fn已經被定義為模型的服務函式,並且filenames是一個包含輸入檔名的列表。

未來趨勢與實務應用評估

隨著機器學習技術的不斷發展,持續評估和模型監控將變得越來越重要。未來,我們可以期待看到更多自動化的監控工具和技術,能夠更有效地檢測模型漂移和其他問題。同時,如何在實際應用中平衡模型的複雜度和解釋性,也將是未來研究的一個重要方向。

視覺化圖表示例

此圖示說明瞭從載入模型到持續監控與評估的整個流程。

  1. 開始:表示整個流程的起點。
  2. 載入模型:使用tf.keras.models.load_model載入已儲存的模型。
  3. 取得服務簽名:透過.signatures['serving_default']取得模型的預設服務簽名。
  4. 進行預測:使用服務函式對輸入資料進行預測。
  5. 評估預測結果:對預測結果進行評估,以確定模型的表現。
  6. 持續監控與評估:不斷監控模型的表現,並根據需要進行調整或重新訓練。

寫作風格與可讀性提升

為了提高文章的可讀性,我們使用了自然流暢的語言,避免了過於機械或制式化的表達。同時,透過適當的類別比和比喻,使複雜的概念更容易被理解。例如,將模型的載入和預測過程比作一個Pipeline,每一步都有其特定的功能和作用,共同協作以實作最終的目標。

模型預測的挑戰與解決方案

在前面的章節中,我們探討瞭如何使用 TensorFlow 訓練模型並將其儲存為 SavedModel 格式。現在,我們將討論如何使用這個模型進行預測,並探討在不同場景下提高預測效率的方法。

記憶體內預測的限制

首先,我們來看看如何在客戶端程式中直接載入 SavedModel 並進行預測。下面的程式碼展示瞭如何使用 TensorFlow 的 serving_fn 函式對一組圖片檔案名稱進行預測:

filenames = [
    'gs://.../9818247_e2eac18894.jpg',
    ...
    'gs://.../8713397358_0505cc0176_n.jpg'
]
pred = serving_fn(tf.convert_to_tensor(filenames))

內容解密:

  1. filenames串列:此串列包含了多個圖片檔案的路徑,這些路徑使用Google Cloud Storage (gs://) 的格式儲存。
  2. serving_fn函式:這是從SavedModel載入的服務函式,用於對輸入資料進行預測。
  3. tf.convert_to_tensor(filenames):將檔案名稱串列轉換為TensorFlow張量,以便能夠被serving_fn函式處理。
  4. pred字典:儲存模型的預測結果,包含多個鍵值對,其中'flower_type_str'鍵對應的張量包含了預測的類別標籤。

預測結果儲存在 pred 字典中,可以透過呼叫 .numpy() 方法將張量轉換為 NumPy 陣列,以獲得最終的預測結果:

pred['flower_type_str'].numpy()

這種方法雖然簡單直接,但存在兩個主要問題:抽象化和效能。

提高抽象化

機器學習工程師和應用程式開發人員通常具有不同的技能和工具。為了使模型預測 API 易於被不同背景的開發者使用,需要提高抽象化程度。

目前的方法仍然需要客戶端程式具有 TensorFlow 相關知識,例如張量操作和 eager execution。為了改善這一點,可以考慮使用更通用的協定(如 HTTPS)和資料格式(如 JSON)來與模型進行互動。

提高效率

在記憶體內預測的方法中,模型直接在客戶端程式中載入和呼叫。這需要客戶端具有足夠的記憶體和計算資源(例如 GPU 或 TPU)。然而,在許多實際應用場景中,這種方法可能無法滿足效能需求。

線上預測

線上預測需要模型能夠處理多個並發請求,並且在短時間內傳回結果。這對於互動式應用(如電子商務網站的產品圖片上傳)至關重要。

批次預測

批次預測涉及對大量資料進行預測。如果每個圖片需要 300 毫秒來處理,那麼對 10,000 張圖片進行預測將需要近一小時。在某些情況下,我們可能需要更快地獲得結果。

串流預測

串流預測需要在資料到達時即時進行處理。如果系統接收到每秒約 10 張圖片,而每張圖片需要 100 毫秒來處理,那麼系統將難以跟上資料流,尤其是在流量高峰期間。

邊緣預測

邊緣預測是指在網路邊緣(例如工廠或行動裝置)進行即時預測。在這些場景中,網路頻寬可能成為瓶頸,因此需要在本地進行快速預測。

線上預測與模型佈署

線上預測需要採用微服務架構,將模型推理佈署在具備加速器的強大伺服器上。客戶端透過傳送HTTP請求並接收HTTP回應來取得模型推理結果。使用加速器和自動擴充套件基礎設施解決了效能問題,而使用HTTP請求和回應則解決了抽象化問題。

TensorFlow Serving

線上預測的推薦方法是使用TensorFlow Serving將模型佈署為回應POST請求的網路微服務。請求和回應不會是張量,而是被抽象成像JSON這樣的網路原生訊息格式。

佈署模型

TensorFlow Serving只是軟體,因此我們還需要一些基礎設施。使用者請求需要動態路由到不同的伺服器,這些伺服器需要自動擴充套件以處理流量峰值。您可以將TensorFlow Serving執行在Google Cloud的Vertex AI、Amazon SageMaker或Azure ML等託管服務上。

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title TensorFlow 模型持續評估與線上預測

package "機器學習流程" {
    package "資料處理" {
        component [資料收集] as collect
        component [資料清洗] as clean
        component [特徵工程] as feature
    }

    package "模型訓練" {
        component [模型選擇] as select
        component [超參數調優] as tune
        component [交叉驗證] as cv
    }

    package "評估部署" {
        component [模型評估] as eval
        component [模型部署] as deploy
        component [監控維護] as monitor
    }
}

collect --> clean : 原始資料
clean --> feature : 乾淨資料
feature --> select : 特徵向量
select --> tune : 基礎模型
tune --> cv : 最佳參數
cv --> eval : 訓練模型
eval --> deploy : 驗證模型
deploy --> monitor : 生產模型

note right of feature
  特徵工程包含:
  - 特徵選擇
  - 特徵轉換
  - 降維處理
end note

note right of eval
  評估指標:
  - 準確率/召回率
  - F1 Score
  - AUC-ROC
end note

@enduml

此圖示展示了線上模型預測透過REST API服務的流程。

要將SavedModel佈署為Google Cloud上的網路服務,我們需要將gcloud指向模型匯出的Google Cloud Storage位置,並將結果模型佈署到Vertex AI端點。

傳送預測請求

預測可以從任何能夠向佈署模型的伺服器傳送HTTPS呼叫的機器上獲得。資料以JSON訊息的形式來回傳送,TensorFlow Serving將JSON轉換為張量並傳送到SavedModel。

我們可以透過建立JSON請求來試用已佈署的模型:

{
  "instances": [
    {
      "filenames": "gs://.../9818247_e2eac18894.jpg"
    },
    {
      "filenames": "gs://.../9853885425_4a82356f1d_m.jpg"
    }
  ]
}

並使用gcloud將其傳送到伺服器:

gcloud ai endpoints predict ${ENDPOINT_ID} \
  --region=${REGION} \
  --json-request=request.json

程式碼實作

以下是使用Python傳送HTTPS POST請求的範例:

api = ('https://{}-aiplatform.googleapis.com/v1/projects/' +
       '{}/locations/{}/endpoints/{}:predict'.format(
           REGION, PROJECT, REGION, ENDPOINT_ID))
token = (GoogleCredentials.get_application_default()
         .get_access_token().access_token)

#### 內容解密:
此段程式碼建構了用於傳送預測請求的API網址並取得了用於身份驗證的token其中,`REGION`、`PROJECT``ENDPOINT_ID`是預先定義的環境變數用於指定請求的區域專案和端點ID。`GoogleCredentials.get_application_default()`用於取得預設的應用程式憑證並從中提取存取令牌

### 修改服務函式

目前花卉模型已被匯出以便它接受檔案名稱作為輸入並傳回包含最可能類別例如雛菊)、該類別的索引例如2以及與該類別相關聯的機率例如0.3的字典假設我們希望更改簽章以便我們還傳回與預測相關聯的檔案名稱

#### 變更預設簽章

要更改簽章首先我們載入已匯出的模型
```python
model = tf.keras.models.load_model(MODEL_LOCATION)

然後,我們定義一個具有所需新簽章的函式,確保從新函式內呼叫模型的舊簽章:

@tf.function(input_signature=[tf.TensorSpec([None,], dtype=tf.string)])
def pass_through_input(filenames):
    old_fn = model.signatures['serving_default']
    result = old_fn(filenames) 
    result['filename'] = filenames 
    return result

最後,我們將模型與新的函式一起匯出作為服務預設:

model.save(NEW_MODEL_LOCATION,
           signatures={
               'serving_default': pass_through_input
           })

內容解密:

此段程式碼定義了一個新的服務函式pass_through_input,它接受檔案名稱作為輸入,並在輸出結果中增加了輸入的檔案名稱。這樣,使用者在取得預測結果的同時,也能得到原始輸入檔案的名稱。

多重簽章支援

TensorFlow Serving允許在模型中擁有多個簽章(儘管只有其中一個將是服務預設)。例如,假設我們希望同時支援原始簽章和傳遞版本。在這種情況下,我們可以用兩個簽章匯出模型。

內容解密:

支援多重簽章使得模型能夠根據不同客戶端的需求提供不同的介面,從而提高了模型的靈活性和可用性。

在 TensorFlow Serving 中處理多種輸入簽章與批次預測的最佳實踐

在機器學習模型佈署的過程中,如何有效地處理多種輸入格式(如檔案名稱與原始位元組)以及實作高效的批次與串流預測,是提升模型服務效能的關鍵。本文將探討如何在 TensorFlow Serving 中實作這些功能,並結合 Apache Beam 進行高效的批次與串流預測。

多重簽章的匯出與應用

TensorFlow 允許模型匯出時定義多個簽章(signatures),以支援不同的輸入格式。例如,可以同時支援直接傳入檔案名稱與傳入圖片的原始位元組進行預測。

model.save('export/flowers_model3',
    signatures={
        'serving_default': predict_filename,
        'from_bytes': predict_bytes
    })

內容解密:

  1. model.save 方法:用於將訓練好的模型匯出並儲存。
  2. signatures 引數:定義多個簽章,使客戶端可以根據需求選擇合適的輸入方式。
    • serving_default:預設簽章,用於處理檔案名稱輸入。
    • from_bytes:自定義簽章,用於處理圖片的原始位元組輸入。

處理圖片原始位元組

為了支援客戶端直接傳送圖片原始位元組,需要對模型進行相應的修改。

@tf.function(input_signature=[tf.TensorSpec([None,], dtype=tf.string)])
def predict_bytes(img_bytes):
    input_images = tf.map_fn(
        preprocess, 
        img_bytes,
        fn_output_signature=tf.float32
    )
    batch_pred = model(input_images) 
    top_prob = tf.math.reduce_max(batch_pred, axis=[1])
    pred_label_index = tf.math.argmax(batch_pred, axis=1)
    pred_label = tf.gather(tf.convert_to_tensor(CLASS_NAMES), pred_label_index)
    return {
        'probability': top_prob,
        'flower_type_int': pred_label_index,
        'flower_type_str': pred_label
    }

內容解密:

  1. @tf.function 修飾符:將 Python 函式編譯為 TensorFlow 圖,提升執行效率。
  2. tf.map_fn:對輸入的 img_bytes 進行逐一處理,呼叫 preprocess 函式進行圖片解碼與預處理。
  3. model(input_images):將預處理後的圖片輸入模型進行預測。
  4. 輸出結果:包含預測機率、類別索引以及類別字串。

Base64 編碼傳輸圖片資料

為了避免圖片原始位元組中的特殊字元幹擾 JSON 解析,通常需要對圖片資料進行 Base64 編碼。

def b64encode(filename):
    with open(filename, 'rb') as ifp:
        img_bytes = ifp.read()
    return base64.b64encode(img_bytes)

內容解密:

  1. open(filename, 'rb'):以二進位制模式讀取圖片檔案。
  2. base64.b64encode(img_bytes):將二進位制圖片資料編碼為 Base64 字串,以適應 JSON 格式傳輸。

使用 Apache Beam 進行批次與串流預測

單一圖片逐一預測的方式效率較低,適合使用 Apache Beam 等分散式處理框架來實作平行處理,提升預測效能。

| 'pred' >> beam.Map(ModelPredict(MODEL_LOCATION))

內容解密:

  1. beam.Map:將 ModelPredict 函式應用於每個輸入元素,實作模型的平行預測。
  2. ModelPredict:封裝了載入模型並進行預測的邏輯,可重複使用已有的模型預測程式碼。