谷歌機器學習白皮書 43 條黃金法則全解析

三川發表於2017-01-28

編者按:此白皮書為谷歌總結的機器學習(ML)最優實踐方法,濃縮了其多年技術積累與經驗,尤其是 YouTube、Google Play 和 Google+ 等平臺背後的 ML 演算法開發、維護經歷。谷歌於白皮書中總結了四十三條 ML 黃金法則,旨在幫助已經掌握了基礎知識的開發者少走彎路。鑑於其珍貴程度與技術性,雷鋒網逐條做了嚴格尊重原文的翻譯。若你已學習過機器學習課程,抑或有開發 ML 模型的經驗,那麼應當具備足夠的背景知識理解這篇文章。

術語

以下是對文中反覆出現的術語的解釋。

例項( Instance):做預測的物件。比如說,例項可以是一個網頁,你想要把它分類為“關於貓”或者“與貓不相關”。

標記(Label):預測任務的答案。它既可以是機器學習系統生成的答案,也可以是訓練資料中提供的正確答案(雷鋒網(公眾號:雷鋒網)注:比如監督學習中的人工標記)。舉例來說,一個網頁的標記可以是“關於貓”。

特徵(Feature):預測任務中例項的屬性。比如說,某網頁可能有“包含關鍵詞‘貓’”的特徵

特徵欄 (Feature Column):這是谷歌自創的術語,意為關聯特徵的集合。比如說,使用者的所有可能居住國家的集合。一個樣例的特徵欄可以有一個或多個特徵。特徵欄可被看作是 VW 系統(微軟、雅虎所用)中的名稱空間,或者場( field)。

樣例(Example):有標記的例項(具備特徵)。

模型(Model):對預測任務的統計表達。你用樣例訓練模型,然後用模型做預測。

指標(Metric):你在意的數字。可被直接優化過,也可沒有。

目標(Objective):你的演算法試圖優化的指標。

流水線(Pipeline):機器學習演算法的基礎設施;包括從前端收集資料,把它放入訓練資料文件,訓練一個或多個模型,以及把模型輸出、產品化。

概覽:

為了開發出好產品:

做機器學習這一行首先要擺正心態,你是一名(優秀的)工程師,不要拿專家的標準來要求自己。

事實上,你將要面對的大多數難題是工程問題(engineering problems)。即便是一個傑出的 ML 專家,坐擁該級別才有的資源,其大多數收穫也來自於特徵而不是 ML 演算法。所以,ML 開發的基本路線是:

保證可靠的端到端流水線

從制定合理的目標著手

用簡單的方式,加入符合常識的特徵

確保流水線始終可靠

該方法能幫你賺錢養家,並且讓很多人滿意。只有當無路可走、簡單的技巧無法再起作用時,你才需要偏離該路線。但注意,提高複雜度會拖慢將來的產品釋出。另外,當你窮盡了簡單技巧,或許就到了登堂入室、探索 ML 最前沿技術的時候了。具體請看本文機器學習第三階。

本文分為四個部分:

第一部分“1.0 做機器學習之前”,會幫你搞清楚,你建立機器學習系統的時機是否已經成熟。

第二部分“2.0 機器學習第一階”是關於設定你的第一個流水線。

第三部分“3.0 機器學習第二階”,關乎啟動和重複,同時向流水線加入新特徵。

最後一部分“4.0 機器學習第三階”是關於達到瓶頸後怎麼辦。

43 條黃金法則列表:

對釋出一個不含 ML 技術的產品,不要有顧慮

首先要設計和貫徹指標

在機器學習和複雜啟發演算法之間,選擇前者

第一個模型要簡單,把基礎設施弄好

測試基礎設施要與 ML 測試分開

複製流水線時當心資料遺落

把啟發式(heuristics)變為特徵,不然就對它們做外部處理

瞭解系統的時效性

在輸出模型之前發現問題

於無聲處聽驚雷:注意沒表現出來的故障

注意特徵欄的維護者和檔案

選擇直接優化哪個目標時,不需要想太多

選擇一個簡單、可觀察並且可歸屬(attributable)的指標來作為第一個目標

用可解釋的模型開頭,修補漏洞會更簡單

用 policy layer(規則層)把垃圾資訊過濾和質量排序分來

做好模型被推倒和重建的準備

直接以觀察到的或報告的特徵開始訓練,而不是經過學習的特徵

從不同的上下文環境中提取特徵

儘量選擇更具體的特徵

以合理的方式組合、修改現有特徵

通過線性模型學到的特徵權重的數目,大致與資料量成正比

清理不需要的特徵

你並不是一個典型的使用者

版本之間存在對等差分(symmetric difference)

選擇模型時,效能勝過預測能力

從誤差中查詢新模式、建立新特徵

嘗試量化觀察到的異常行為

注意短期行為和長期行為的差別

確保訓練和服務一樣好的最直接辦法是:儲存服務時使用的特徵,然後將這些特徵匯入日誌,以便在訓練中使用。

重視取樣資料

注意表格中的資料可能改變

儘量在訓練和服務流水線中複用程式碼

訓練和測試的資料不能相同

在二進位制分類過濾的應用場景中(例如垃圾郵件檢測),不要為了純淨的資料做太大的效能犧牲

注意排序問題的固有偏差

避免具有位置特徵的反饋迴路

測量訓練/服務偏差

如果目標之間不搭,併成為問題,就不要在新特徵上浪費時間

模型釋出決策是長期產品目標的代理

保證整合模型(ensemble)的簡潔

當效能達到瓶頸,相比精煉現存訊號,不如尋找新性質的資訊源

不要期望多樣性、個性化、相關性和受歡迎程度之間有緊密聯絡

不同產品中,你的朋友總是那一個,你的興趣不會如此

1. 0 做機器學習之前

1. 對釋出一個不含 ML 技術的產品,不要有顧慮

機器學習很酷,但要有資料。理論上,你可以把另一個相近課題的資料拿來用,調整下模型變成一個新產品。但這麼做的實際效果,通常比簡單的啟發式演算法(heuristics)還差。如果你認為機器學習能完成任務的 100%。那麼啟發式演算法能幫你完成 50%。

