本文主要以下探究這一點:梯度反向傳播過程中,測試強行修改后的預測結果是否還會傳遞loss?
clamp應用場景:在深度學習計算損失函數的過程中,會有這樣一個問題,如果Label是1.0,而預測結果是0.0,則BCE損失中理論上計算出的結果是無窮大的(當然pytorch并不會報錯,而是將損失上限設在了100.0),在實際開發過程中,我們一般會使用torch.clamp等函數將預測tensor不符合取值范圍的值全部置為最小或最大值。
那對于這些被替換后的元素,他們會在反向傳播過程中對網絡產生梯度嗎?第一想法是沒有,因為這些替換后的新值的來源是一個賦值操作,而非通過網絡計算出來的,但為了更好的理解,我們來做一個測試。
from torch.nn import functional as F
import torch.nn as nn
import torch
#初始化一個最簡單的網絡
fc = nn.Linear(in_features=1, out_features=1, bias=True)
fc.weight.data = torch.tensor([[0.01]])
fc.bias.data = torch.tensor([[0.01]])
input_t = torch.tensor([[1.0]], dtype=torch.float32)
pred = fc(input_t)
label = torch.tensor([[1.0]])
這里網絡的預測結果為0.02,將其強行截斷到0.1,損失的計算仍然是正常的,但是反向傳播后,網絡的訓練參數是沒有梯度的,即可以認為這個預測的樣本對網絡是沒有更新作用的,是一個無意義的預測樣本。
pred = torch.clamp(pred, min=0.1, max=0.9)
loss = F.binary_cross_entropy(pred, label)
print(loss) # tensor(2.3026, grad_fn=<BinaryCrossEntropyBackward>)
loss.backward()
print(fc.weight.grad, fc.bias.grad) #tensor([[0.]]) tensor([[0.]])
?正常的預測結果產生梯度,符合預期。
loss = F.binary_cross_entropy(pred, label)
print(loss) #tensor(3.9120, grad_fn=<BinaryCrossEntropyBackward>)
loss.backward()
print(fc.weight.grad, fc.bias.grad) #tensor([[-50.]]) tensor([[-50.]])
更一般的,假設有n個預測結果,其中有k個值由于torch.clamp等操作被強行修改了值,還剩n - k個預測結果是真實來源于網絡,則在梯度反向傳播的時候只有這n - k個樣本能夠成功回傳梯度給網絡,即便計算的loss是這k個樣本產生的。