線上 A/B 測試在機器學習系統開發中扮演著至關重要的角色,能有效驗證新模型或演算法的效能提升。首先,必須精確估算樣本大小,才能確保實驗結果具有統計顯著性。以圖片搜尋引擎為例,可根據網站流量、點選率和轉換率等資料,計算 A/B 測試所需的最小樣本數。實驗過程中,需持續監控關鍵指標,如點選率和轉換率,並分析兩組之間的差異。實驗結束後,可採用 Bootstrap 等統計方法評估效應的分佈,並計算效應的悲觀、保守和樂觀估計值。此外,還需評估新模型上線後的潛在影響,例如預估收入提升等。最後,根據實驗結果和評估報告,決定後續步驟,例如逐步擴大新模型的覆寫範圍,或進行更進一步的實驗驗證。除了模型效能,API 設計也是系統整合的關鍵環節。良好的 API 設計應注重簡單性、可預測性和相容性,並提供完善的客戶端函式庫和錯誤處理機制。

實驗結果的評估與報告

在進行A/B測試後,我們需要對實驗結果進行深入的評估與報告,以確保測試的有效性和可靠性。

實驗設計與樣本大小估計

在實驗設計階段,我們首先需要確定樣本大小,以確保實驗結果的統計顯著性。我們採用保守的錯誤率(Type I錯誤率$\alpha = 0.01$,Type II錯誤率$\beta = 0.05$)來進行樣本大小的估計。

根據PhotoStock Inc.網站的流量資料:

  • 每日存取量:100,000次
  • 平均每次存取的搜尋查詢次數:1.5次
  • 每次查詢後平均瀏覽的照片數量:20張
  • 瀏覽照片被點選的平均比例:10%
  • 被點選照片被購買的平均比例:1%

由此可得每日瀏覽量為3,000,000次(100,000 × 1.5 × 20),點選量為300,000次,購買量為3,000次。

計算實驗所需的樣本大小

使用樣本大小估計公式: [ n = \frac{(Z_{\alpha/2} + Z_{\beta})^2 \cdot (p_A(1-p_A) + p_B(1-p_B))}{(p_B - p_A)^2} ] 其中,$p_A$和$p_B$分別代表舊版本和新版本的轉化率(CTR或CVR),$Z_x$代表給定水平下的Z統計量的臨界值。

對於CTR,假設舊版本CTR為10%,新版本CTR為10.5%,計算得出需要131,095次瀏覽。由於每天每個組別有150,000次瀏覽,因此僅需1天即可收集到足夠的資料來檢測CTR的顯著提升。

對於CVR,舊版本為0.1%,新版本為0.12%,計算得出需要978,693次瀏覽,因此需要7天來收集資料。

綜合考慮,為了滿足兩個指標的需求,實驗將執行一週,以涵蓋完整的週期性波動。

實驗結果與報告

實驗結束後,我們收集了以下指標資料:

  • CTR:A組為9.91%,B組為10.51%(+6%差異)
  • CVR:A組為0.10%,B組為0.13%(+29%差異)

初步結論表明,新搜尋引擎僅略微增加了點選率(+6%),但可點選照片的相關性顯著提高(轉化率+29%),因此A/B實驗是成功的。

擴充套件效應報告

我們採用bootstrap程式來估計效應的分佈,並將95%置信區間的下限和上限視為悲觀和樂觀的效應估計。

對於CTR:

  • 悲觀估計:+5.1%(新CTR為10.4%)
  • 保守估計:+6%(新CTR為10.5%)
  • 樂觀估計:+6.8%(新CTR為10.6%)

對於CVR:

  • 悲觀估計:+19.2%(新CVR為0.12%)
  • 保守估計:+29%(新CVR為0.13%)
  • 樂觀估計:+39.4%(新CVR為0.14%)

縮放效應評估