比如說,若你為應用商店進行 app 排名,不妨直接利用下載率和裝機量寫個簡單演算法;若你在檢測垃圾郵件,可以先把傳送過垃圾郵件的地址過濾掉。也不要在人工編輯上有顧慮。如果機器學習對於你的產品不是必需的,那麼在獲得資料之前不要用它。

2. 首先要設計和貫徹指標

在定義你的 ML 系統要做什麼之前,要儘可能多得追蹤你當前的系統。這出於以下原因:

在早期,獲得系統使用者的許可相對容易。

如果你認為有些東西在將來需要考慮,最好從現在起就收集歷史資料。

如果你設計系統時考慮了指標的工具化( metric instrumentation),會省下將來的許多力氣。你絕對不想為了指標而查詢日誌字串。

有些東西會改變,有些不會。比如說,假設你想要直接優化每日活躍使用者。但是,在你對系統的早期操作中,你也許會發現使用者體驗的大幅變化並不會顯著改變這個指標。

Google+ 團隊會衡量每次閱讀的擴充套件數(expands per read)、分享、點贊、評論,以及每使用者評論數、分享等等。然後他們利用這些資料計算髮布訊息的質量。另外要注意,能通過試驗把使用者分組並整合資料的試驗框架非常重要,參考第 12 條。

通過更靈活地收集指標,你能用更大的視角觀察系統。發現一個問題?新增一個指標來追蹤它!對上一個釋出版本的量化變動很興奮?新增指標來追蹤!

3. 在機器學習和複雜啟發演算法之間,選擇前者

一個簡單的啟發演算法能幫助產品走向市場,而複雜啟發演算法難以維護。一旦你有了資料以及需要實現的目標的藍圖,就可以轉去開發 ML。在大多數軟體工程任務中,開發者需要不停更新開發方式,不管是啟發式演算法還是 ML 模型。你會發現後者更加容易更新維護(參考第 16 條)。

2. 0 機器學習第一階

2. 1 你的第一條流水線

對於第一條流水線,關注你的系統基礎設施。雖然,設想你將要做的種種 ML 應用很有趣;但如果你無法信任自己的流水線,你會很難搞清楚狀況。

4. 第一個模型要簡單,把基礎設施弄好

第一個模型為你的產品提供了最大的助力,所以它不需要花哨。而且你會遇到許多想象之外的基礎設施問題。在你的新 ML 系統誕生之前,你需要決定:

如何獲取學習演算法的樣例

對於你的系統,“好”、“壞”的定義是什麼

如何把模型整合入應用。你可以實時應用模型,也可以線上下預計算模型,並把結果儲存好。比如對網頁預分類,然後在表格裡儲存結果。但有的任務可能需要對實時聊天資訊進行分類。

選擇簡單的特徵更容易保證:

這些特徵正確應用於學習演算法

模型學會合理的權重。

這些特徵正確應用於伺服器模型。

當你有了能可靠做到上述三點的系統,大部分的工作就已完成。簡單模型提供給你基礎的指標和行為,然後你可以用它們來測試更復雜的模型。有些團隊把目標定為“中性”的首發——故意在首次釋出不那麼重視機器學習成果,以避免分心。

5. 測試基礎設施要與 ML 測試分開

要確保基礎設施可測試,而且系統的學習部分都被包含在內,使得你能夠測試所有相關物。特別是:

測試把資料匯入演算法。檢查可填充的特徵欄是不是空的。若條件允許,手工檢查訓練演算法的輸入。若可能,把流水線資料與其他地方作比較,比如 RASTA。

測試把資料匯出訓練演算法。確保訓練環境的模型與服務環境(serving environment)的模型產生同樣的得分(詳見第 37 條)。

ML 有不可預測的因素。所以一定要對生成訓練、服務樣例的程式碼進行測試;這樣你可以在服務中載入、使用固定模型。另外,理解你的資料也十分重要。

6. 複製流水線時當心資料遺落

我們經常複製現成的流水線來建立新流水線(例如 cargo cult 程式設計),但有時舊流水線遺落了新流水線需要的資料。舉個例子, Google Plus What’s Hot(雷鋒網按:社交軟體 Google+ 的熱門新聞版塊) 的流水線會遺落舊帖子(因為它試圖為新帖子排名)。我們複製該流水線,用於 Google Plus Stream(Google+ 流)。對於後者,舊帖子仍然有意義,但新流水線仍然會丟掉資料。

另一個常見的模式是隻記錄使用者看過的資料。因此,當你需要對為什麼使用者沒有看到某個資訊進行建模,該資料完全沒用——因為所有反例已經被丟掉了。Google Play 發生過一個類似的問題:當我們開發 Google Play 應用商城主頁時,建立出的新流水線包含另外兩個登入頁面(Play Games Home and Play Home Home,遊戲主頁和家庭主頁)的樣例。但是,並沒有能夠對“樣例來自於哪個主頁”加以區分的特徵。

7. 把啟發式(heuristics)變為特徵,不然就對它們做外部處理

通常來講,ML 試圖解決的問題並不是什麼新問題——一般有現成的排名、分類等各種系統。這意味著有一大堆規則和啟發式演算法可用。這些啟發式能在你調整 ML 時起到幫助。你應該壓榨出啟發式演算法的所有資訊,這有兩個原因:1. 到 ML 系統的過渡會更順暢。2. 這些規則通常包含一大堆關於系統的直覺資訊,你絕對不想把它們扔掉。有四種利用現成啟發式演算法的途徑:

使用啟發式演算法預處理。如果該特徵非常棒,那麼這就是一個選擇。舉個垃圾郵件過濾器的例子,若發件人已經被加入黑名單,不要試圖重新學習“加入黑名單”是啥意思。直接攔截該資訊。該方法最適用於二分類任務。

建立特徵。直接用啟發式建立特徵相當棒。比如說,如果你用啟發式計算一個問題結果的相關度分值,你可以把該得分作為特徵值。之後,你或許想用 ML 技術來運算元值(比如把數值轉化為有限個獨立值集合,或與其他特徵合併),但卻拿啟發式生成的原始數值來開頭。

挖掘啟發式的原始輸入。如果有面向 APP 的啟發式把裝機量、文字中字母數目和日期組合到一起,就得考慮把它們分開——把這些輸入分開來學習。有些應用於整體的技巧可用在這裡(詳見第 40 條)。

