天天看點

python中maker_在python中使用SageMaker Debugger進行機器學習模型的開發調試

python中maker_在python中使用SageMaker Debugger進行機器學習模型的開發調試

如果你從事軟體開發,你就會知道 Bug 是生活的一部分。當你開始你的項目時,Bug 就可能存在,當你把你的産品傳遞給客戶時,Bug 也可能存在。在過去的幾十年中,軟體開發社群已經開發了許多的技術工具、IDE、代碼庫等來幫助開發者盡早地發現 Bug,以避免在産品傳遞的時候仍舊存在 Bug。

不幸的是,機器學習開發人員和資料科學家并沒有享受到傳統軟體所提供的強大的調試工具。這就是為什麼我們中的許多人在訓練腳本中經常性使用 “print” 語句。這一問題在分布式訓練和在叢集上開展大規模實驗時尤其突出,雖然你可以儲存工作日志,但是通過這些工作日志來定位 Bug 簡直無異于大海撈針。

在這篇部落格文章中,将讨論調試機器學習代碼與傳統軟體的不同之處,以及為什麼調試機器學習代碼要困難得多。然後,将展示如何使用更好的機制來捕獲調試資訊、在訓練期間實時監控常見問題、發現問題後及時幹預以防止發生進一步的錯誤及浪費計算機資源。

具體地,主要通過 Amazon SageMaker Debugger(一個用于機器學習模型調試的開源庫)實作上述目的。

機器學習調試與傳統軟體開發調試有何不同?

如果機器學習以軟體的形式呈現,那麼将能夠找到許多調試工具來解決 Bug 的問題,比如:

使用內建開發環境(IDE),設定斷點并檢查中間變量;使用開發所使用的程式設計語言進行異常處理和類型檢查;使用靜态代碼分析工具查找錯誤并檢查是否符合标準;使用諸如 gdb 的調試庫;使用日志和“print”語句。但是現階段的機器學習調試仍然是一項十分困難的工作,主要原因如下:

機器學習不僅僅是簡單的代碼首先,讓我們考察一個典型的資料科學問題——面對一個資料集和一個對應的問題描述,需要建立一個基于資料的模型來實作預測,并且評價該模型的準确性,然後在模型達到要求後,進行部署、內建、銷售等。

相較于傳統軟體,機器學習代碼涉及到更多的非固定的組分。如:資料集、模型結構、微調過後的模型權重、優化算法及其參數、訓練後的梯度等。

在某種意義上,機器學習代碼在訓練階段是“動态的”。因為模型本身是随着模型訓練而改變或發展的。在訓練過程中,模型中的數百萬個參數或權重每一步都在變化。一旦訓練完成,它就會停止改變,此時,在訓練過程中沒有發現的錯誤現在已經成為模型的一部分。 而傳統軟體代碼中,有嚴格的邏輯和規則,不會在每次運作時改變,即使有條件分支,但代碼仍然是“靜态的”。

調試這個動态的、不斷演化的代碼需要不同于傳統軟體開發調試的工具。需要的是通過分析數百萬個不斷變化的變量來監測訓練進度,并在滿足某些條件時采取動作。主要通過監視模型參數、優化參數和名額,及時發現諸如梯度消失、activation saturation 等問題。

而調試工具的缺乏,導緻大部分機器學習開發人員通過 “print” 語句分析模型訓練的過程。

難以在機器學習訓練過程中實施監測和幹預

python中maker_在python中使用SageMaker Debugger進行機器學習模型的開發調試

考慮到效率和經濟因素,很多機器學習訓練代碼運作在叢集上,或者至少在各大雲平台中,大部分都不是在個人計算機上運作。而在叢集上訓練模型時設定斷點幾乎是不可能的。

當你的程式設計範式改變時,你的調試工具和方法也應該随之改變。在叢集上進行分布式訓練時,監視進度的主要方法是插入代碼以生成日志以供分析。但這是不夠的,相反,需要的是一種更簡單的方法來實時監控進度,并在滿足特定條件時發出提醒或采取一些行動。而這就給我們帶來了下一個挑戰。

調試機器學習代碼可能需要大量重寫或改變架構機器學習代碼的核心依賴于一系列高度優化的線性代數子程式,這些語言通常用C語言、C++語言和CUDA語言編寫。更高層次的架構,如TensorFlow、PyTorch、MXNet和其他架構,對底層程式代碼進行封裝,并提供一種設計和訓練模型的簡便方法。當減少代碼複雜度時,一定程度上提升了調試的困難度。