假設平均照片利潤為$3.0,每日存取量保持不變,將新的ML-based搜尋引擎擴充套件至全部流量後,預計收入將顯著增加。

  • 悲觀估計:每日收入$10,800(+$1,800),年度收入$3.9 million(+$600,000)
  • 保守估計:每日收入$11,700(+$2,700),年度收入$4.3 million(+$1 million)
  • 樂觀估計:每日收入$12,600(+$3,600),年度收入$4.6 million(+$1.3 million)

這些數字完全證明瞭我們所付出的努力和時間是值得的。

後續步驟

進一步的步驟將涉及進行兩到三個較短期的A/B實驗,以逐漸增加覆寫使用者的比例(例如,20% -> 30% -> 50%),確保系統的安全性、效應的可重現性以及實驗結果的可信度。

此圖示說明瞭A/B測試流程,從實驗設計到結果評估及後續決策的整個過程。

第12章:衡量與報告結果

在進行線上測試後,我們需要仔細分析實驗結果。以下幾個側面值得注意:

  • 控制指標在實驗期間未檢測到任何事件發生。
  • 平均搜尋時間略微下降,這是一個好跡象,表明使用者經驗有所改善,使用者能更快找到所需內容。
  • 結束於購買的會話數量增加,證明搜尋結果頁面(SERPs)變得更加相關。
  • 每張照片的平均利潤保持不變(約3.0美元)。

實驗後,我們回顧性地估計了有多少整體點選的照片進入了新模型的前1000名。結果顯示,這些點選的Recall@1000達到了97%。這一重要發現提示了系統的進一步改進,特別是透過新增檢索階段(候選模型)轉向兩階段管道。

第13章:整合

將系統開發完成後,如果只是放在那裡不用,是最糟糕的事情。整合是一個持續的過程,從專案的一開始就持續到系統被廢棄甚至更久。正確的整合是系統成功的關鍵,能夠更容易獲得反饋並進行改進。

本章涵蓋了API設計、發布週期、系統操作、覆寫和回退等內容。

13.1 API設計

API設計是整合過程中的關鍵部分。它可以被視為您的系統與其使用者之間的一個合約,但在簽署之前,您需要徹底閱讀它。因為一旦API設計被設定,即使系統仍在開發中,要更改它也是代價高昂的。

對於機器學習(ML)系統來說,好的API應該具備簡單性和可預測性。簡單性是指找到合適的抽象層次,而不是過度抽象。一個好的抽象應該能夠隱藏複雜的內部實作細節,使API更容易學習和使用。

圖示:API設計原則

此圖示展示了簡單性在API設計中的重要性。

對於ML系統來說,通常有很多處理程式和引數,暴露太多內部實作細節會導致過於複雜的解決方案。更好的方法是將複雜性隱藏在簡單的介面後面,提供少量的引數和方法。同時,也需要提供自定義系統行為的方式,特別是在除錯時。合理的預設值和可覆寫的引數可以大大提高使用的便捷性。

內容解密:

  1. 簡單性:使API易於理解和使用。
  2. 可預測性:讓使用者能夠預期API的行為。
  3. 抽象層次:找到適合的抽象層次以隱藏內部實作細節。
  4. 引數和方法:提供必要的引數和方法,同時避免過度複雜。

透過遵循這些原則,可以設計出更有效、更易用的API,從而促進系統的整合和成功佈署。

API 設計:可預測性與相容性的重要性

在設計 API 時,首要考慮的是其可預測性和相容性。機器學習(ML)系統由於其固有的不確定性,往往會導致 API 的輸出結果不可預測。這種不確定性可能源自多個方面,包括隨機種子、輸入資料的變化等。因此,確保 API 的輸出結果對於相同的輸入始終保持一致,是設計中的一個重要挑戰。

強制確定性行為

為了實作 API 的可預測性,可以透過多種方式強制其行為的確定性。例如,在 ML 模型中使用固定的隨機種子,或者明確傳遞隨機狀態,如 Google 的 JAX 函式庫所示。這種方法可以確保在相同的輸入下,API 的輸出結果保持一致。