修正標記。當你發現啟發式抓取了標記中未包含的資訊時,這是一個選擇。舉個例子,如果你試圖最大化下載量,但卻仍然想要高品質內容,那麼或許最好的方案是把標記與 APP 的平均星星得分相乘。這裡有很大的餘地。請參考“2.3 你的第一個目標”部分。

請注意啟發式為 ML 系統加入的複雜度。在新 ML 演算法中加入舊啟發式有助於平滑地過渡,但你需要考慮是否更簡單的實現方式。

2. 2 監測

總的來講,養成處理警告(alerts)的好習慣,比如對每個提醒付諸行動,並且建立一個儀表頁面(dashboard page)。

8. 瞭解系統的時效性

當你的模型已經開發出來一天、一週、一季度了,它的效果分別會降低多少?該資訊能幫助你理解維護任務的優先順序。假設模型一天沒更新,你就要損失 10% 的收入。那麼你或許要考慮僱傭專人每天維護。許多廣告服務系統每天都有需要處理的新廣告,因此必須每日更新。再舉一個例子,如果 Google Play 的搜尋 ML 模型停止更新,一個月內就會造成很大的損失。Google+ What’s Hot(雷鋒網注:熱門推薦)的一些模型,並沒有針對釋出資訊的身份確認機制,所以不需要頻繁匯出這些模型。但有身份確認機制的模型就需要非常頻繁地更新。另外需注意,時效性會隨時間而變化,尤其是為模型新增或移除特徵欄的時候。

9. 在輸出模型之前發現問題

許多 ML 系統包含該步驟:輸出模型到服務端。如果輸出的模型有問題,會直接讓使用者們遇上。而這個環節之前的問題只是訓練問題,不會影響使用者體驗。

在匯出模型之前一定要檢查,尤其要確保模型在給定資料上有合理的效果。另外,若你對資料有顧慮,不要輸出該模型。許多開發團隊會在模型輸出前檢查 ROC 曲線 (或 AUC) 下的區域。未輸出的模型存在問題,可能只需要一封 email 提醒一下。但使用者端模型出了問題,很可能需要你向上司、同事解釋一整頁。所以最好多花點時間,在影響到使用者之前做到胸有成竹。

10. 於無聲處聽驚雷:注意沒表現出來的故障

這是一個多見於機器學習、而少見於其他系統的問題。設想一個不再更新的特定表格:機器學習系統會調整,其行為仍會有合理表現,但逐漸退化。有時候開發者會發現過期幾個月的表格——這時,一個簡單的更新所提高的效能,比該季度的所有釋出新版本都要高。舉個例子,對一個特徵的取捨會因為執行情況的變化而變化:覆蓋 90% 樣例的特徵欄可能突然降低到只覆蓋 60%。Google Play 曾經就有一個過期了六個月的表格,單單更新那個表格就帶來了 2% 的安裝率提升。如果你對統計資料進行跟蹤,並偶爾人工檢查,就能減少這類失誤。

11. 注意特徵欄的維護者和檔案

如果系統很大、有許多特徵欄,你需要知道誰創立、維護了每一個特徵欄。如果你發現懂得特徵欄的那個人要跳槽了,一定要確保團隊裡有還有人知道這些資訊。雖然許多特徵欄有描述名稱,你仍然需要更詳細的解釋,知道它是什麼、從哪裡來、起什麼作用。

2. 3 你的第一個目標

你有許多關心的系統指標或度量,但 ML 演算法通常只需要一個目標——演算法試圖優化的某個數字。這裡,我要區別目標(objectives)和指標(metrics):指標是系統報告的任何數字,或許重要,或許不重要。詳見第二條。

12. 選擇直接優化哪個目標時,不需要想太多

你想要賺錢,讓使用者滿意,並且讓地球更美好。有許多你關心的指標,你應該全部都去測量(見第二條)。但在 ML 初期,你會注意到它們全都有提升,即便是那些沒有直接優化的也是如此。舉個例子,假設你關注點選數、瀏覽時間和每日活躍使用者。如果你優化點選數,你會看到瀏覽時間也在上升。

所以簡簡單單就好。當你能輕易地提高所有指標,不需要在不同指標之間的平衡上想太多。但也不要誤解這條建議:別把目標與系統最終的健康混為一談(詳見第 39 條)。另外,如果你增加了直接優化的指標,但決定不予釋出,或許有必要重新修訂目標。

13. 選擇一個簡單、可觀察並且可歸屬(attributable)的指標來作為第一個目標

很多情況下你不知道真正的目標是什麼——你以為你知道。但當你仔細觀察資料,以及對舊系統和新 ML 系統進行分析,你意識到自己其實想要對原定目標進行修改。團隊不同成員也經常無法在真正的目標上取得一致意見。ML 目標應當易於測量,並可作為“真正”目標的代理。所以最好採用簡單的 ML 目標訓練,然後考慮在這之上設一個 “policy layer”(規則層),允許你加入額外的邏輯(但願是簡單的邏輯)來做最終排名。

最容易建模的是,能被直接觀察到、並且可歸屬於系統中某個行動的使用者行為:

這個排名連結被點選了嗎?

這個排名物件被下載了嗎?

這個排名物件被轉發/回覆/發 email 了嗎?

這個排名物件被打分了嗎?

這個顯示的物件被標記為垃圾郵件/色情資訊/侮辱性資訊了嗎?

一開始要避免對間接作用建模:

使用者在第二天訪問了嗎?

使用者的訪問時間是多長?

每日活躍使用者都是誰?

其實,間接作用是非常不錯的指標,並且可在 A/B 測試和釋出決定中使用。

最後,不要試圖讓 ML 搞懂:

使用者對使用該產品滿意嗎?

使用者對體驗滿意嗎?

產品提升了使用者的福祉了嗎?

這如何影響公司的整體健康?

這些都很重要,但是極度困難。你應該用代理來替代:如果使用者感到開心,他們會在頁面停留更長時間。如果使用者滿意,他明天會再次訪問。目前,當涉及到福祉和公司健康狀態,把 ML 目標與產品本質和商業計劃之間做關聯需要人的判斷。

14. 用可解釋的模型開頭,修補漏洞會更簡單

