【构建ML驱动的应用程序】第 10 章 :为模型构建安全措施
???🔎大家好,我是Sonhhxg_柒,希望你看完之后,能對你有所幫助,不足請指正!共同學(xué)習(xí)交流🔎
📝個人主頁-Sonhhxg_柒的博客_CSDN博客?📃
🎁歡迎各位→點贊👍 + 收藏?? + 留言📝?
📣系列專欄 - 機器學(xué)習(xí)【ML】?自然語言處理【NLP】? 深度學(xué)習(xí)【DL】
?
?🖍foreword
?說明?本人講解主要包括Python、機器學(xué)習(xí)(ML)、深度學(xué)習(xí)(DL)、自然語言處理(NLP)等內(nèi)容。
如果你對這個系列感興趣的話,可以關(guān)注訂閱喲👋
文章目錄
工程師圍繞失敗
輸入和輸出檢查
檢查輸入
模型輸出
模型失敗回退
過濾模型
性能工程師
擴展到多個用戶
機器學(xué)習(xí)緩存
模型和數(shù)據(jù)生命周期管理
再現(xiàn)性
彈力
流水線靈活性
數(shù)據(jù)處理和 DAG
尋求反饋
Chris Moody:授權(quán)數(shù)據(jù)科學(xué)家部署模型
結(jié)論
什么時候在設(shè)計數(shù)據(jù)庫或分布式系統(tǒng)時,軟件工程師關(guān)注的是容錯性,即系統(tǒng)在其某些組件發(fā)生故障時繼續(xù)工作的能力。在軟件中,問題不在于系統(tǒng)的給定部分是否會失敗,而是何時會失敗。相同的原則可以應(yīng)用于 ML。無論模型有多好,它都會在某些示例上失敗,因此您應(yīng)該設(shè)計一個能夠優(yōu)雅地處理此類失敗的系統(tǒng)。
在本章中,我們將介紹幫助預(yù)防或減輕故障的不同方法。首先,我們將了解如何驗證我們接收和生成的數(shù)據(jù)的質(zhì)量,并使用此驗證來決定如何向用戶顯示結(jié)果。然后,我們將研究如何使建模管道更加健壯,以便能夠有效地為許多用戶提供服務(wù)。之后,我們將查看利用用戶反饋的選項并判斷模型的性能。我們將以對 Chris Moody 的關(guān)于部署最佳實踐的采訪結(jié)束本章。
工程師圍繞失敗
讓我們涵蓋一些最有可能導(dǎo)致 ML 管道失敗的方法。細心的讀者會注意到,這些失敗案例與我們在“調(diào)試接線:可視化和測試”中看到的調(diào)試技巧有些相似。事實上,在生產(chǎn)環(huán)境中向用戶公開模型會帶來一系列挑戰(zhàn),這些挑戰(zhàn)與調(diào)試模型所面臨的挑戰(zhàn)相似。
錯誤和錯誤可能出現(xiàn)在任何地方,但驗證三個領(lǐng)域尤為重要:管道的輸入、模型的置信度以及它產(chǎn)生的輸出。讓我們按順序解決每個問題。
輸入和輸出檢查
任何給定的模型是在表現(xiàn)出特定特征的特定數(shù)據(jù)集上訓(xùn)練的。訓(xùn)練數(shù)據(jù)具有一定數(shù)量的特征,并且這些特征中的每一個都屬于特定類型。此外,每個特征都遵循模型為了準(zhǔn)確執(zhí)行而學(xué)習(xí)的給定分布。
正如我們在“新鮮度和分布轉(zhuǎn)變”中看到的那樣,如果生產(chǎn)數(shù)據(jù)與訓(xùn)練模型的數(shù)據(jù)不同,模型可能難以執(zhí)行。為此,您應(yīng)該檢查管道的輸入。
檢查輸入
一些當(dāng)面對數(shù)據(jù)分布的微小差異時,模型可能仍然表現(xiàn)良好。但是,如果一個模型接收到的數(shù)據(jù)與其訓(xùn)練數(shù)據(jù)有很大不同,或者如果某些特征缺失或?qū)儆谝馔忸愋?#xff0c;它將難以執(zhí)行。
正如我們之前看到的,即使輸入不正確(只要這些輸入的形狀和類型正確),ML 模型也能夠運行。模型會產(chǎn)生輸出,但這些輸出可能非常不正確。考慮圖 10-1中所示的示例。管道首先將句子矢量化并在矢量化表示上應(yīng)用分類模型,從而將句子分類為兩個主題之一。如果管道接收到一串隨機字符,它仍然會將其轉(zhuǎn)換為向量,模型會進行預(yù)測。這種預(yù)測是荒謬的,但是僅僅通過觀察模型的結(jié)果是沒有辦法知道的。
圖 10-1。模型仍將輸出對隨機輸入的預(yù)測
為了防止模型在不正確的輸出上運行,我們需要在將這些輸入傳遞給模型之前檢測這些輸入是否不正確。
檢查與測試
在本節(jié)中,我們談?wù)摰氖禽斎霗z查,而不是我們在“測試您的 ML 代碼”中看到的輸入測試。區(qū)別很微妙但很重要。測試驗證代碼在給定已知的預(yù)定輸入的情況下是否按預(yù)期運行。每次代碼或模型更改時通常都會運行測試以驗證管道是否仍然正常工作。本節(jié)中的輸入檢查是管道本身的一部分,并根據(jù)輸入質(zhì)量更改程序的控制流。失敗的輸入檢查可能會導(dǎo)致運行不同的模型或根本不運行模型。
這些檢查涵蓋與“測試您的 ML 代碼”中的測試類似的領(lǐng)域。按照重要性順序,他們將:
驗證是否存在所有必要的功能
檢查每個功能類型
驗證特征值
孤立地驗證特征值可能很困難,因為特征分布可能很復(fù)雜。執(zhí)行此類驗證的一種簡單方法是定義一個特征可以采用的合理值范圍,并驗證它是否落在該范圍內(nèi)。
如果任何輸入檢查失敗,則模型不應(yīng)運行。您應(yīng)該做什么取決于用例。如果丟失的數(shù)據(jù)代表了一條核心信息,您應(yīng)該返回一個錯誤,說明錯誤的來源。如果你估計你仍然可以提供一個結(jié)果,你可以用啟發(fā)式代替模型調(diào)用。這是通過構(gòu)建啟發(fā)式來啟動任何 ML 項目的另一個原因;它為您提供了一個后退的選擇!
在圖 10-2中,您可以看到此邏輯的示例,其中采用的路徑取決于輸入檢查的結(jié)果。
圖 10-2。輸入檢查的示例分支邏輯
以下是來自 ML Editor 的一些控制流邏輯示例,用于檢查缺失的特征和特征類型。根據(jù)輸入的質(zhì)量,它要么引發(fā)錯誤,要么運行試探法。我在這里復(fù)制了示例,但您也可以在?本書的 GitHub 存儲庫中找到它以及其余的 ML Editor 代碼。
def validate_and_handle_request(question_data):missing = find_absent_features(question_data)if len(missing) > 0:raise ValueError("Missing feature(s) %s" % missing)wrong_types = check_feature_types(question_data)if len(wrong_types) > 0:# If data is wrong but we have the length of the question, run heuristicif "text_len" in question_data.keys():if isinstance(question_data["text_len"], float):return run_heuristic(question_data["text_len"])raise ValueError("Incorrect type(s) %s" % wrong_types)return run_model(question_data)驗證模型輸入允許您縮小故障模式并識別數(shù)據(jù)輸入問題。接下來,您應(yīng)該驗證模型的輸出。
模型輸出
一次模型做出預(yù)測后,您應(yīng)該確定是否應(yīng)將其顯示給用戶。如果預(yù)測超出模型可接受的答案范圍,您應(yīng)該考慮不顯示它。
例如,如果您根據(jù)照片預(yù)測用戶的年齡,則輸出值應(yīng)介于 0 到 100 多歲之間(如果您在 3000 年閱讀本書,請隨意調(diào)整界限)。如果模型輸出的值超出此范圍,則不應(yīng)顯示它。
在這種情況下,可接受的結(jié)果不僅由合理的結(jié)果來定義。它還取決于您對對我們的用戶有用的結(jié)果類型的估計。
對于我們的 ML 編輯器,我們只想提供可操作的建議。如果一個模型預(yù)測用戶寫的所有內(nèi)容都應(yīng)該被完全刪除,這將包含一個相當(dāng)無用(和侮辱)的建議。以下是驗證模型輸出并在必要時恢復(fù)為啟發(fā)式的示例片段:
def validate_and_correct_output(question_data, model_output):# Verify type and range and raise errors accordinglytry:# Raises value error if model output is incorrectverify_output_type_and_range(model_output)except ValueError:# We run a heuristic, but could run a different model hererun_heuristic(question_data["text_len"])# If we did not raise an error, we return our model resultreturn model_output當(dāng)模型失敗時,您可以恢復(fù)到我們之前看到的啟發(fā)式方法,或者恢復(fù)到您之前構(gòu)建的更簡單的模型。嘗試早期類型的模型通常是值得的,因為不同的模型可能有不相關(guān)的錯誤。
我已經(jīng)在圖 10-3中的玩具示例中說明了這一點。在左側(cè),您可以看到具有更復(fù)雜決策邊界的性能更好的模型。在右側(cè),您可以看到一個更糟糕、更簡單的模型。較差的模型會犯更多的錯誤,但由于其決策邊界的形狀不同,其錯誤與復(fù)雜模型不同。正因為如此,更簡單的模型得到了一些正確的例子,而復(fù)雜的模型卻出錯了。這就是為什么在主模型失敗時使用簡單模型作為備份是一個合理想法的直覺。
如果您確實使用更簡單的模型作為備份,您還應(yīng)該以相同的方式驗證其輸出并回退到啟發(fā)式或如果它們未通過您的檢查則顯示錯誤。
驗證模型的輸出是否在合理范圍內(nèi)是一個好的開始,但這還不夠。在下一節(jié)中,我們將介紹我們可以圍繞模型構(gòu)建的額外保護措施。
圖 10-3。更簡單的模型通常會出現(xiàn)不同的錯誤
模型失敗回退
我們建立了檢測和糾正錯誤輸入和輸出的安全措施。然而,在某些情況下,我們模型的輸入可能是正確的,而我們模型的輸出可能是合理的,但完全錯誤。
回到從照片預(yù)測用戶年齡的例子,保證模型預(yù)測的年齡是合理的人類年齡是一個好的開始,但理想情況下我們希望預(yù)測這個特定用戶的正確年齡。
沒有一個模型會 100% 正確,輕微的錯誤通常是可以接受的,但您應(yīng)該盡可能地檢測模型何時出錯。這樣做可以讓您潛在地將給定案例標(biāo)記為太難,并鼓勵用戶提供更簡單的輸入(例如,以光線充足的照片的形式)。
那里是檢測錯誤的兩種主要方法。最簡單的方法是跟蹤模型的置信度以估計輸出是否準(zhǔn)確。第二個是構(gòu)建一個附加模型,其任務(wù)是檢測主模型可能失敗的示例。
對于第一種方法,分類模型可以輸出一個概率,該概率可用作模型對其輸出的置信度的估計。如果這些概率得到很好的校準(zhǔn)(參見“校準(zhǔn)曲線”),它們可用于檢測模型不確定的情況并決定不向用戶顯示結(jié)果。
有時,盡管為示例分配了很高的概率,但模型還是錯誤的。這就是第二種方法的用武之地:使用模型過濾掉最難的輸入。
過濾模型
除了不總是值得信賴之外,使用模型的置信度分數(shù)還有另一個嚴(yán)重的缺點。為了獲得這個分數(shù),無論是否使用其預(yù)測,都需要運行整個推理管道。例如,當(dāng)使用需要在 GPU 上運行的更復(fù)雜的模型時,這尤其浪費。理想情況下,我們希望在不運行模型的情況下估計模型在示例上的表現(xiàn)如何。
這就是過濾模型背后的想法。由于您知道模型難以處理某些輸入,因此您應(yīng)該提前檢測它們,而不用在它們上運行模型。過濾模型是輸入測試的 ML 版本。它是一個二元分類器,經(jīng)過訓(xùn)練可以預(yù)測模型是否會在給定示例上表現(xiàn)良好。這種模型之間的核心假設(shè)是,對于主要模型來說很難的數(shù)據(jù)點類型存在趨勢。如果這些困難的例子有足夠多的共同點,過濾模型可以學(xué)習(xí)將它們與更簡單的輸入分開。
以下是您可能希望過濾模型捕獲的一些類型的輸入:
-
與主模型在其上表現(xiàn)良好的輸入在質(zhì)量上不同的輸入
-
模型接受過訓(xùn)練但遇到困難的輸入
-
意在愚弄主要模型的對抗性輸入
在圖 10-4中,您可以看到圖 10-2中邏輯的更新示例,其中現(xiàn)在包含一個過濾模型。如您所見,過濾模型僅在輸入檢查通過時運行,因為您只需要過濾掉可能進入“運行模型”框的輸入。
要訓(xùn)??練過濾模型,您只需收集包含兩類示例的數(shù)據(jù)集;您的主要模型成功的類別和它失敗的其他類別。這可以使用我們的訓(xùn)練數(shù)據(jù)來完成,不需要額外的數(shù)據(jù)收集!
圖 10-4。在我們的輸入檢查中添加過濾步驟(粗體)
在圖 10-5中,我展示了如何通過利用經(jīng)過訓(xùn)練的模型及其在數(shù)據(jù)集上的結(jié)果來做到這一點,如左圖所示。對模型正確預(yù)測的一些數(shù)據(jù)點和模型預(yù)測失敗的一些數(shù)據(jù)點進行采樣。然后,您可以訓(xùn)練一個過濾模型來預(yù)測哪些數(shù)據(jù)點是原始模型失敗的數(shù)據(jù)點。
圖 10-5。獲取過濾模型的訓(xùn)練數(shù)據(jù)
一旦你有了訓(xùn)練有素的分類器,訓(xùn)練過濾模型就相對簡單了。給定一個測試集和一個訓(xùn)練有素的分類器,下面的函數(shù)就可以做到這一點。
def get_filtering_model(classifier, features, labels):"""Get prediction error for a binary classification dataset:param classifier: trained classifier:param features: input features:param labels: true labels"""predictions = classifier.predict(features)# Create labels where errors are 1, and correct guesses are 0is_error = [pred != truth for pred, truth in zip(predictions, labels)]filtering_model = RandomForestClassifier()filtering_model.fit(features, is_error)return filtering_model這個方法被谷歌用于他們的智能回復(fù)功能,它建議對收到的電子郵件進行一些簡短的回復(fù)(參見 A. Kanan 等人的這篇文章,“智能回復(fù):電子郵件的自動回復(fù)建議”)。他們使用他們所謂的觸發(fā)模型,負責(zé)決定是否運行建議響應(yīng)的主模型。在他們的案例中,只有大約 11% 的電子郵件適合這種模式。通過使用過濾模型,他們將基礎(chǔ)設(shè)施需求減少了一個數(shù)量級。
過濾模型通常需要滿足兩個標(biāo)準(zhǔn)。它應(yīng)該很快,因為它的全部目的是減少計算負擔(dān),并且應(yīng)該善于消除困難的情況。
試圖識別疑難案例的過濾模型不需要能夠捕獲所有案例;它只需要檢測到足以證明在每次推理時運行它的額外成本是合理的。通常,過濾模型越快,所需的效率就越低。原因如下:
假設(shè)您僅使用一個模型的平均推理時間是i.
使用過濾模型的平均推理時間為f+i(1-b)其中f是過濾模型的執(zhí)行時間,b是它過濾掉的示例的平均比例(b 代表塊)。
要通過使用過濾模型減少平均推理時間,您需要具備f+i(1-b)<i, 轉(zhuǎn)化為fi<b.
這意味著您的模型過濾掉的案例比例需要高于其推理速度與較大模型速度之間的比率。
例如,如果您的過濾模型比常規(guī)模型快 20 倍(fi=5%), 它需要阻止超過 5% 的案例 (5%<b) 在生產(chǎn)中有用。
當(dāng)然,您還需要確保過濾模型的精度良好,這意味著它阻止的大部分輸入實際上對您的主模型來說太難了。
一種方法是定期讓一些示例通過您的過濾模型會阻止并檢查您的主要模型如何處理它們。我們將在“選擇要監(jiān)控的內(nèi)容”中更深入地介紹這一點。
由于過濾模型不同于推理模型,專門為預(yù)測困難案例而訓(xùn)練,因此它可以比依賴主模型的概率輸出更準(zhǔn)確地檢測這些案例。因此,使用過濾模型有助于降低出現(xiàn)不良結(jié)果的可能性并提高資源利用率。
由于這些原因,將過濾模型添加到現(xiàn)有的輸入和輸出檢查中可以顯著提高生產(chǎn)管道的穩(wěn)健性。在下一節(jié)中,我們將通過討論如何將 ML 應(yīng)用程序擴展到更多用戶以及如何組織復(fù)雜的訓(xùn)練過程來解決更多使管道健壯的方法。
性能工程師
保持性能將模型部署到生產(chǎn)中是一項重大挑戰(zhàn),尤其是當(dāng)產(chǎn)品變得越來越流行并且模型的新版本會定期部署時。我們將通過討論允許模型處理大量推理請求的方法來開始本節(jié)。然后,我們將介紹可以更輕松地定期部署更新模型版本的功能。最后,我們將討論通過使訓(xùn)練管道更具可重復(fù)性來減少模型之間性能差異的方法。
擴展到多個用戶
許多軟件工作負載是水平可擴展的,這意味著增加服務(wù)器是在請求數(shù)量增加時保持合理響應(yīng)時間的有效策略。ML 在這方面沒有什么不同,因為我們可以簡單地啟動新服務(wù)器來運行我們的模型并處理額外的容量。
筆記
如果您使用深度學(xué)習(xí)模型,您可能需要 GPU 才能在可接受的時間內(nèi)提供結(jié)果。如果是這種情況,并且您希望有足夠多的請求來需要多個支持 GPU 的機器,則您應(yīng)該在兩個不同的服務(wù)器上運行您的應(yīng)用程序邏輯和模型推理。
由于 GPU 實例通常比大多數(shù)云提供商的常規(guī)實例貴一個數(shù)量級,因此使用一個更便宜的實例擴展您的應(yīng)用程序,而 GPU 實例僅處理推理將顯著降低您的計算成本。使用此策略時,您應(yīng)該記住,您正在引入一些通信開銷,并確保這不會對您的用例造成太大損害。
除了增加資源分配外,機器學(xué)習(xí)還有助于采用有效的方式來處理額外的流量,例如緩存。
機器學(xué)習(xí)緩存
緩存是將結(jié)果存儲到函數(shù)調(diào)用的做法,以便將來可以通過簡單地檢索存儲的結(jié)果來更快地調(diào)用具有相同參數(shù)的此函數(shù)。緩存是加速工程流水線的常見做法,對 ML 非常有用。
緩存推理結(jié)果
一個最近最少使用 (LRU) 緩存是一種簡單的緩存方法,它需要跟蹤模型的最新輸入及其相應(yīng)的輸出。在對任何新輸入運行模型之前,請在緩存中查找輸入。如果找到相應(yīng)的條目,則直接從緩存中提供結(jié)果。圖 10-6顯示了此類工作流程的示例。第一行表示最初遇到輸入時的緩存步驟。第二行描述了再次看到相同輸入后的檢索步驟。
圖 10-6。圖像字幕模型的緩存
這種緩存策略適用于用戶將提供相同類型輸入的應(yīng)用程序。如果每個輸入都是唯一的,這是不合適的。如果應(yīng)用程序通過拍攝爪印照片來預(yù)測它們屬于哪種動物,它應(yīng)該很少會收到兩張相同的照片,因此 LRU 緩存無濟于事。
使用緩存時,您應(yīng)該只緩存沒有副作用的函數(shù)。例如,如果run_model函數(shù)還將結(jié)果存儲到數(shù)據(jù)庫,則使用 LRU 緩存將導(dǎo)致不保存重復(fù)的函數(shù)調(diào)用,這可能不是預(yù)期的行為。
在 Python 中,該functools模塊提出了 LRU 緩存的默認實現(xiàn),您可以將其與簡單的裝飾器一起使用,如下所示:
from functools import lru_cache@lru_cache(maxsize=128) def run_model(question_data):# Insert any slow model inference belowpass緩存在檢索特征、處理特征時最有用,并且運行推理比訪問緩存慢。根據(jù)您的緩存方法(例如,在內(nèi)存中還是在磁盤上)和您使用的模型的復(fù)雜性,緩存將具有不同程度的有用性。
通過索引緩存
盡管描述的緩存方法在接收唯一輸入時不合適,我們可以緩存可以預(yù)先計算的管道的其他方面。如果模型不僅僅依賴于用戶輸入,這是最簡單的。
假設(shè)我們正在構(gòu)建一個系統(tǒng),允許用戶搜索與他們提供的文本查詢或圖像相關(guān)的內(nèi)容。如果我們預(yù)計查詢會發(fā)生顯著變化,那么緩存用戶查詢不太可能顯著提高性能。但是,由于我們正在構(gòu)建一個搜索系統(tǒng),因此我們可以訪問我們目錄中可以返回的潛在項目列表。無論我們是在線零售商還是文檔索引平臺,我們都提前知道這個列表。
這意味著我們可以預(yù)先計算僅依賴于目錄中項目的建模方面。如果我們選擇一種允許我們提前進行此計算的建模方法,我們可以更快地進行推理。
出于這個原因,構(gòu)建搜索系統(tǒng)時的一種常見方法是首先將所有索引文檔嵌入到一個有意義的向量中(有關(guān)向量化方法的更多信息,請參閱“向量化” )。創(chuàng)建嵌入后,它們可以存儲在數(shù)據(jù)庫中。這在圖 10-7的第一行中進行了說明。當(dāng)用戶提交搜索查詢時,它會在推理時嵌入,并在數(shù)據(jù)庫中執(zhí)行查找以找到最相似的嵌入并返回與這些嵌入對應(yīng)的產(chǎn)品。您可以在圖 10-7的底行中看到這一點。
這種方法顯著加快了推理速度,因為大部分計算都是提前完成的。嵌入已成功用于 Twitter(請參閱Twitter 博客上的這篇文章)和 Airbnb(請參閱 M. Haldar 等人的文章“Applying Deep Learning To Airbnb Search”?)等公司的大規(guī)模生產(chǎn)管道。
圖 10-7。帶有緩存嵌入的搜索查詢
緩存可以提高性能,但它增加了一層復(fù)雜性。緩存的大小成為一個額外的超參數(shù),需要根據(jù)應(yīng)用程序的工作負載進行調(diào)整。此外,每當(dāng)更新模型或底層數(shù)據(jù)時,都需要清除緩存以防止其提供過時的結(jié)果。更一般地說,將生產(chǎn)中運行的模型更新到新版本通常需要小心。在下一節(jié)中,我們將介紹一些有助于簡化此類更新的域。
模型和數(shù)據(jù)生命周期管理
保持最新的緩存和模型可能具有挑戰(zhàn)性。許多模型需要定期重新訓(xùn)練以保持其性能水平。雖然我們將在第 11 章介紹何時重新訓(xùn)練您的模型,但我會喜歡簡單說一下如何給用戶部署更新的模型。
經(jīng)過訓(xùn)練的模型通常存儲為二進制文件,其中包含有關(guān)其類型和體系結(jié)構(gòu)以及學(xué)習(xí)參數(shù)的信息。大多數(shù)生產(chǎn)應(yīng)用程序在啟動時會在內(nèi)存中加載經(jīng)過訓(xùn)練的模型并調(diào)用它來提供結(jié)果。用較新版本替換模型的一種簡單方法是替換應(yīng)用程序加載的二進制文件。這在圖 10-8中進行了說明,其中受新模型影響的管道的唯一方面是粗體框。
然而,在實踐中,這個過程通常要復(fù)雜得多。理想情況下,ML 應(yīng)用程序產(chǎn)生可重現(xiàn)的結(jié)果,對模型更新具有彈性,并且足夠靈活以處理重大的建模和數(shù)據(jù)處理更改。保證這一點涉及我們接下來將介紹的一些額外步驟。
圖 10-8。部署同一模型的更新版本似乎是一個簡單的更改
再現(xiàn)性
至跟蹤并重現(xiàn)錯誤,您需要知道哪個模型正在生產(chǎn)中運行。為此,需要保留經(jīng)過訓(xùn)練的模型和訓(xùn)練它們的數(shù)據(jù)集的存檔。每個模型/數(shù)據(jù)集對都應(yīng)分配一個唯一標(biāo)識符。每次在生產(chǎn)中使用模型時都應(yīng)記錄此標(biāo)識符。
在圖 10-9中,我將這些要求添加到加載和保存框中,以表示這增加了 ML 管道的復(fù)雜性。
圖 10-9。在保存和加載時添加重要的元數(shù)據(jù)
除了能夠為現(xiàn)有模型的不同版本提供服務(wù)外,生產(chǎn)流水線還應(yīng)該致力于在不造成重大停機的情況下更新模型。
彈力
啟用應(yīng)用程序在更新后加載新模型需要構(gòu)建一個進程來加載更新的模型,理想情況下不會中斷對用戶的服務(wù)。這可能包括啟動一個為更新模型提供服務(wù)的新服務(wù)器,并緩慢地將流量轉(zhuǎn)移到它,但對于更大的系統(tǒng)來說,它很快就會變得更加復(fù)雜。如果新模型表現(xiàn)不佳,我們希望能夠回滾到之前的模型。正確地完成這兩項任務(wù)具有挑戰(zhàn)性,并且傳統(tǒng)上被歸類在 DevOps 領(lǐng)域。雖然我們不會深入介紹這個領(lǐng)域,但我們將在第 11 章介紹監(jiān)控。
生產(chǎn)變更可能比更新模型更復(fù)雜。它們可以包括對數(shù)據(jù)處理的大量更改,這些更改也應(yīng)該是可部署的。
流水線靈活性
我們以前看到改進模型的最佳方法通常是通過迭代數(shù)據(jù)處理和特征生成。這意味著模型的新版本通常需要額外的預(yù)處理步驟或不同的特征。
這種變化不僅反映在模型二進制文件中,而且通常會與應(yīng)用程序的新版本相關(guān)聯(lián)。因此,當(dāng)模型進行預(yù)測時,還應(yīng)記錄應(yīng)用程序版本,以使該預(yù)測可重現(xiàn)。
這樣做會給我們的流水線增加另一層復(fù)雜性,如圖 10-10中添加的預(yù)處理和后處理框所示。這些現(xiàn)在也需要是可復(fù)制和可修改的。
部署和更新模型具有挑戰(zhàn)性。在構(gòu)建服務(wù)基礎(chǔ)架構(gòu)時,最重要的方面是能夠重現(xiàn)模型在生產(chǎn)中運行的結(jié)果。這意味著將每個推理調(diào)用與運行的模型、訓(xùn)練模型的數(shù)據(jù)集以及為該模型提供服務(wù)的數(shù)據(jù)管道版本相關(guān)聯(lián)。
圖 10-10。添加模型和應(yīng)用程序版本
數(shù)據(jù)處理和 DAG
至如前所述,為了產(chǎn)生可重現(xiàn)的結(jié)果,訓(xùn)練流水線也應(yīng)該是可重現(xiàn)的和確定性的。對于給定的數(shù)據(jù)集、預(yù)處理步驟和模型的組合,訓(xùn)練流水線應(yīng)該在每次訓(xùn)練運行時生成相同的訓(xùn)練模型。
構(gòu)建模型需要許多連續(xù)的轉(zhuǎn)換步驟,因此管道通常會在不同位置中斷。這可以確保每個部分都成功運行并且它們都以正確的順序運行。
簡化這一挑戰(zhàn)的一種方法是將我們從原始數(shù)據(jù)到訓(xùn)練模型的過程表示為有向無環(huán)圖 (DAG),每個節(jié)點代表一個處理步驟,每個步驟代表兩個節(jié)點之間的依賴關(guān)系。這個想法是數(shù)據(jù)流編程的核心,流行的 ML 庫 TensorFlow 所基于的編程范例。
DAG 是一種自然的可視化方式預(yù)處理。在圖 10-11中,每個箭頭代表一個依賴于另一個任務(wù)的任務(wù)。表示允許我們保持每個任務(wù)的簡單性,使用圖形結(jié)構(gòu)來表達復(fù)雜性。
圖 10-11。我們應(yīng)用程序的 DAG 示例
一旦我們有了 DAG,我們就可以保證我們對我們生產(chǎn)的每個模型都遵循相同的操作集。有多種解決方案可以為 ML 定義 DAG,包括活躍的開源項目,例如Apache Airflow或 Spotify 的Luigi。這兩個包都允許您定義 DAG 并提供一組儀表板,以允許您監(jiān)控 DAG 和任何相關(guān)日志的進度。
首次構(gòu)建 ML 管道時,使用 DAG 可能會不必要地麻煩,但一旦模型成為生產(chǎn)系統(tǒng)的核心部分,可重復(fù)性要求使 DAG 非常引人注目。一旦模型被定期重新訓(xùn)練和部署,任何有助于系統(tǒng)化、調(diào)試和版本化管道的工具都將成為節(jié)省時間的關(guān)鍵。
作為本章的結(jié)尾,我將介紹另一種確保模型運行良好的直接方法——詢問用戶。
尋求反饋
這個本章涵蓋的系統(tǒng)有助于確保我們及時為每位用戶提供準(zhǔn)確的結(jié)果。為了保證結(jié)果的質(zhì)量,我們介紹了檢測模型預(yù)測是否不準(zhǔn)確的策略。我們?yōu)槭裁床粏栍脩?#xff1f;
你可以通過明確要求反饋和測量隱式信號來收集用戶的反饋。您可以在顯示模型的預(yù)測時要求明確的反饋,并附上一種供用戶判斷和糾正預(yù)測的方法。這可以像詢問“這個預(yù)測有用嗎?”的對話一樣簡單。或者更微妙的東西。
例如,預(yù)算應(yīng)用程序 Mint 會自動對帳戶上的每筆交易進行分類(類別包括Travel、Food等)。如圖 10-12所示,每個類別在 UI 中顯示為一個字段,用戶可以根據(jù)需要進行編輯和更正。例如,此類系統(tǒng)允許收集有價值的反饋,以比滿意度調(diào)查更少侵入性的方式不斷改進模型。
圖 10-12。讓用戶直接修復(fù)錯誤
用戶無法為模型所做的每個預(yù)測提供反饋,因此收集隱式反饋是判斷 ML 性能的重要方法。收集此類反饋包括查看用戶執(zhí)行的操作以推斷模型是否提供了有用的結(jié)果。
隱式信號很有用,但更難解釋。您不應(yīng)該希望找到一個總是與模型質(zhì)量相關(guān)的隱式信號,而只能是一個整體相關(guān)的信號。例如,在推薦系統(tǒng)中,如果用戶點擊推薦的項目,您可以合理地假設(shè)該推薦是有效的。這并非在所有情況下都是正確的(人們有時會點擊錯誤的東西!),但只要它經(jīng)常是正確的,它就是一個合理的隱含信號。
通過收集這些信息,如圖 10-13所示,您可以估計用戶發(fā)現(xiàn)結(jié)果有用的頻率。收集此類隱式信號很有用,但會增加收集和存儲此數(shù)據(jù)的風(fēng)險,并可能引入我們在第 8 章中討論的負反饋循環(huán)。
圖 10-13。作為反饋來源的用戶操作
在你的產(chǎn)品中建立隱式反饋機制可能是收集額外數(shù)據(jù)的一種有價值的方式。許多動作可以被認為是隱式和顯式反饋的混合。
假設(shè)我們在 ML 編輯器的推薦中添加了一個“在 Stack Overflow 上提問”按鈕。通過分析哪些預(yù)測導(dǎo)致用戶點擊此按鈕,我們可以衡量足以作為問題發(fā)布的推薦的比例。通過添加這個按鈕,我們并不是直接詢問用戶這個建議是否好,而是允許他們根據(jù)它采取行動,從而給我們一個“弱標(biāo)簽”(有關(guān)弱標(biāo)簽數(shù)據(jù)的提醒,請參閱“數(shù)據(jù)類型”?)問質(zhì)量。
除了作為訓(xùn)練數(shù)據(jù)的良好來源之外,隱式和顯式用戶反饋可能是注意到 ML 產(chǎn)品性能下降的第一種方式。雖然理想情況下,應(yīng)該在向用戶顯示之前發(fā)現(xiàn)錯誤,但監(jiān)視此類反饋有助于更快地檢測和修復(fù)錯誤。我們將在第 11 章中更詳細地介紹這一點。
部署和更新模型的策略因團隊規(guī)模和他們的 ML 經(jīng)驗而異。本章中的一些解決方案對于 ML 編輯器等原型來說過于復(fù)雜。另一方面,一些在 ML 上投入了大量資源的團隊構(gòu)建了復(fù)雜的系統(tǒng),使他們能夠簡化部署過程并保證為用戶提供高質(zhì)量的服務(wù)。接下來,我將分享對 Chris Moody 的采訪,他是 Stitch Fix 的 AI Instruments 團隊的負責(zé)人,他將向我們介紹他們在部署 ML 模型時的理念。
Chris Moody:授權(quán)數(shù)據(jù)科學(xué)家部署模型
克里斯穆迪來自加州理工學(xué)院和 UCSC 的物理學(xué)背景,現(xiàn)在領(lǐng)導(dǎo) Stitch Fix 的 AI Instruments 團隊。他對 NLP 有著濃厚的興趣,并涉足深度學(xué)習(xí)、變分方法和高斯過程。他為Chainer深度學(xué)習(xí)庫做出了貢獻,為scikit-learn的超快速 Barnes–Hut 版本的 t-SNE 做出了貢獻,并用Python編寫了(為數(shù)不多的!)稀疏張量分解庫。他還構(gòu)建了自己的 NLP 模型lda2vec。
問:數(shù)據(jù)科學(xué)家在 Stitch Fix 研究模型生命周期的哪一部分?
答:在 Stitch Fix,數(shù)據(jù)科學(xué)家擁有整個建模流程。這個管道很廣泛,包括構(gòu)思、原型制作、設(shè)計和調(diào)試、ETL 以及使用 scikit-learn、pytorch 和 R 等語言和框架進行的模型訓(xùn)練。此外,數(shù)據(jù)科學(xué)家負責(zé)建立系統(tǒng)以衡量指標(biāo)并為他們的模型建立“健全性檢查”。最后,數(shù)據(jù)科學(xué)家運行 A/B 測試,監(jiān)控錯誤和日志,并根據(jù)他們觀察到的情況根據(jù)需要重新部署更新的模型版本。為了能夠做到這一點,他們利用了平臺和工程團隊所做的工作。
問:平臺團隊如何使數(shù)據(jù)科學(xué)工作更輕松?
答:平臺團隊工程師的目標(biāo)是找到正確的建模抽象。這意味著他們需要了解數(shù)據(jù)科學(xué)家的工作方式。工程師不會為從事給定項目的數(shù)據(jù)科學(xué)家構(gòu)建單獨的數(shù)據(jù)管道。他們構(gòu)建解決方案,使數(shù)據(jù)科學(xué)家能夠自己這樣做。更一般地說,他們構(gòu)建工具以使數(shù)據(jù)科學(xué)家能夠擁有整個工作流程。這使工程師能夠花更多時間改進平臺,減少構(gòu)建一次性解決方案的時間。
Q:你如何判斷模型部署后的性能?
答:Stitch Fix 的很大一部分優(yōu)勢在于讓人類和算法協(xié)同工作。例如,Stitch Fix 花費大量時間思考向其造型師呈現(xiàn)信息的正確方式。從根本上說,如果您有一個 API,一方面公開您的模型,另一方面公開用戶(例如造型師或商品買家),您應(yīng)該如何設(shè)計他們之間的交互?
乍一看,您可能很想構(gòu)建一個前端來簡單地向用戶展示您的算法結(jié)果。不幸的是,這會讓用戶覺得他們無法控制算法和整個系統(tǒng),并且當(dāng)它表現(xiàn)不佳時會導(dǎo)致沮喪。相反,您應(yīng)該將此交互視為一個反饋循環(huán),允許用戶更正和調(diào)整結(jié)果。這樣做可以讓用戶訓(xùn)練算法,并通過提供反饋對整個過程產(chǎn)生更大的影響。此外,這使您可以收集標(biāo)記數(shù)據(jù)來判斷模型的性能。
為了做好這一點,數(shù)據(jù)科學(xué)家應(yīng)該問問自己,他們?nèi)绾尾拍軐⒛P捅┞督o用戶,以便讓他們的工作更輕松,并使他們能夠使模型變得更好。這意味著,由于數(shù)據(jù)科學(xué)家最清楚什么樣的反饋對他們的模型最有用,因此他們擁有端到端的流程是不可或缺的。他們可以發(fā)現(xiàn)任何錯誤,因為他們可以看到整個反饋循環(huán)。
問:您如何監(jiān)控和調(diào)試模型?
答:當(dāng)您的工程團隊構(gòu)建出出色的工具時,監(jiān)控和調(diào)試就會變得容易得多。Stitch Fix 構(gòu)建了一個內(nèi)部工具,該工具接受建模管道并創(chuàng)建 Docker 容器、驗證參數(shù)和返回類型、將推理管道公開為 API、將其部署在我們的基礎(chǔ)設(shè)施上,并在其上構(gòu)建儀表板。該工具允許數(shù)據(jù)科學(xué)家直接修復(fù)部署期間或之后發(fā)生的任何錯誤。由于數(shù)據(jù)科學(xué)家現(xiàn)在負責(zé)對模型進行故障排除,我們還發(fā)現(xiàn)這種設(shè)置會激勵簡單而強大的模型,這些模型往往很少出現(xiàn)故障。整個管道的所有權(quán)導(dǎo)致個人優(yōu)化影響和可靠性,而不是模型復(fù)雜性。
問:你們?nèi)绾尾渴鹦碌哪P桶姹?#xff1f;
答:此外,數(shù)據(jù)科學(xué)家使用定制的 A/B 測試服務(wù)運行實驗,該服務(wù)允許他們定義粒度參數(shù)。然后他們分析測試結(jié)果,如果團隊認為他們是決定性的,他們就會自己部署新版本。
在部署方面,我們使用類似于金絲雀開發(fā)的系統(tǒng),我們首先將新版本部署到一個實例,然后在監(jiān)控性能的同時逐步更新實例。數(shù)據(jù)科學(xué)家可以訪問一個儀表板,該儀表板顯示每個版本下的實例數(shù)量以及部署過程中的連續(xù)性能指標(biāo)。
結(jié)論
在本章中,我們介紹了通過主動檢測模型的潛在故障并找到減輕故障的方法來使我們的響應(yīng)更具彈性的方法。這包括確定性驗證策略和過濾模型的使用。我們還介紹了使生產(chǎn)模型保持最新所帶來的一些挑戰(zhàn)。然后,我們討論了一些可以估計模型性能的方法。最后,我們查看了一個經(jīng)常大規(guī)模部署 ML 的公司的實際示例,以及他們?yōu)榇藰?gòu)建的流程。
在第 11 章中,我們將介紹其他方法來關(guān)注模型的性能并利用各種指標(biāo)來診斷 ML 驅(qū)動的應(yīng)用程序的健康狀況。
總結(jié)
以上是生活随笔為你收集整理的【构建ML驱动的应用程序】第 10 章 :为模型构建安全措施的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 论文写作 2: 常见的 Latex 格式
- 下一篇: Bin文件夹下的DLL可以做什么?