def predict(features, time=None, seed=42):
    if time is None:
        time = datetime.now()
    return model.predict(features, time, seed)

內容解密:

此程式碼片段展示了一個改進的 predict 函式設計。與原始設計不同,這個版本明確控制了影響輸出結果的所有引數,包括 timeseed。如果呼叫者沒有提供 time,則預設使用目前時間。這種設計提高了 API 的可預測性,因為它允許呼叫者控制所有相關引數。

相容性問題

相容性是另一個需要仔細考慮的方面。它包括向後相容性和向前相容性。向後相容性意味著新版本的 API 應該與舊版本相容,而向前相容性則意味著舊版本的 API 應該能夠與新版本一起使用。在 ML 系統中,相容性還與底層模型的版本控制有關。

class Model:
    def __init__(self, version):
        self.version = version
        self.model = load_model(version)

    def predict(self, features, time=None, seed=42):
        if time is None:
            time = datetime.now()
        return self.model.predict(features, time, seed)

內容解密:

此程式碼片段展示瞭如何透過版本控制來管理 ML 模型。Model 類別根據指定的版本載入相應的模型,並使用該模型進行預測。這種方法確保了不同版本的模型可以共存,並且客戶端可以根據需要選擇特定的模型版本。

版本控制的挑戰

版本控制是確保相容性的關鍵。然而,在實踐中,更新模型或其依賴項而不更新版本號可能會導致不可預見的變更,從而破壞相容性。甚至看似無害的變更,例如更新 Python 版本,也可能由於底層函式庫的不同而導致結果的差異。

第13章 整合:持續整合與API最佳實踐

持續整合(CI)是捕捉問題的最佳方式。多年來,業界已經發展出多種與API合作的最佳實踐。這些實踐雖然不一定特定於機器學習系統,但往往與之相關。

13.1.1 API最佳實踐

在設計API時,有幾個重要的最佳實踐值得遵循:

  • 設計至少兩層API:外部API和內部API。外部API是內部API的子集,對使用者或其他元件公開。內部API用於實作外部API的功能,只要內部API不對使用者公開,就可以進行更改而不破壞相容性。
  • 分離ML和IO元件:當可能時,將機器學習(ML)和輸入/輸出(IO)元件分開。這使得維護和擴充套件更加容易,因為ML和IO元件可以獨立擴充套件。
  • 建立客戶端函式庫:為API建立客戶端函式庫,以簡化使用和除錯過程。這也是一個實作額外功能(如重試和逾時)的好地方。
  • 考慮嵌入功能切換:使用功能切換(或功能旗標)來控制系統的行為,而無需重新佈署或更改API/客戶端行為。

程式碼範例:簡單的API客戶端函式庫

import requests

class MLServiceClient:
    def __init__(self, api_url, timeout=10):
        self.api_url = api_url
        self.timeout = timeout

    def predict(self, input_data):
        try:
            response = requests.post(f"{self.api_url}/predict", json=input_data, timeout=self.timeout)
            response.raise_for_status()
            return response.json()
        except requests.RequestException as e:
            # #### 內容解密:
            # 這裡實作了簡單的錯誤處理,包括逾時和HTTP錯誤。
            # 使用者可以根據需要擴充套件此功能,例如新增重試邏輯。
            print(f"請求失敗:{e}")
            return None

# 使用範例
client = MLServiceClient("https://example.com/ml-api")
input_data = {"feature1": 1.0, "feature2": 2.0}
result = client.predict(input_data)
print(result)

內容解密:

此程式碼範例展示了一個簡單的客戶端函式庫,用於與ML服務的API互動。它初始化了一個客戶端,具有指定的API URL和逾時設定。predict方法向API傳送POST請求,傳遞輸入資料,並處理回應和可能的例外。錯誤處理被簡化,實際應用中可能需要根據具體需求進行擴充套件,例如新增重試機制。

13.2 發布週期