線性迴歸、邏輯迴歸、泊松迴歸(Poisson regression)直接被概率模型驅動,每個預測都可作為概率或期望值解釋。這使得相比使用了目標、直接優化分類精度或排序效果的模型(zero?one 損失、各種 hinge 損失等等),它們修補漏洞更加簡單。如果通過對比或檢查產品系統,發現訓練裡的概率偏離了預測概率,就可能存在問題。

比如說,線上性迴歸、邏輯迴歸、泊松迴歸之中,有的資料子集裡平均預期和平均標籤相等(1-?moment 校準,或者普通校準 )。對於一個值要麼是 0 要麼是 1 的特徵,三個特徵值為 1 的樣例集就會被校準。同樣地,若某特徵下所有樣例的特徵值都是 1,它們都會被校準。

對於簡單的模型,處理反饋迴路( feedback loops )更加容易。我們經常用這些概率預期來做決定:比如以期望值(點選概率/下載量等)為標準對釋出訊息進行降序排列。但要記住,當決定採用那個模型的時候,你的決定比給定模型資料的可能性( the likelihood of the data given the model )更加重要(參考第 21 條)。

15. 用 policy layer(規則層)把垃圾資訊過濾和質量排序分來

質量排序是一門高雅的藝術,而垃圾資訊過濾是一場戰爭。對於使用你係統的人,你用來判斷高質量訊息的訊號十分顯而易見。然後,他們會據此調整他們的釋出資訊來獲得這些屬性。因此,你的質量排序應當專注於有信譽的內容——不應該讓質量排序學習器退化到給垃圾資訊高排名。同樣的,重口味內容應當與質量排序分開。而垃圾資訊過濾是另一回事了。你需要建立的特徵會不斷變化,對此要有心理準備。通常,你加入系統裡的規則有些很顯而易見(比如,若一個釋出資訊得到超過三個“垃圾資訊”票數,不要恢復它)。任何學習到的模型需要至少每天更新。內容生產者的名譽會起到相當大的作用。

在某個層級,這兩個系統的輸出需要整合在一起。需要注意的是,在搜尋結果裡過濾垃圾資訊,比過濾垃圾郵件要更加強力。 為了高質量的分類器而去除訓練資料中的垃圾,已是行業標準。

3. 0 機器學習第二階段

3. 1 特徵工程

在進行機器學習相關實踐的第一階段,你要關注的主要問題包括以下三個方面:一是將訓練資料匯入系統,二是確定系統的重點關注指標,三是保證底層基礎設施的穩定可靠。當這三個問題都確認無誤,即已經搭建了一個端到端的可穩定執行的系統,並且針對系統本身和其中的每個單元都經過了嚴格測試,這時就可以進入第二階段了。

應該說,第二階段將更容易取得成績。這一階段會有許多顯著的特徵(feature)被匯入系統,因此,匯入並以直觀的方式組合這些特徵,將是本階段涉及的主要任務。另外,本階段也更適合多位工程師協同工作,共同對此前匯入的訓練資料進行整合和處理,推動所有的指標(metric)在本階段取得持續性的上升。

16. 做好模型被推倒和重建的準備

不要指望從頭到尾只使用一個模型,也不要指望著某一結點之後就不用重建模型了,模型的推倒和重建是機器學習過程中的必修課。另外,每加入一個新特性都必須考慮是否會拉低模型的執行效率。目前,許多團隊每三個月或一年就會新建一個模型。這裡我們總結了一般情況下引發模型重建的三大原因:

1) 增加新的特徵

2) 打算重組舊的特徵,或對舊模型正則化

3) 修訂建模目標

無論如何,建立模型時多想想並沒有什麼壞處:例如檢查訓練資料是否有更合理的組織形式,考慮當前的建模方式是否便於特徵的修改和重組,當前的機器學習流水線(pipeline)是否便於建立副本並檢驗其正確率,以及是否可以建立兩到三個副本並行執行等等。最後需要指出的是,並不一定非要在一個機器學習流水線中覆蓋所有特徵,在下一個版本中實現也是可行的。

17. 直接以觀察到的或報告的特徵開始訓練,而不是經過學習的特徵

這一點建議或許存在一些爭議,但的確能避免許多潛在的問題。這裡經過學習的特徵(learned feature)是指由外部系統(例如無監督的聚類系統)或模型本身(例如通過深度學習和因子模型)產生的特徵。這兩種情況雖然的確可以使用,但並不適合系統的第一個模型。

首先,在使用外部系統建立特徵時必須要格外小心。因為外部系統的目標可能與當前系統並不相符,而且從外部系統更新當前系統的特徵,其特定的含義也可能改變。

另一方面,因子模型和深度模型的主要問題是它們是非凸的(non-convex),因此它們無法保證可以最終找到或近似找到最優解,它們在每次迭代中產生的區域性最小值都可能變化,而且目前無法評估這種變化對系統的影響是有益的還是有害的。通過建立沒有深度特徵的模型,你就可以獲得很好的基準效能。在實現這一基準效能之後,你可以嘗試更高階的方法。

18. 從不同的上下文環境中提取特徵

通常情況下,機器學習只佔到一個大系統中的很小一部分,因此你必須要試著從不同角度審視一個使用者行為。比如熱門推薦這一場景,一般情況下論壇裡“熱門推薦”裡的帖子都會有許多評論、分享和閱讀量,如果利用這些統計資料對模型展開訓練,然後對一個新帖子進行優化,就有可能使其成為熱門帖子。另一方面,YouTube 上自動播放的下一個視訊也有許多選擇,例如可以根據大部分使用者的觀看順序推薦,或者根據使用者評分推薦等。總之,如果你將一個使用者行為用作模型的標記(label),那麼在不同的上下文條件下審視這一行為,可能會得到更豐富的特徵(feature),也就更利於模型的訓練。需要注意的是這與個性化不同:個性化是確定使用者是否在特定的上下文環境中喜歡某一內容,並發現哪些使用者喜歡,喜歡的程度如何。

19. 儘量選擇更具體的特徵

在海量資料的支援下,即使學習數百萬個簡單的特徵也比僅僅學習幾個複雜的特徵要容易實現。由於被檢索的文字標識與規範化的查詢並不會提供太多的歸一化資訊,只會調整頭部查詢中的標記排序。因此你不必擔心雖然整體的資料覆蓋率高達 90% 以上,但針對每個特徵組裡的單一特徵卻沒有多少訓練資料可用的情況。另外,你也可以嘗試正則化的方法來增加每個特徵所對應的樣例數。