機器學習架構的實作方式有以下兩種:(1)聲明式方法,将模型體系結構定義為一個計算圖,然後進行編譯、優化和執行(例如TensorFlow)(2)指令式方法,将模型體系結構定義為一個計算圖,然後按定義執行(例如Pythorch,TensorFlow eager mode)。在聲明式方法中,無法通路優化的計算圖,是以調試可能會更困難。在指令式方法中,調試更容易,但需要在較低的級别上測試代碼以擷取調試資料,在某些情況下,還需要權衡性能。

為了更好地進行調試,必須編寫額外的代碼加入到訓練腳本中,或者重寫代碼以支援不同的架構。或者更糟的是,在多個架構上維護相同的模型。而這些操作可能會引入更多的 bug。

Bug 會讓開發者在硬體、時間上付出更多的成本大多數機器學習 Bug 可以在訓練過程的早期發現,如一些常見的問題:初始化不好、梯度消失、activation saturation 等。而其他問題則是随着時間的推移而顯現的,如過拟合等。而無論是訓練早期還是訓練後期發現的問題,都将導緻資源的浪費。

python中maker_在python中使用SageMaker Debugger進行機器學習模型的開發調試

在上圖中可以看到,當模型開始超過20k步時,應該停止。當訓練持續到40k步左右,計算成本是原來的兩倍。這樣的問題很常見,因為普遍存在着指定了固定數量的 epochs 來執行訓練,然後出去吃午飯的情況。

機器學習調試涉及到哪些操作?

一個好的機器學習調試工具或方法應該具備的主要功能如下:

捕獲(capture)能夠捕獲模型和優化器的有關參數和名額資料。開發人員能夠指定資料采集頻率,并對調試資料進行後處理操作。

反應(react)能夠監視捕獲資料中的變更并作出反應。開發人員能夠指定模型在滿足條件(如:梯度消失、過拟合)時停止訓練。

分析(analyze)能夠允許使用者在模型訓練期間實時分析捕獲的資料。開發人員能夠對捕獲的資料進行脫機分析。

使用 Amazon SageMaker Debugger 進行機器學習模型的開發調試

Amazon SageMaker Debugger 使得開發人員能夠監測模型訓練情況,實作針對訓練階段的模型參數的監測、記錄、分析。 可以通過以下兩種途徑使用 Amazon SageMaker Debugger:

Amazon SageMaker managed training 方式當使用 Amazon Sagemaker 訓練模型時,将自動啟用 Amazon SageMaker Debugger。并且不需要對訓練腳本進行任何更改,隻需指定要監視的問題,它就會自動運作監視,可以捕獲梯度消失、過拟合等問題。還可以在訓練期間記錄張量,并将其儲存在 Amazon S3中,以便進行實時或離線分析。

smdebug 開源庫方式可以在 TensorFlow、Keras、PyTorch、MXNet或XGBoost 等編寫的訓練代碼中加入 smdebug 開源庫相關代碼,以進行調試。

具體地,Amazon SageMaker debugger 的 capture、react、analyze 使用方法如下:

通過 debugger hooks 獲得調試資料

機器學習訓練中的大部分代碼都是為了實作對于模型參數的優化。通過優化算法,對比預測值和真實值、計算梯度、更新權重。通常涉及到百萬數量級的權重參數和偏差參數。

python中maker_在python中使用SageMaker Debugger進行機器學習模型的開發調試

為了在訓練階段捕獲重要資訊,Amazon SageMaker Debugger 自動将 Hooks 添加到 TensorFlow、Keras、PyTorch、MXNet或XGBoost代碼中。當指定SageMaker Debugger Hook 時,可以針對性地儲存重要資料和資訊。Amazon SageMaker Debugger 提供一個預定義的張量清單,可以通過這個清單儲存權重、偏差、梯度、損失、優化器變量等參數。也可以通過聲明 regex 字元串指定需要捕獲的模型特定層中的特定張量。

在 Amazon SageMaker 使用 Hooks

如果使用Amazon SageMaker 進行模型訓練,則會自動配置Amazon SageMaker Debugger,無需更改訓練代碼主體。隻需要聲明如下内容:

from sagemaker.debugger import Rule, DebuggerHookConfigdebugger_hook_config = DebuggerHookConfig(hook_parameters={"save_interval": '100'}, collection_configs=[ CollectionConfig("losses"), CollectionConfig("weights"), CollectionConfig("gradients"), CollectionConfig("biases")] )

通過上述代碼,Hook 将間隔100步自動存儲 losses、weights、gradients、biases等參數。當然,也可以指定采樣起止步數。

當調用SageMaker TensorFlow estimator 時,通過 Amazon SageMaker Python SDK将 Hook 傳遞給 debuggerHookconfig參數。代碼如下:

