每個人都可以輕松地将資料放入任何模型機器學習或深度學習架構中。但是遵循最佳實踐技巧可能有助于提升工作效率。以下是常見的一些方法。

本文内容
資料預處理
- 處理原始資料
- 使用張量
- 資料擴充
- 資料采樣
模型訓練
- 存儲中間狀态
- 虛拟周期
- 簡化原則
- 定位問題
調試
- 定位問題
- 使用評價模型
- 資料轉換
- 欠拟合
- 過拟合
生産
- 中繼資料關聯
- 切換到推理模型
- 縮放成本
- 無狀态模式
- 批處理
- 使用C++
資料預處理(Data Preparation)
處理原始資料(Process Your Own Data)
因為消費者可能不知道開展資料處理和特征工程,是以資料分析師需要在模型内進行資料預處理。
- 以文本分類問題為例,使用BERT進行分類。資料分析師不能要求客戶進行标記處理和特征整理。
- 以回歸問題為例,時間是特征之一。在初始模型中,資料分析師隻能使用星期幾(如星期四)作為特征。經過幾次疊代之後,星期幾不再是一個好的特征因素,資料分析師隻想使用日期(如31号)作為特征。而客戶可能隻提供了星期幾的資訊,而沒有具體日期的資訊,是以需要進行資料預處理。
- 以語音識别為例,消費者隻能向資料分析師發送音頻,而不能發送諸如Mel Cepstral Coefficient(MFCC)等經典特征資料。
是以,建議在代碼中嵌入資料預處理,而不是要求客戶機進行預處理。
使用張量(Use Tensor)
張量是一個N維數組,用于多元計算。它比使用Python字典或數組要快,深度學習架構(例如PyTorch或TensorFlow)的對象資料格式是tensor。
資料擴充(Data Augmentation)
缺少标記資料是從業者通常面臨的挑戰之一。遷移學習是克服這一問題的途徑之一,計算機視覺從業者可以考慮使用ResNet,自然語言處理從業者可以考慮BERT。另一方面,可以生成合成資料以增加标記資料。albumentations和imgaug可以生成圖像資料,而nlpaug可以生成文本資料。
如果你了解你的資料,你應該量身設計資料擴充方法。請記住,資料科學的黃金法則是garbage in garbage out。
資料采樣(Sampling Same Data)
大多數情況下,我們希望随機抽取資料,以保持樣本資料在訓練集、測試集和驗證集之間的機率分布是一緻的。同時,也希望保持這種“随機”行為,使得我們可以在不同的時刻獲得相同的訓練集、測試集和驗證集。
- 如果資料帶有日期屬性,則可以按日期拆分資料。
- 否則,可以更改随機種子,使其具有一緻的随機行為。
import torch
import numpy as np
import random
seed = 1234
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
複制
模型訓練(Model Training)
存儲中間狀态(Saving Intermediate Checkpoint)
隻是在訓練完成後儲存模型,通常具有以下幾個缺點:
- 由于模型的複雜性、計算資源和訓練資料的大小,整個模型訓練過程可能需要幾天或幾周的時間。如果沒有中間狀态被存儲,這将是非常危險的,因為機器可能會被意外關閉。
- 一般來說,較長訓練能夠獲得更好的結果(例如,損失更少)。然而,可能會發生過度拟合。在大多數情況下,最後一個模型狀态并不能提供最佳結果。我們大部分時間都需要使用中間狀态的模型來進行生産。
- 使用檢查-停止機制能夠節省資金。注意到一個模型在幾個周期内并沒有改進,我們可以早點停止它以節省時間和資源。
理想情況下,我們可以連續性存儲模型(例如,在每個epoch之後儲存模型),但它需要大量的存儲。事實上,我們建議隻保留最好的模型(或最好的三個模型)和最後一個模型。
虛拟周期(Virtual Epoch)
Epoch是模型訓練中一個非常常見的參數。如果初始化不正确,可能會影響模型性能。
例如,如果我們有100萬條記錄,我們設定了5個epoch,那麼總共有500萬條的訓練資料。三周後,我們又得到了50萬條記錄。如果我們使用相同的epoch進行模型訓練,總訓練資料将達到750萬。問題是:
- 難以确定模型性能的改進是由于特定資料的數量增加還是總體資料的數量增加。
- 新的50萬條資料使訓練時間延長1小時甚至幾天。它增加了機器故障的風險。
建議用虛拟epoch代替原始靜态epoch。虛拟epoch可以根據訓練資料的大小、期望epoch、批大小來計算得到。
通常的靜态epoch如下:
#original
num_data = 1000 * 1000
batch_size = 100
num_step = 14 * 1000 * 1000
num_checkpoint = 20
steps_per_epoch = num_step//num_checkpoint
#TensorFlow/ Keras
model.fit(x, epoch=num_checkpoint, steps_per_epoch=steps_per_epoch,
batch_size=batch_size
)
複制
而虛拟epoch如下:
num_data = 1000 * 1000
num_total_data = 14 * 1000 * 1000
batch_size = 100
num_checkpoint = 20
steps_per_epoch = num_total_data // (batch_size*num_checkpoint)
#TensorFlow/ Keras
model.fit(x, epoch=num_checkpoint, steps_per_epoch=steps_per_epoch,
batch_size=batch_size
)
複制
簡化原則(Simple is Beauty)
從業者通常打算使用最先進的模型來建構初始模型。事實上,我們建議建立一個足夠簡單的模型作為基線模型。原因是:
- 我們總是需要一個基線模型來證明所提出的模型是正确的。
- 基線模型不需要在性能方面非常好,但它必須是可解釋的。業務使用者總是想知道預測結果的原因。
- 易于實施是非常重要的。客戶不能等一年才能得到一個足夠好的模型。我們需要建立一套模型,以便從投資者那裡獲得動力,在初始模型的基礎上建立你的精彩模型。
以下是一些建議的不同領域的基線模型:
- 語音識别:可以使用經典特征,如mel frequency cepstral coefficient(MFCC)或 mel spectrogram features,而不是訓練模型來獲得向量表征(如增加嵌入層)。将這些特征傳遞給一個長短期記憶網絡(LSTM)或卷積神經網絡(CNN)和一個完全連接配接的層進行分類或預測。
- 計算機視覺:TODO。
- 自然語言處理:使用bag-of-words 或 classic word embeddings嵌入LSTM是一個很好的出發點,然後再轉向其它模型,如BERT或XLNet。
調試(Debugging)
簡化問題(Simplifying Problem)
有時,分類問題包括100萬個資料和1000個類别。當模型性能低于理想值時,很難調試模型。糟糕的性能可能是由模型複雜性、資料品質或bug造成的。是以,建議簡化問題,這樣我們就可以保證它是無缺陷的。我們可以利用過度拟合問題來實作這一目标。
一開始,不需要對1000個類别進行分類,可以先對10個類别進行抽樣,每個類别有100個資料,并訓練模型。通過使用相同的訓練資料集(或子集)作為評估資料集,能夠過度拟合模型并獲得良好的結果(例如,80甚至90+的精确度)。在這一基礎上進行模型開發能夠減少bug的出現。
使用評估模式(Using Eval Mode for Training)
如果評估模式的精度在前幾個epoch中沒有變化,通常可能是忘記在評估後重置為“訓練”模式。
在Pytorch中,需要在訓練和評估階段轉換訓練模式以及評估模式。如果啟用訓練模式,批标準化、dropout或其他參數将受到影響。有時,資料分析師可能會在評估模式後忘記啟用訓練模式。
model = MyModel() # Default mode is training mode
for e in range(epoch):
# mode.train() # forget to enable train mode
logits = model(x_train)
loss = loss_func(logits, y_train)
model.zero_grad()
loss.backward()
optimizer.step()
mode.eval() # enable eval mode
with torch.no_grad():
eval_preds = model(x_val)
複制
資料轉換(Data Shifting)
當訓練資料集與評估/測試資料集存在顯著差異時,需要進行資料轉換。在計算機視覺任務中,可能大部分訓練資料是白天的圖檔,而測試資料是夜間的圖檔。
如果發現訓練損失/準确度和測試損失/準确度之間存在很大差異,可以從兩個資料集中随機抽取一些樣本進行檢查。為了解決這個問題,可以考慮如下方法:
- 確定在訓練、測試和預測資料集之間保持相似的資料分布。
- 如果可能,添加更多的訓練資料。
- 通過利用相關庫添加合成資料。考慮使用nlpaug(用于自然語言處理和聲學任務)和imgaug(用于計算機視覺任務)。
欠拟合問題(Addressing Underfitting)
欠拟合是指訓練誤差大于期望誤差。換言之,模型無法達到預期的性能。造成大誤差的因素很多。要解決這個問題,可以從一個更簡單的模型或者方法開始,看看它是否可以解決。
- 執行錯誤分析。通過LIME、SHAP或Anchor來解釋你的模型,這樣你就可以感覺到問題所在。
- 初始模型可能過于簡單。增加模型的複雜性,例如增加長短期記憶(LSTM)層、卷積神經網絡(CNN)層或完全連接配接(FC)層。
- 通過減少正則化層,稍微過拟合模型。Dropout和降低權重則可以防止過拟合。然後可以嘗試移除這些正則化層,看看是否可以解決問題。
- 采用最先進的模型架構。考慮在自然語言處理(NLP)中使用轉換器(如BERT或XLNet)。
- 引入合成資料。生成更多資料有助于提高模型性能,而無需任何人工操作。理論上,生成的資料應該共享同一個标簽。它允許模型“看到”更多不同的資料,并最終提高魯棒性。可以利用nlpaug和imgaug來執行資料擴充。
- 配置設定更好的超參數和優化器。可以考慮執行超參數調整,而不是使用預設/正常學習速率、epoch、batch size。考慮使用波束搜尋、網格搜尋或随機搜尋來識别更好的超參數和優化器。這種方法相對簡單,隻需改變超參數,但可能需要較長的時間。
- 重新檢視資料并引入額外的特征。
過拟合問題(Addressing Overfitting)
除了欠拟合,你還可能面臨着過拟合的問題。過度拟合意味着你的模型太适合你的訓練集,而對其他資料沒有足夠的适用性。換句話說,訓練集準确性比驗證集準确性要好。考慮以下解決方法:
- 執行錯誤分析。通過LIME、SHAP或Anchor來解釋你的模型,這樣你就可能發現問題所在。
- 增加更多的訓練資料。
- 引入正則化層。Dropout(正則化層)和批處理标準化(normalization layer)通過删除一些輸入和平滑輸入來幫助減少過度拟合。
- 引入合成資料。生成更多資料有助于提高模型性能,而無需任何人工操作。
- 配置設定更好的超參數和優化器。
- 移除部分特征。
- 模型可能太過于複雜。可以減少模型複雜度。
生産(Production)
中繼資料聯系(Meta Data Association)
在模型推出後,需要檢查一些例外資料。一種方法是生成ID并将添加到資料庫中。然而,它伴随着幾個問題,也增加了故障排除的難度。以下是一些缺點:
- 影響系統的靈活性。從體系結構設計的角度來看,解耦是建構高柔性系統的途徑之一。如果我們生成ID并将帶有此ID的預測結果傳遞給客戶,那麼客戶需要在其資料庫中持久使用它。如果我們更改了格式或資料類型,需要通知所有使用者更新他們的資料庫。
- 我們可能需要根據使用者的關鍵資料收集更多的中繼資料。額外的關鍵資料增加了連接配接的複雜性和存儲消耗。
為了克服這個問題,預測結果應該直接與使用者的關鍵資料相關聯。
轉換為推理模型(Switch to Inference Mode)
使用Pytorch時,在将模型部署到生産環境中時,需要注意幾個設定。前面提到了Pytorch中的eval,它使這些層(如Dropout、BatchNorm)在推理模式下工作,例如在推理階段内不應用任何Dropout操作。它不僅能加快你的程序,而且能把所有的資訊輸入神經網絡。
mode.eval() # enable eval mode
with torch.no_grad():
eval_preds = model(x_val)
複制
計算成本(Scalling Cost)
當嘗試擴充API以處理更大的資料量時,有時可能會考慮使用GPU。的确,GPU虛拟機比CPU貴得多。然而,GPU帶來了一些優勢,例如計算時間更少,并且需要較少的VM來維持相同的服務級别。資料分析師應該試着評估一下GPU是否能節省一些錢。
無狀态化(Stateless)
試着使你的API無狀态化,這樣你的API服務可以很容易地調整。無狀态意味着不在API伺服器(記憶體或本地存儲)中儲存任何中間結果。隻需保持API伺服器的簡單性,并将結果傳回給用戶端,而無需在記憶體或本地存儲中存儲任何内容。
批處理(Batch Process)
預測一組資料通常比逐個預測更快。大多數現代機器學習或深度學習架構優化了預測性能(在速度方面)。你可能會注意到,切換到批處理模式預測對于效率有很大的改進。
使用C++
雖然Python是機器學習領域中的主流語言,但與其他程式設計語言(如C++)相比,Python可能太慢了。如果希望低延遲的計算推理時間,可以考慮使用TorchScript。一般的方案是,你仍然可以在Python中訓練你的模型,但是通過使用它生成C++相容的模型。
作者:Edward Ma
deephub翻譯組:Oliver Lee