20. 以合理的方式組合、修改現有的特徵

目前有多種方法組合、修改現有的特徵,由於本文以 Google 工具為背景,因此在這裡推薦兩種 TensorFlow 框架已實現好的方法:“離散化”(discretizations)和“交叉”(crosses)。

離散化主要包含提取連續特徵和從連續特徵中建立離散特徵兩個部分。比如對於年齡這一連續的特徵,你就可以建立這樣的離散特徵:當年齡小於 18 時結果為1,或者當年齡介於 18-35 之間時為1,等等。另外,不要過分考慮直方圖中基本分位數的問題。

在 TensorFlow 的術語中,特徵欄是一組相似的特徵,比如{男性,女性},{美國,加拿大,墨西哥}等。這裡的交叉是指將兩個或多個特徵欄合併,例如{男性,女性}×{美國,加拿大,墨西哥}的結果就是一個交叉(a cross),也就構成了一個新的特徵欄。假設你利用 TensorFlow 框架建立了這樣一個交叉,其中也就包含了{男性,加拿大}的特徵,因此這一特徵也就會出現在男性加拿大人的樣例中。需要注意的是,交叉方法中合併的特徵欄越多,所需要的訓練資料量就越大。

如果通過交叉法生成的特徵欄特別龐大,那麼就可能引起過擬合。例如,假設你正在進行某種搜尋,並且在查詢請求和文件中都具有一個包含關鍵字的特徵欄。那麼假如你選擇用交叉法組合這兩個特徵欄,這樣得到的新特徵欄就會非常龐大,它內部包含了許多特徵。當這種情況發生在文字搜尋場景時,有兩種可行的應對方法。最常用的是點乘法(dot produc),點乘法最常見的處理方式就是統計查詢請求和文件中共同的所有特徵詞,然後對特徵離散化。另一個方法是交集(intersection),比如當且僅當關鍵詞同時出現在文件和查詢結果中時,我們才能獲取所需的特徵。

21. 通過線性模型學到的特徵權重的數目,大致與資料量成正比

許多人都認為從一千個樣例中並不能得到什麼可靠的訓練結果,或者由於選擇了某種特定的模型,就必須獲取一百萬個樣例,否則就沒法展開模型訓練。這裡需要指出的是,資料量的大小是和需要訓練的特徵數是正相關的:

1) 假如你在處理一個搜尋排名問題,文件和查詢請求中包含了數百萬個不同的關鍵詞,並且有一千個被標記的樣例,那麼你應該用上文提到的點乘法處理這些特徵。這樣就能得到一千個樣例,對應了十幾個特徵。

2) 如你有一百萬個樣例,那麼通過正則化和特徵選擇的方式就可以交叉處理文件和查詢請求中的特徵欄,這可能會產生數百萬的特徵數,但再次使用正則化可以大大減少冗餘特徵。這樣就可能得到一千萬個樣例,對應了十萬個特徵。

3) 如果你有數十億或數百億個樣例,那同樣可以通過特徵選擇或正則化的方法交叉處理文件和查詢請求中的特徵欄。這樣就可能得到十億個樣例,對應了一千萬個特徵。

對特徵數和樣例來說,這些統計學上的結論並不能給出一個具體的比例關係,但卻可以從數量級上給出一些指導。另外,這裡推薦使用者依照第 28 條建議來選擇具體使用哪些特徵。

22. 清理不需要的特徵

如果你發現有些特徵並沒有在使用,而且將其與其他特徵相結合之後也無法使用的話,就應該清理這些特徵。應該保持系統的清潔,這樣才能儘快嘗試那些最有希望出結果的特徵。而且,如果有必要,被刪除的特徵也可以隨時找人加回來。

在考慮增刪一個特徵時,應該仔細排查其覆蓋範圍。例如你有一些個性化的特徵,但只有大約8% 的使用者使用了該特徵,那麼刪掉或新增這個特徵就不會有太大影響。

另一方面,增刪特徵時也要考慮其對應的資料量。例如你有一個只覆蓋了1% 資料的特徵,但有 90% 的包含這一特徵的樣例都通過了訓練,那麼這就是一個很好的特徵,應該新增。

3. 2 對系統的人工分析

在進入機器學習實踐的第三階段之前,關注一些課堂上不曾教授的問題也同樣至關重要,比如如何檢查一個模型並改進它。要說這一點是一門科學,反而不如說它是一種藝術,這裡我們介紹幾點反面模式(anti-patterns)。

23. 你並不是一個典型的使用者

這可能是讓一個團隊陷入困境的最簡單的方法。雖然 fishfooding(只在團隊內部使用原型)和 dogfooding(只在公司內部使用原型)都有許多優點,但無論哪一種,開發者都應該首先確認這種方式是否符合效能要求。另一方面,應該儘量避免不好的變化,但任何看起來合理的產品策略都應該被進一步驗證,例如通過非專業人士在眾包平臺上的問卷調查,或者請目標使用者來實測。

走外部驗證渠道的原因來自兩個方面:一是作為開發者,你太熟悉程式碼。例如你可能正在分析資料的某一方面而非全域性,或者投入了太多的個人感情色彩,從而引發一些偏見。二是幾位工程師開一個小時的討論會議得到的評估結果,可能遠比不上直接交給眾包平臺來得簡單和有效。

如果你真的想要獲取使用者反饋,那麼應該採用使用者體驗法(user experience methodologies)。 在流程早期建立使用者角色(詳情見 Bill Buxton 的《Designing User ExperienCES》一書),然後進行可用性測試(詳情見 Steve Krug 的《Do not Make Me Think》一書)。這裡的使用者角色涉及建立假想使用者。例如,假設你的團隊成員都是男性,現在要針對 35 歲女性使用者研發一款產品,那麼基於目標群體建立一個假想角色,肯定比幾位 25-40 歲的男性開發者閉門造車的效果要好。當然,讓使用者實測產品並觀察他們的反應也是很不錯的方法。

24. 版本之間存在對等差分(symmetric difference)