tf_estimator = TensorFlow(entry_point = 'tf-training-script.py', ... ... debugger_hook_config = debugger_hook_config)

本地環境下通過 smdebug 開源庫使用 Hooks

當在個人電腦中進行模型訓練或者 Amazon SageMaker 未能夠自動配置 Hooks 時,可以使用smdebug庫手動配置。 以 Keras 和 PyTorch 為例:

在 Keras 代碼中使用 Hook

import smdebug.tensorflow as smdjob_name = 'tf-debug-job'hook = smd.KerasHook(out_dir=f'./smd_outputs/{job_name}',tensorboard_dir=f'./tb_logs/{job_name}', save_config=smd.SaveConfig(save_interval=1), include_collections=['gradients', 'biases'])opt = tf.keras.optimizers.SGD(learning_rate=0.01, momentum=0.9, name='SGD')opt = hook.wrap_optimizer(opt)

通過上述代碼,首先導入smdebug包,然後執行個體化 KerasHook。通過 KerasHook 儲存梯度和偏差張量至 out_dir,儲存 TensorBoard 日志到tensorboard_dir。

在 PyTorch 代碼中使用 Hook

import smdebug.pytorch as smdnet = get_network()criterion = nn.CrossEntropyLoss()optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)job_name = 'pytorch-debug-job'hook = smd.Hook(out_dir=f'./smd_outputs/{job_name}',save_config=smd.SaveConfig(save_interval=10), include_collections=['gradients', 'biases'])hook.register_module(net)hook.register_loss(criterion)

通過上述代碼,首先導入smdebug包,然後執行個體化 Hook,最後将 hook 添加到神經網絡中。除了對優化函數使用 hook,也可以對損失函數使用 hook。

此外,可以通過 hook.record_tensor_value來記錄指定的張量資料。

for epoch in range(10):running_loss = 0.0 for i, data in enumerate(trainloader, 0): inputs, labels = data[0].to(device), data[1].to(device) optimizer.zero_grad() outputs = net(inputs) loss = criterion(outputs, labels) # Use hook to record tensors hook.record_tensor_value(tensor_name="loss", tensor_value=loss) loss.backward() optimizer.step()

使用 debugger rules 對調試資料變更做出反應

如果隻是單純的對資料進行采樣記錄,并不能很好的實作調試工作。真正意義上實作調試,要求在訓練階段能夠實時的做出反應。是以引入 debugger rules,對代碼運作過程中的某一條件進行監測,當條件發生改變時做出停止訓練、發生通知等操作。

Amazon SageMaker Debugger 内置了部分常用的條件判斷函數:死亡節點(dead relu)、張量爆炸(exploding tensor)、權重初始化不良(poor weight initialization)、激活函數飽和(saturated activation)、梯度消失(vanishing gradient)、分類不平衡(calss imbalance)、過拟合等。如果想要自定義條件,可以通過smdebug庫函數進一步編寫。

如果使用Amazon SageMaker 進行模型訓練,則會自動運作 debugger rules。當然也可以使用smdebug庫在本地環境運作相關函數。

在 Amazon SageMaker 中使用 debugger rules

python中maker_在python中使用SageMaker Debugger進行機器學習模型的開發調試

具體代碼如下:

debug_rules = [Rule.sagemaker(rule_configs.overtraining()), Rule.sagemaker(rule_configs.overfit()), Rule.custom(name='MyCustomRule', image_uri='840043622174.dkr.ecr.us-east-2.amazonaws.com/sagemaker-debugger-rule-evaluator:latest', instance_type='ml.t3.medium', source='rules/my_custom_rule.py', rule_to_invoke='CustomGradientRule', volume_size_in_gb=30, rule_parameters={"threshold": "20.0"}) ]

通過上述代碼,添加了兩個内置條件(overtraining,overfitting)和一個自定義條件(customGradientRule)。

編寫自定義條件,需要聲明需要調用的 SageMaker 資源(本例中為 t3.medium)。

在SageMaker framework estimator 函數(例如下面的TensorFlow estimator)中,可以将規則配置作為其中的 rules 參數。 這将訓示Amazon SageMaker不僅啟動一個訓練程序,還啟動 rules 程序。

python中maker_在python中使用SageMaker Debugger進行機器學習模型的開發調試

在本地環境中使用 debugger rules

下面的代碼将示範如何定義一個名為CustomGradientRule的規則。通過該規則檢查梯度的絕對平均值是否大于某個門檻值,如果沒有指定門檻值,則門檻值為10。