機器學習系統的發布週期與常規軟體類別似,但有兩個主要區別:

  • 測試複雜性更高:由於機器學習模型的更新可能引入不可預見的變化,因此僅執行測試可能不足以確保一切正常運作。
  • 訓練新模型耗時更長:即使用完全自動化的流程,訓練新模型通常比編譯程式碼和其他構建工件需要更多時間。

Plantuml發布週期

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
skinparam arrow {
    color #262626
    thickness 2
}
skinparam package {
    borderColor #262626
    backgroundColor #F2F2F2
    fontColor #262626
}
skinparam component {
    borderColor #262626
    backgroundColor #FFFFFF
    fontColor #262626
}

title A/B 測試結果評估與報告流程

package "實驗設計" {
    [樣本大小估計] as Sample
    [設定 Type I/II 錯誤率] as ErrorRates
    [實驗時程規劃] as Schedule
    ErrorRates -> Sample
    Sample -> Schedule
}

package "指標監控" {
    [點選率 (CTR)] as CTR
    [轉換率 (CVR)] as CVR
    [組間差異分析] as Diff
    Schedule -> CTR
    Schedule -> CVR
    CTR -> Diff
    CVR -> Diff
}

package "效應評估" {
    [Bootstrap 估計效應分佈] as Bootstrap
    [悲觀/保守/樂觀估計] as Estimate
    [預估收入影響] as Revenue
    Diff -> Bootstrap
    Bootstrap -> Estimate
    Estimate -> Revenue
}

package "後續步驟" {
    [漸進式擴大流量] as Expand
    [API 設計與整合] as API
    [長期監控模型效能] as LongTermMonitor
    Revenue -> Expand
    Expand -> API
    API -> LongTermMonitor
}

@enduml

此圖示展示了機器學習系統的發布週期,包括測試、佈署和監控階段。

內容解密:

此圖表描述了一個典型的發布流程。首先,系統會進行測試。如果測試透過,則進入佈署階段。如果測試失敗,則需要修復問題後重新測試。佈署後,系統進入監控階段。如果監控過程中發現問題,則傳回修復問題的階段;如果未發現問題,則發布流程結束。

發布週期與機器學習系統的整合挑戰

在機器學習(ML)系統的開發過程中,發布新版本是一個複雜且具有挑戰性的任務。與傳統軟體開發相比,ML系統的發布需要考慮更多的因素,包括模型的訓練時間、測試的複雜性以及變更的影響。

人工參與的必要性

許多情況下,ML系統的變更需要人工評估,以確定是否足以發布新版本。例如,當一個新的模型提高了某些樣本的效能,但同時引入了新的錯誤時,需要人工判斷是否值得發布。這種人工參與的過程可能涉及ML工程師、產品經理或領域專家。

自動化與人工審查

在某些情況下,AutoML(自動機器學習)技術可以實作模型的自動發布,無需人工審查。例如,在一個具有自動完成功能的文字編輯器中,模型的更新可以自動進行,以適應使用者的寫作風格。然而,這種情況下需要更高階的測試,以確保模型的更新不會引入錯誤。

發布週期的挑戰

與傳統軟體相比,ML系統的發布週期通常更長,因為模型的訓練需要時間。即使在測試沒有問題的情況下,修復一個錯誤也可能需要重新訓練模型,這是一個耗時的過程。因此,ML系統的設計需要考慮到發布週期的長度,並相應地調整測試和驗證的策略。

多元件系統的發布策略

對於由多個元件組成的系統,可以採用不同的發布策略。例如,在一個搜尋引擎中,索引、過濾器和API層可以獨立發布,而排名模型則需要更頻繁的驗證。這種靈活性使得非ML元件可以更快速地迭代,而ML元件則保持穩定。

藍綠佈署和金絲雀佈署

為了降低發布新版本的風險,可以採用藍綠佈署和金絲雀佈署等技術。這些技術涉及在生產環境中同時執行多個版本的系統,並根據需要將流量引導到新版本。這使得測試新版本和回復變更變得更加容易。