將產品交付至使用者之前,有時候最簡單有效的做法就是評估當前版本與交付版本的差異。例如面對排名問題,你可以在兩個版本間利用同一組樣例進行測試,然後對比其結果。如果差異很小,那麼意味著這個版本沒問題。如果差異很大,那麼就需要確認進行了哪些修改,為什麼進行這些修改。通過檢視哪些測試樣例造成了這一差異,也有助於定性瞭解修改具體是怎樣的。總之,目標是確保不同版本的模型之間的對等差分做到最小。

25. 選擇模型時,效能勝過預測能力

你的模型可能會被用來預測點選率,但更關鍵問題是:這種預測是應用在什麼場景的。如果你用它來排列文件,那麼最終排名的質量顯然比預測本身更重要。如果你用它來排查垃圾郵件,那麼識別精度顯然更重要。大多數情況下,這兩類功能應該是一致的,如果他們存在不一致,則意味著系統可能存在某種小增益。因此,假如一個改進措施可以解決日誌丟失的問題,但卻造成了系統效能的下降,那就不要採用它。當這種情況頻繁發生時,通常應該重新審視你的建模目標。

26. 從誤差中查詢新模式、建立新特徵

假設你的模型在某個樣例中預測錯誤。在分類任務中,這可能是誤報或漏報。在排名任務中,這可能是一個正向判斷弱於逆向判斷的組。但更重要的是,在這個樣例中機器學習系統知道它錯了,需要修正。如果你此時給模型一個允許它修復的特徵,那麼模型將嘗試自行修復這個錯誤。

另一方面,如果你嘗試基於未出錯的樣例建立特徵,那麼該特徵將很可能被系統忽略。例如,假設在谷歌 Play 商店的應用搜尋中,有人搜尋“免費遊戲”,但其中一個排名靠前的搜尋結果卻是一款其他 App,所以你為其他 App 建立了一個特徵。但如果你將其他 App 的安裝數最大化,即人們在搜尋免費遊戲時安裝了其他 App,那麼這個其他 App 的特徵就不會產生其應有的效果。

所以,正確的做法是一旦出現樣例錯誤,那麼應該在當前的特徵集之外尋找解決方案。例如,如果你的系統降低了內容較長的帖子的排名,那就應該普遍增加帖子的長度。而且也不要拘泥於太具體的細節。例如你要增加帖子的長度,就不要猜測長度的具體含義,而應該直接新增幾個相關的特徵,交給模型自行處理,這才是最簡單有效的方法。

27. 嘗試量化觀察到的異常行為

有時候團隊成員會對一些沒有被現有的損失函式覆蓋的系統屬性感到無能為力,但這時抱怨是沒用的,而是應該盡一切努力將抱怨轉換成實實在在的數字。例如,當有些開發者認為在谷歌 Play 商店的搜尋結果中顯示了過多的其他 App,就可以選擇人工識別的方法剔除這些 App(這時是可以選擇人工標記資料的,因為相對較小的 App 查詢可能佔了很大一部分流量)。首先要確認你的問題是可量化的,然後才可以根據這些問題建立新的特徵(features)、目標(objectives)或者指標(metrics)。總之規則是:先量化,再優化。

28. 注意短期行為和長期行為的差別

假設你有一個新系統,它可以檢視每個 doc_id 和 exact_query,然後根據每個文件的每次查詢行為計算其點選率。你發現它的行為幾乎與當前系統的並行和A/B測試結果完全相同,而且它很簡單,於是你啟動了這個系統。但卻沒有新的應用顯示,為什麼?由於你的系統只基於自己的歷史查詢記錄顯示文件,所以不知道應該顯示一個新的文件。

要了解一個系統在長期行為中如何工作的唯一辦法,就是讓它只基於當前的模型資料展開訓練。這一點非常困難。

3. 3 訓練服務的偏差(Training?-Serving Skew)

這裡訓練服務偏差是指系統在訓練時的效能表現和服務中的效能表現出現差別。造成這種差別的原因可能有如下三個方面:

1) 在訓練和服務中的資料處理流水線不同;

2) 在訓練和服務中使用了不同的資料;

3) 模型和演算法間的反饋迴路引起。

我們注意到谷歌的機器學習系統也存在訓練服務偏差,而且會對效能產生負面影響。這裡需要說明的是:最好的解決辦法就是明確地監視它,使系統和資料的改變不至於引發潛在的偏差。

29. 確保訓練和服務一樣好的最直接辦法是:儲存服務時使用的特徵,然後將這些特徵匯入日誌,以便在訓練中使用

即使你不能對每個樣例都這樣做,做一小部分也比什麼也不做好,這樣你就可以驗證服務和訓練之間的一致性(見規則 37)。在谷歌採取了這項措施的團隊有時候會對其效果感到驚訝。比如 YouTube 主頁在服務時會切換到日誌記錄特徵,這不僅大大提高了服務質量,而且減少了程式碼複雜度。目前有許多團隊都已經在其基礎設施上採用了這種策略。

30. 重視取樣資料

當資料太多時,有些團隊可能會選擇丟棄一部分以減輕負擔。這是一個明顯的錯誤:歷史經驗證明在訓練過程中丟棄資料將引發一系列問題(詳見規則6)。當然,有時候的確可以丟棄資料,比如那些從未向使用者顯示過的,但重要性加權卻是更好的選擇。重要性加權意味著,如果你決定以 30% 的概率對樣例X進行抽樣,則權重應該是3/10。值得一提的是,使用重要性加權並不影響規則 14 中討論的校準屬性。

31. 注意表格中的資料可能改變

假設你通過包含檔案特徵的表格(表格中還可能包含評論或點選的次數)加入檔案的 ID 資訊,那麼需要注意表格中的特徵可能會在訓練和服務的不同時間點發生一些變化,造成模型對同一文件的預測也跟著改變。避免此類問題的最簡單方法是在服務時記錄特徵(請參閱規則 32)。如果表格的變化足夠緩慢的話,你可以每天或每小時都記錄一次表格以獲得非常接近的資料,但需要注意的是,這並不能完全解決問題。

32. 儘量在訓練和服務流水線中複用程式碼

