Torcheck —— 測試你的 PyTorch 模型
引言
你是否有過這樣的經歷:長時間訓練 PyTorch 模型,結果發(fā)現在模型的 forward 方法中輸入了一行錯誤?你是否曾經遇到過這樣的情況:你從模型中獲得了一些合理的輸出,但是不確定這是否表明你構建的模型是正確的,或者這只是因為深度學習是如此強大,即使是錯誤的模型架構也會產生下降的結果。
就我個人而言,測試深度學習模型有時會讓我抓狂。最突出的痛點是:
它的黑盒特性使它很難測試。即使不是不可能,也需要很多專業(yè)知識來理解中間結果
長的訓練時間大大減少了迭代次數
沒有專門的工具。通常,您希望在一個小樣本數據集上測試模型,這需要重復編寫樣板代碼,以便進行設置優(yōu)化、計算損失和反向傳播
為了減少這種開銷,我之前做了一些研究。這里有一篇詳細文章:https://thenerdstation.medium.com/how-to-unit-test-machine-learning-code-57cf6fd81765,其核心思想是,我們永遠不能百分之百確定我們的模型是正確的,但至少它應該能夠通過一些合理性檢驗。換句話說,這些合理性檢驗是必要的,但可能還不夠。
為了節(jié)省您的時間,以下是他提出的所有合理性檢驗的摘要:
如果一個模型參數在訓練過程中沒有被故意凍結,那么它應該在訓練過程中不斷變化。這可以是 PyTorch 線性層的張量
模型參數在訓練過程中不應該改變,如果它被凍結。這可能是一個你不想更新的預訓練好的層
根據您的模型屬性,模型輸出的范圍應該服從某些條件。例如,如果它是一個分類模型,它的輸出不應該都在范圍(0,1)內。否則,很有可能您在計算損失之前錯誤地將 softmax 最大激活函數應用于輸出
(這實際上不是來自那篇文章,而是一個常見的問題)在大多數情況下,模型參數不應該包含 NaN 或 Inf(infinite number),這同樣適用于模型輸出
除了提出這些檢查,他還構建了一個 Python 包來實現這些檢查。這是一個很好的包,但仍然有未解決的痛點。這個包是幾年前創(chuàng)建的,現在已經不再維護了。
因此,受這種合理性檢驗思想的啟發(fā),目標是創(chuàng)建一個易于使用的 Python 包,創(chuàng)建 torcheck!其主要創(chuàng)新包括:
不再需要額外的測試代碼。只需添加幾行代碼指定訓練前的檢查,torcheck 將在訓練發(fā)生時執(zhí)行檢查,并在檢查失敗時提出信息性錯誤消息
可以在不同的級別檢查模型。你可以指定子模塊、線性層甚至權重張量的檢查,而不是檢驗整個模型!這樣就可以對復雜體系結構的檢查進行更多的自定義
接下來,我們會給你一個關于 torcheck 的快速教程。
假設我們已經編寫了一個 ConvNet 模型來對 MNIST 數據集進行分類:
# modelclass CNN(nn.Module):def __init__(self):super().__init__()self.conv1 = nn.Conv2d(1, 1, kernel_size=1, stride=1)self.conv2 = nn.Conv2d(1, 8, kernel_size=3, stride=1, padding=1)self.conv3 = nn.Conv2d(8, 16, kernel_size=3, stride=1, padding=1)self.relu = nn.ReLU()self.maxpool = nn.MaxPool2d(2, 2)self.fc1 = nn.Linear(16 * 7 * 7, 128)self.fc2 = nn.Linear(128, 10)def forward(self, x):output = self.relu(self.conv1(x))output = self.relu(self.conv2(x))output = self.maxpool(output)output = self.relu(self.conv3(output))output = self.maxpool(output)output = output.view(output.size()[0], -1)output = self.relu(self.fc1(output))output = self.fc2(output)return output# training routinemodel = CNN()optimizer = optim.Adam(model.parameters(), lr=0.001)for epoch in range(num_epochs):for x, y in dataloader:y_pred = model(x)loss = F.cross_entropy(y_pred, y)loss.backward()optimizer.step()optimizer.zero_grad()
在模型代碼中實際上有一個細微的錯誤。你們中的一些人可能已經注意到了:在第16行中,我們不小心把 x 放在了右邊,而應該是 output。
現在讓我們看看 torcheck 如何幫助我們檢驗這個隱藏的錯誤!
步驟0:安裝
在我們開始之前,首先用一行代碼安裝軟件包。
pip install torcheck步驟1: 添加 torcheck 代碼
接下來我們將添加代碼。Torcheck 代碼總是駐留在循環(huán)訓練之前,在模型和優(yōu)化器實例化之后,如下所示:
# model and optimizer instantiationmodel = CNN()optimizer = optim.Adam(model.parameters(), lr=0.001)############################ torcheck code goes here ############################# training routinefor epoch in range(num_epochs):for x, y in dataloader:y_pred = model(x)loss = F.cross_entropy(y_pred, y)loss.backward()optimizer.step()optimizer.zero_grad()
步驟1.1:注冊優(yōu)化器
首先,用 torcheck 注冊你的優(yōu)化器:
torcheck.register(optimizer)步驟1.2:增加合理性檢驗
接下來,添加要在四個類別中執(zhí)行的所有檢驗。
1. 參數改變/不改變
對于我們的例子,我們希望在訓練過程中更改所有的模型參數:
# check all the model parameters will change# module_name is optional, but it makes error messages more informative when checks failtorcheck.add_module_changing_check(model, module_name="my_model")
附注
為了演示 torcheck 的全部功能,讓我們假設稍后你已經凍結了卷積層,只想微調線性層。在這種情況下將會像這樣:
# check the first convolutional layer's parameters won't changetorcheck.add_module_unchanging_check(model.conv1, module_name="conv_layer_1")# check the second convolutional layer's parameters won't changetorcheck.add_module_unchanging_check(model.conv2, module_name="conv_layer_2")# check the third convolutional layer's parameters won't changetorcheck.add_module_unchanging_check(model.conv3, module_name="conv_layer_3")# check the first linear layer's parameters will changetorcheck.add_module_changing_check(model.fc1, module_name="linear_layer_1")# check the second linear layer's parameters will changetorcheck.add_module_changing_check(model.fc2, module_name="linear_layer_2")
2. 輸出范圍檢查
因為我們的模型是一個分類模型,所以我們想要添加前面提到的檢驗:模型輸出不應該都在范圍(0,1)內。
# check model outputs are not all within (0, 1)# aka softmax hasn't been applied before loss calculationtorcheck.add_module_output_range_check(model,output_range=(0, 1),negate_range=True,)
negate_range = True 參數帶有“ not all”的含義。如果您只是想檢查模型輸出都在某個范圍內,只需刪除該參數。
盡管 torcheck 不適用于我們的示例,但是它還允許你檢查子模塊的中間輸出。
3. NaN 檢查
我們當然希望確保模型參數在訓練期間不會變成 NaN,并且模型輸出不包含 NaN。添加 NaN 檢查很簡單:
# check whether model parameters become NaN or outputs contain NaNtorcheck.add_module_nan_check(model)
4. Inf 檢查
類似地,添加 Inf 檢查:
# check whether model parameters become infinite or outputs contain infinite valuetorcheck.add_module_inf_check(model)
在添加了所有感興趣的檢驗之后,最終的訓練代碼如下:
model = CNN()optimizer = optim.Adam(model.parameters(), lr=0.001)torcheck.register(optimizer)torcheck.add_module_changing_check(model, module_name="my_model")torcheck.add_module_output_range_check(model, output_range=(0, 1), negate_range=True)torcheck.add_module_nan_check(model)torcheck.add_module_inf_check(model)for epoch in range(num_epochs):for x, y in dataloader:y_pred = model(x)loss = F.cross_entropy(y_pred, y)loss.backward()optimizer.step()optimizer.zero_grad()
步驟2:訓練和修復
現在讓我們像往常一樣進行訓練,看看會發(fā)生什么:
$ python run.pyTraceback (most recent call last):(stack trace information here)RuntimeError: The following errors are detected while training:Module my_model's conv1.weight should change.Module my_model's conv1.bias should change.
砰!我們立即得到一個錯誤消息,說我們的模型的 conv1.weight 和 conv1.bias 不會改變。一定是 model.conv1出了什么問題。
正如預期的那樣,我們轉向模型代碼,注意錯誤,修復它,并重新運行訓練。
(可選)步驟3:關閉檢驗
耶! 我們的模型通過了所有的檢驗。最后,我們可以對其進行關閉:
torcheck.disable()當你想要在驗證集上運行模型,或者只想從你的模型訓練中消除檢查耗時,這是非常有用的。
如果你還想繼續(xù)使用,只需要:
torcheck.enable()個人微信(如果沒有備注不拉群!) 請注明:地區(qū)+學校/企業(yè)+研究方向+昵稱
下載1:何愷明頂會分享
在「AI算法與圖像處理」公眾號后臺回復:何愷明,即可下載。總共有6份PDF,涉及 ResNet、Mask RCNN等經典工作的總結分析
下載2:終身受益的編程指南:Google編程風格指南
在「AI算法與圖像處理」公眾號后臺回復:c++,即可下載。歷經十年考驗,最權威的編程規(guī)范!
下載3 CVPR2021 在「AI算法與圖像處理」公眾號后臺回復:CVPR,即可下載1467篇CVPR 2020論文 和 CVPR 2021 最新論文
點亮
,告訴大家你也在看