藍綠佈署

藍綠佈署涉及兩個完全相同的生產環境,其中一個(例如“藍色”)正在執行當前版本,而另一個(例如“綠色”)則執行新版本。一旦新版本透過驗證,所有流量都會被切換到新版本。

金絲雀佈署

金絲雀佈署則是將新版本佈署到一小部分使用者,以測試其效能和穩定性。如果新版本表現良好,則可以逐漸增加其接收的流量比例,直到完全取代舊版本。

13.3 系統運作

構建系統並將其直接與需要其輸出的其他元件整合,從產品邏輯的角度來看,這還不夠。任何系統都需要額外的連線,以確保其健康運作,包括技術和非技術相關的方面。其中一些是為了簡化維護和運作(從工程和產品的角度來看);其他的則是由於與系統相關的隱含非功能性需求(例如法律或隱私問題)。

13.3.1 技術相關的連線

持續整合(CI)通常是整個基礎設施中第一個被設定的元素。它有助於識別和解決整合問題,同時促進更順暢和更快速的開發過程。CI 的典型任務包括執行測試(單元測試或整合測試)和構建將在下游使用的工件(例如,用於進一步佈署)。然而,在 CI 層面上可能還有其他需求,例如安全測試、效能測試、成本分析(「這個版本是否需要我們啟動更多的雲端伺服器?」)、佈署到測試環境、檢查程式碼風格、報告關鍵指標等。

有兩個主要的事情不屬於系統的資料,但需要被儲存:日誌和指標。通常,公司對於如何儲存、聚合和監控日誌和指標有共同的方法,你只需要遵循這種共同的方式。我們將在下一章中對此進行詳細闡述。

系統的效能可能會出現故障,這並不令人意外。因此,系統應該連線到公司使用的警示和事件管理平台,以便值班人員意識到潛在的事件並做出適當的反應。

但是他們究竟如何反應呢?在這裡,你可能需要準備特定的「食譜」,描述預期的故障模式以及如何處理它們。此外,可能還需要額外的工具集來幫助處理緊急情況,例如用於組態的管理面板、系統特定的儀錶板等,我們將在第 16 章中介紹這些內容。

同樣,通常公司內部對於 ML 和非 ML 系統有共同的標準,因此很可能你只需要調整已經使用的軟體工具集,而不需要重新發明輪子。

設計系統需要考慮系統的整個生命週期,而不僅僅是「幸福路徑」,有一點「偏執」是有幫助的。

13.3.2 非技術相關的連線

除了純粹的技術方面,還有一些非技術方面需要被考慮。它們通常與客戶成功或合規性相關,而且並不總是顯而易見。如果使用者希望根據《通用資料保護條例》(General Data Protection Regulation)清除所有個人資料,我們應該怎麼做(回想第 11 章,想像他們的資料可以傳播得多深)?是否有法規強制要求模型具有可解釋性?在不犧牲模型效能的情況下,最好的遵循方法是什麼?如果高階主管或創業投資者遇到系統中的錯誤並且非常憤怒,我們該怎麼辦?我們如何在難以重現的場景中除錯系統的行為(例如,只有上述主管的使用者帳戶才能重現缺陷)?所有這些問題都應該在系統釋出之前得到答案,並且至少在設計階段簡要反映出來。否則,後續的更改可能會太昂貴。通常,這需要構建額外的元件,例如某些使用者模擬機制或用於資料管理或模型可解釋性的管理面板,這可能需要很多專案時間,並且需要其他團隊(例如,法律或合規團隊來理解法規,或者網頁開發團隊來構建所需的儀錶板)的幫助。

根據我們的經驗,所有這些額外的連線和考慮通常比核心系統本身需要更多時間,而且公司越大,需要的努力就越多。鑑於目前的趨勢,短期內不太可能改善,因為全球範圍內正在應用越來越多的與 ML 和隱私相關的法規。