首先需要明確的一點是:批處理與線上處理不同。線上處理中,你必須在每個請求到達時及時處理(例如必須為每個查詢單獨查詢);而在批處理中,你可以組合任務(例如建立聯結)。類似的,可以將服務視為線上處理過程,而訓練視為批處理過程,而其中有許多程式碼是可以複用的。比如說,你可以建立特定於系統的物件,其中的所有聯結和查詢結果都以人類可讀的方式儲存,錯誤也可以被簡單地測試。然後,一旦在服務或訓練期間收集了所有資訊,你就可以通過一種通用方法在這個特定物件和機器學習系統需要的格式之間形成互通,訓練和服務的偏差也得以消除。另外,由此推知:最好不要在訓練和服務期間使用不同的程式語言(因為不同的語言間幾乎無法複用)。

33. 訓練和測試的資料不能相同

一般來說,最好用不同的資料對模型進行訓練和測試,例如你用 1 月 5 日之前的資料訓練了一個模型,那麼最好用 1 月 6 日之後的資料對模型展開測試。可能模型對新資料的效能表現不如訓練資料,但也不會太糟。由於可能會產生每日效應(daily effects),因此你可能無法預測平均點選率或轉化率,但曲線下方的面積(表示正面樣例的分數高於反面樣例的可能性)應該是接近的。

34. 在二進位制分類過濾的應用場景中(例如垃圾郵件檢測),不要為了純淨的資料做太大的效能犧牲

一般在過濾應用場景中,反面樣例並不會對使用者展示。不過假如你的過濾器在服務過程中阻止了 75% 的反面樣例,那麼你可能需要從向使用者顯示的例項中提取額外的訓練資料並展開訓練。比如說,使用者將系統認可的郵件標記為垃圾郵件,那麼你可能就需要從中學習。

但這種方法同時也引入了取樣偏差。如果改為在服務期間將所有流量的1% 標記為“暫停”,並將所有這樣的樣例傳送給使用者,那你就能收集更純淨的資料。現在你的過濾器阻止了至少 74% 的反面樣例,這些樣例可以成為訓練資料。

需要注意的是,如果你的過濾器阻止了 95% 或更多的反面樣例,那這種方法可能就不太適用。不過即使如此,如果你想衡量服務的效能,可以選擇做出更細緻的取樣(例如 0.1% 或 0.001%),一萬個例子足以準確地估計效能。

35. 注意排序問題的固有偏差

當你徹底改變排序演算法時,一方面會引起完全不同的排序結果,另一方面也可能在很大程度上改變演算法未來可能要處理的資料。這會引入一些固有偏差,因此你必須事先充分認識到這一點。以下這些方法可以有效幫你優化訓練資料。

1) 對涵蓋更多查詢的特徵進行更高的正則化,而不是那些只覆蓋單一查詢的特徵。這樣,模型將偏好於那些基於一個或幾個特定查詢的特徵,而不是所有的特徵。這種方式可以有效防止那些最常見的查詢結果洩漏到不相關的查詢中。需要注意的是,這與一條更傳統的建議相左:更多地正則化一些具有單一值的特徵欄。

2) 只允許特徵具有正向權重,這樣一來就能保證任何好特徵都會比未知特徵合適。

3) 不要選擇那些只處理文件資料的特徵。例如,不管搜尋請求是什麼,即使一個給定的應用程式是當前的熱門下載,你也不會想在所有地方都顯示它。沒有文件特徵的話,這一點會很容易做到。

36. 避免具有位置特徵的反饋迴路

內容的位置會顯著影響使用者與它互動的可能性。很明顯,如果你把一個 App 置頂,那它一定會更頻繁地被點選。處理這類問題的一個有效方法是加入位置特徵,即關於頁面中的內容的位置特徵。假如你用正向特徵來訓練模型,那模型就會更偏向“1st-position”這類的特徵。因而模型對其他因素的權重就會相應地減小,例如對“1st-position = true”這種樣例。在服務的時候,你可以選擇不提供任何位置特徵的例項,或者為所有位置特徵設定相同的初始值,因為在決定以怎樣的順序顯示它們之前,你具有決策權。

需要注意的是,因為訓練和測試的不對稱性,所以最好在一些位置特徵和模型之間保持一定的分離性,這一點很重要。讓模型成為位置特徵函式和其他特徵函式的和,是理想的狀態。比如說,最好不要交叉任何文件特徵和位置特徵。

37. 測量訓練/服務偏差

許多情況都會引起偏差,但它們大多可以分為如下三類:

1) 訓練資料和測試資料的效能之間的差異。一般來說,這總是存在的,但並不會太嚴重。

2) 測試資料的效能與“第二天資料”(next-day data)之間的差異。同樣,這也會一直存在。你可以不同程度地正則化以最大限度地提高第二天的效能(next-day performance)。然而,如果在測試資料和第二天資料之間存在很大的效能下降,這有可能意味著某些特徵是時間敏感的,而且整個模型的效能也會跟著下降。

3) “第二天資料”和實時資料的效能之間的差異。如果你將模型應用於訓練資料的樣例,也應用於相同的服務樣例,則它們應該給出完全相同的結果(詳見規則5)。因此,這裡的差異可能是指工程誤差。

4. 0 機器學習第三階

4. 1 減慢的增速,精細優化和複雜模型

第二階段將要結束的時候,一定會有些訊號。首先,你每月的收益開始降低。你開始要在指標之間做犧牲:一些試驗中有的上升有的下降。從此情況變得更有趣。由於更難產生效益,機器學習不得不變得更復雜。

警告:這部分有許多開放式的實踐法則。我們親眼看著很多團隊走過第一階段和第二階段的幸福期——一旦到達第三階段,開發團隊就不得不找出他們自己的路。

38. 如果目標之間不搭,併成為問題,就不要在新特徵上浪費時間

當達到度量瓶頸,你的團隊開始關注 ML 系統目標範圍之外的問題。如同之前提到的,如果產品目標沒有包括在演算法目標之內,你就得修改其中一個。比如說,你也許優化的是點選數、點贊或者下載量,但釋出決策部分依賴於人類評估者。

39. 模型釋出決策是長期產品目標的代理

