2017-06-16 117 views
7

我有三個簡單的問題。PyTorch中的自定義丟失函數

  1. 如果我的自定義丟失函數不可區分會發生什麼?將pytorch通過錯誤或做別的?
  2. 如果我在自定義函數中聲明瞭一個將代表模型最終損失的損失變量,那麼我應該爲該變量放置requires_grad = True嗎?或者沒關係?如果沒關係,那爲什麼?
  3. 我已經看到人們有時會編寫一個單獨的圖層並計算forward函數中的損失。編寫一個函數或一個圖層最好採用哪種方法?爲什麼?

我需要對這些問題有一個清晰而好的解釋來解決我的困惑。請幫忙。

回答

7

讓我走了。

  1. 這取決於你的意思是「不可微分」。第一個有意義的定義是PyTorch不知道如何計算漸變。如果您嘗試計算漸變,則會產生錯誤。這兩種可能的情況是:

    a)您正在使用自定義的PyTorch操作,其漸變尚未實現,例如, torch.svd()。在這種情況下,你會得到一個TypeError

    import torch 
    from torch.autograd import Function 
    from torch.autograd import Variable 
    
    A = Variable(torch.randn(10,10), requires_grad=True) 
    u, s, v = torch.svd(A) # raises TypeError 
    

    b)你已經實現了你自己的操作,但沒有規定backward()。在這種情況下,你會得到一個NotImplementedError

    class my_function(Function): # forgot to define backward() 
    
        def forward(self, x): 
         return 2 * x 
    
    A = Variable(torch.randn(10,10)) 
    B = my_function()(A) 
    C = torch.sum(B) 
    C.backward() # will raise NotImplementedError 
    

    是有道理的是「數學上不可微分的」第二個定義。顯然,數學上不可區分的操作應該沒有執行backward()方法或者是合理的子梯度。例如,考慮torch.abs()backward()方法在0返回梯度0:

    A = Variable(torch.Tensor([-1,0,1]),requires_grad=True) 
    B = torch.abs(A) 
    B.backward(torch.Tensor([1,1,1])) 
    A.grad.data 
    

    對於這些情況,你應該參考PyTorch文檔直接,直接挖掘出各自的操作方法backward()

  2. 沒關係。使用requires_grad是爲了避免不必要的子圖梯度計算。如果需要漸變的操作有單個輸入,則其輸出也需要漸變。相反,只有當所有輸入不需要漸變時,輸出也不需要它。反向計算從不在子圖中執行,其中所有變量不需要漸變。

    因爲,最有可能的一些Variables(例如nn.Module()的子類的參數),您的loss變量也將自動需要梯度。但是,您應該注意到requires_grad的工作原理(請參閱上面的內容),無論如何,您只能更改圖表的葉變量requires_grad

  3. 所有自定義PyTorch丟失函數都是_Loss的子類,它是nn.Module的子類。See here.如果您想堅持這一慣例,則在定義自定義丟失函數時應劃分_Loss。除了一致性之外,如果您尚未將目標變量標記爲volatilerequires_grad = False,則其中一個優點是您的子類將提高AssertionError。另一個優點是,你可以將你的損失函數嵌套在nn.Sequential()中,因爲它的一個nn.Module我會推薦這種方法出於這些原因。

+0

不客氣。不幸的是無法打開鏈接。 – mexmex

+0

我之所以刪除這個問題,是因爲我解決了這個問題。但你能幫我在這個問題 - https://stackoverflow.com/questions/44580450/cuda-vs-dataparallel-why-the-difference? –

相關問題