from smdebug.rules import Ruleclass CustomGradientRule(Rule):def __init__(self, base_trial, threshold=10.0): super().__init__(base_trial) self.threshold = float(threshold) def invoke_at_step(self, step): for tname in self.base_trial.tensor_names(collection="gradients"): t = self.base_trial.tensor(tname) abs_mean = t.reduction_value(step, "mean", abs=True) if abs_mean > self.threshold: return True return False

為了調用該規則,需要建立一個rule_object:

from smdebug.rules import invoke_rulefrom smdebug.trials import create_trialtrial = create_trial(path=’./smd_outputs/)rule_obj = CustomVanishingGradientRule(trial, threshold=0.0001)invoke_rule(rule_obj, start_step=0, end_step=None)

使用 Amazon SageMaker Debugger 分析調試資料

使用hook可以在訓練期間導出資料,如權重、梯度和其他資料;而 rule 允許在訓練階段監測模型條件是否改變,以便采取行動。在某些情況下,開發者隻想分析原始資料并将其繪制出來,以找到尚不了解的問題。 具體的可視化方法如下:

通過 Amazon SageMaker Studio 進行可視化Amazon SageMaker Studio 建立在 Jupyter Notebook 之上,它內建了跟蹤實驗、在訓練期間可視化性能曲線以及在實驗中比較不同試驗結果的功能。還可以通過選擇 debugger hook 儲存的資料值來調出自定義圖表。

python中maker_在python中使用SageMaker Debugger進行機器學習模型的開發調試

本地環境下使用 smdebug 庫進行可視化以如下代碼為例:

hook = smd.Hook(out_dir=f'./smd_outputs/{job_name}',save_config=smd.SaveConfig(save_interval=10), include_collections=['gradients', 'biases'])

首先通過 Hook 存儲 梯度和偏差。

import smdebug.pytorch as smdtrial = smd.create_trial(path=PATH_TO_S3_OR_LOCAL_DIR')

然後建立一個 trial,以便實時分析。

trial.tensor_names()

通過 tensor_names() 查詢儲存的張量:

[2020-03-30 06:02:17.108 ip-172-31-28-67:31414 INFO local_trial.py:35] Loading trial pytorch-exp03-30-05-53-52 at path ./smd_outputs/pytorch-exp03-30-05-53-52[8]:['CrossEntropyLoss_output_0','Net_conv1.bias', 'Net_conv2.bias', 'Net_fc1.bias', 'Net_fc2.bias', 'Net_fc3.bias', 'gradient/Net_conv1.bias', 'gradient/Net_conv1.weight', 'gradient/Net_conv2.bias', 'gradient/Net_conv2.weight', 'gradient/Net_fc1.bias', 'gradient/Net_fc1.weight', 'gradient/Net_fc2.bias', 'gradient/Net_fc2.weight', 'gradient/Net_fc3.bias', 'gradient/Net_fc3.weight', 'loss_output_0']

通過 trail.tensor().values() 查詢所有資料:

python中maker_在python中使用SageMaker Debugger進行機器學習模型的開發調試

注意到梯度每10步儲存一次,這是我們在 hook 中預先指定的。通過在循環中運作上述指令來查詢最近的值,可以在訓練期間檢索張量。這樣,可以繪制性能曲線,或在訓練過程中可視化權重的變化。

python中maker_在python中使用SageMaker Debugger進行機器學習模型的開發調試

Amazon SageMaker Debugger 工作流程

python中maker_在python中使用SageMaker Debugger進行機器學習模型的開發調試

使用SageMaker Python SDK和各架構(TensorFlow、PyTorch等)開始Amazon SageMaker 上的深度學習訓練任務。Amazon SageMaker在指定數量的CPU或GPU上啟動訓練程序。同時SageMaker啟動 rule 程序以監控訓練過程。使用debug Hook config,Amazon SageMaker把權重、偏差和其他張量儲存到指定的S3位置。在 Hook 采集資料的基礎上, rule 程序執行指定的條件監控。當指定的條件發生狀态變化,采取停止訓練、發生通知等行動。可以使用smdebug庫來建立 trial 對象。trail對象可用于查詢張量,以便于執行實時或脫機分析及可視化。總結

調試是一項具有挑戰性的工作,本文中讨論了機器學習開發調試和普通軟體開發調試的差異,并且給出了通過 Amazon SageMaker Debugger 進行調試的辦法。

而使用Amazon SageMaker Debugger的三種途徑如下:

通過在 Amazon SageMaker 全托管服務平台使用,将免去手動配置等操作。通過 smdebug開源庫在個人電腦等本地環境使用,需要進行一定的手動配置。可以通過 Amazon SageMaker 進行模型訓練,通過本地環境執行 rules 對調試資料進行可視化分析。