(雷鋒網注:谷歌工程師在這裡舉了個例子)Alice 有一個關於降低安裝預測的邏輯損失的想法。她加入一個特徵。邏輯損失下降。當她實時測試時,安裝量上升了。但在公司的釋出會議上,有人指出每日活躍使用者數降低了 5%。團隊決定不釋出該模型。Alice 很失望,但意識到釋出決策取決於多個標準,其中只有一部分能夠被 ML 直接優化。

事實是,現實世界並不是網路遊戲:沒有“攻擊值”和“血量”來衡量產品的健康。團隊需要利用收集的資料,來試圖預測將來系統的表現會怎樣。他們需要操心使用者黏性、每日活躍使用者、每月活躍使用者、收入和廣告主的收益。這些 A/B 測試中的指標,實際上只是長期目標的代理:讓使用者滿意、增加使用者、讓合作方滿意還有利潤;即便這時你還可以考慮高品質、有使用價值的產品的代理,以及五年後一個繁榮的企業的代理。

做出釋出決策變得容易的唯一一種情況是:所有指標都變好了(起碼沒有變差的)。如果團隊在複雜 ML 演算法和簡單啟發式演算法之間有的選擇;如果簡單的啟發式演算法在這些指標上做得更好;那麼應當選擇後者。另外,所有指標數值並沒有明確的排序。更具體的,考慮以下兩種情形:

如果現有系統是 A ,團隊不會想要轉移到 B。如果現有系統是 B,團隊也不會想要轉到 A。這看起來與理性決策相牴觸:但是,對指標變化的預期情形或許會發生,或許不會。因此任意一種改變都有相當大的風險。每一個指標覆蓋了一些團隊所關注的風險。但沒有指標能覆蓋團隊的首要關切——“我的產品在五年後會怎樣?”

另一方面,個體傾向於選擇能直接優化的目標。大多數 ML 工具喜歡這樣的環境。這樣的環境下,一個能快速建立新特徵的工程師能穩定輸出一系列產品釋出。有一種叫“多目標學習”(multi?objective learning)的機器學習開始解決這一問題。比如說,可以制定一個在每個指標上有下限的約束滿意度問題(constraint satisfaction problem),然後優化指標的一些線性組合。但即便那時,也不是所有指標都能輕易表達為 ML 目標:如果一個檔案被點選,或者 APP 被安裝,這是因為有內容被展示出來。但搞清楚使用者為什麼訪問你的頁面就更加難了。如何預測一個頁面在將來是否成功,是一項 AI?-complete 問題(雷鋒網注:意味著完成它的難度相當於解決 AI 問題),與計算機視覺和自然語言處理一樣難。

40. 保證整合模型(ensemble)的簡潔

接收原始特徵、直接對內容排序的統一模型,是最容易理解、最容易修補漏洞的模型。但是,一個整合模型(一個把其他模型得分組合在一起的“模型”)的效果會更好。為保持簡潔,每個模型應該要麼是一個只接收其他模型的輸入的整合模型,要麼是一個有多種特徵的基礎模型,但不能兩者皆是。如果你有單獨訓練、基於其它模型的模型,把它們組合到一起會導致不好的行為。

只用簡單模型來整合:那些只把基礎模型的輸入作為輸出、進行接收的模型。你或許想要為這些整合模型強加上屬性。比如,基礎模型生成得分的提高,不應該降低整合模型的分數。另外,如果連入模型在語義上可解釋(比如校準了的)會更好,這樣其下層模型不會與整合模型混淆。再者,強行讓下層分類器預測的概率升高,不會降低整合模型的預測概率。

41. 當效能達到瓶頸,相比精煉現存訊號,不如尋找新性質(qualitatively)的資訊源

你已經加入了一些關於使用者的人口統計資訊,還有檔案中的詞語。你經歷了模板探索,和正則化(regularization)調參。但連續幾個季度的釋出,你都沒有看到核心指標有超過 1% 的提升。現在怎麼辦?

你已經到了為不同尋常(雷鋒網(公眾號:雷鋒網)注:很不一樣)的特徵,建立基礎設施的時候了。比如使用者昨天、上週、去年檢索的文件,或是另一種屬性的資料。為你的公司使用維基資料(wikidata)實體或者一些內部的東西(比如谷歌的知識圖,Google’s knowledge graph)。你或許需要使用深度學習。開始調整你對投資回報的期望,並作出相應努力。如同所有工程專案,你需要平衡新增加的特徵與提高的複雜度。

42. 不要期望多樣性、個性化、相關性和受歡迎程度之間有緊密聯絡

一系列內容的多樣效能意味著許多東西,內容來源的多樣性最為普遍。個性化意味著每個使用者得到屬於他們自己的結果。相關性意味著一個特定檢索的結果,對應它比對應其他檢索更合適。因此,這三個屬性的定義都有別於“標準”。

但標準更難被打敗。

注意:如果你的系統在統計點選量、耗費時間、瀏覽數、點贊數、分享數等等,你事實上在衡量內容的受歡迎程度。有團隊試圖學習具備多樣性的個性化模型。為個性化,他們加入允許系統進行個性化的特徵(有的特徵代表使用者興趣),或者加入多樣性(表示該文件與其它返回文件有相同特徵的特徵,比如作者和內容),然後發現這些特徵比他們預想的得到更低的權重(有時是不同的訊號)。

這不意味著多樣性、個性化和相關性就不重要。如同上個法則所指出的,你可以通過後處理來提高多樣性或相關性。如果你看到長期目標的進步,那麼你可以宣佈在受歡迎程度之外,多樣性和相關性是有價值的。你可以繼續採用後處理,或者直接根據多樣性或相關性修改目標。

43. 不同產品中,你的朋友總是同一個,你的興趣不會如此

谷歌的 ML 團隊  常常把一個預測某產品聯絡緊密程度(the closeness of a connection in one product)的模型,應用在另一個產品上,然後發現效果很好。另一方面,我見過好幾個在產品線的個性化特徵上苦苦掙扎的團隊。是的,之前看起來它應該能奏效。但現在看來它不會了。有時候起作用的是——用某屬性的原始資料來預測另一個屬性的行為。即便知道某使用者存在另一個屬效能湊效的歷史,也要記住這一點。比如說,兩個產品上使用者活動的存在或許就自身說明了問題。

谷歌白皮書原文地址:http://martin.zinkevich.org/rules_of_ml/rules_of_ml.pdf

相關文章