pytorch 常見錯誤
RuntimeError: a leaf Variable that requires grad is being used in an in-place operation.
如下程式會抱上述錯誤
x=torch.randn(3,requires_grad=True)
x += 1 # 原位操作 報錯:RuntimeError: a leaf Variable that requires grad is being used in an in-place operation.
報錯:你在一個變數上進行操作,但是該變數是不可以修改的。這個變數是tensor。x是梯度是開啟的,此時x不應該進行原位操作,但是x進行了原位操作。
原因:pytorch的自動求導機制的本質是使用鏈式求導法則,將求導的過程分解成一個一個的基本操作運算元。其具體是透過自動構建計算圖,來求解導數。
如下函式 \(y=f(x)\) , pytorch 的計算過程是這樣
x = x0 # x取值x0
x.requires_grad=True # 目標函式是否關於x求梯度
y=f(x) # 前向過程
y.backward() # 反向求導
x.grad # 輸出x在x0處的導數
py計算的是目標函式關於自變數在某一個確定點的導數值。此時已經構建了一張圖,你將x進行了改變,此時計算圖要重新構建。pytorch不允許這種操作。
假設 \(y=x*x\), 現在對x進行了操作x=x+1
, 那麼再對y求x的導數的時候,y關於x的對映關係是哪個?是\(y=x*x\), 還是 \(y = (x+1) * (x+1)\)。pytorch決定不了,總要有一個選擇。
解決方案:
-
使用tensor的data屬性:tensor有一個基本屬性data,它是tensor上儲存的變數的數值,你可以修改這個數值,但是不修改其他屬性。選擇的是\(y=(x+1)*(x+1)的路子\)
x=torch.tensor([1.0,1.0],requires_grad=True) x.data += 1 y=torch.dot(x,x)*0.5 y.backward() x.grad #tensor([2., 2.], requires_grad=True) x.grad == x #tensor([True, True, True])
-
使用
with torch.no_grad()
此時梯度屬性被禁用了x=torch.tensor([1.0,1.0],requires_grad=True) with torch.no_grad(): # 在上下文管理器中進行 x += 1 y=torch.dot(x,x) * 0.5 y.backward() x.grad #tensor([2., 2.], requires_grad=True) x.grad == x #tensor([True, True, True])
2、tensor.grad.zero_() 梯度清零的使用場景
- 構建tensor x。其梯度打來
- 函式
y=f(x)
對y關於\(x\) 在某一點求梯度x.grad
- 使用\(x\) 構建函式\(g=g(x)\), 如果x不進行梯度清零,那麼對g關於x求導,其結果為
x.grad = g關於x的導數+y關於x的導數
在深度學習裡面,神經網路的引數是在動態變化中,所以其對應的對映關係也是在動態變化中。所以一次反向求導之後,進行第二次反向求導,那麼需要將導數清零。
x=torch.tensor([1.0,1.0],requires_grad=True) y=torch.dot(x,x) * 0.5 g=2*x y.backward() g.sum().backward() x.grad # tensor([3., 3.]) = tensor([1., 1.]) + 2
3、pytorch當loss是nan的時候,其是無法輸出的,具體案例如下:
x=torch.tensor([0,1,1,1,1],requires_grad=True,dtype=torch.float) y=x/x y.sum().backward() x.grad # 產生了除0操作,y為NAN,此時x為NAN
4.python的生成器機制yield
透過yield關鍵字定義生成器。使得函式能夠記住上一次執行的狀態,並在下一次呼叫的時候,從該狀態繼續執行。生成器有如下特性:
- 惰性求值:等到使用的時候再計算
- 節省記憶體:由於生成器在任何時刻只處理一個值,因此它不需要在記憶體中儲存整個資料集,這在處理大量資料時尤其有用。
- 狀態保持:生成器函式可以記住其上一次執行的狀態,這意味著它可以從中斷的地方繼續執行。
定義生成器:
-
使用yield關鍵字
def f(n): for i in range(n): yield i # 使用yield定義生成器
-
生成器表示式
y = (x * x for x in range(5))
如何使用生成器?
-
使用for迴圈: 更加頻繁,pytorch dataloader函式
for i in f(3): x = i print(i)
-
使用next函式
next(y)
使用場景
- 大檔案處理,節省記憶體