前言:
def to_var(self, x, volatile=False): #torch.Size([1024, 118]) if torch.cuda.is_available(): x = x.cuda() return Variable(x, volatile=volatile)
class torch.autograd.Variable:為什么要引入Variable?首先回答為什么引入Tensor。僅僅使用numpy也可以實現前向反向傳播,但numpy不支持GPU運算。而Pytorch的Tensor提供多種操作運算,此外Tensor支持GPU。問來了,兩三個網絡可以推公式寫反向傳播,當網絡很復雜的時需要自動化。autograd可以幫助我們,當利用autograd時,前向傳播會定義一個計算圖,圖中的節點就是Tensor。圖中的變就是函數。當我們將Tensor塞(Variable(tensor,....))到Variable時,Variable就變成了節點。若x為一個Variable,那么x.data即為Tensor,x.grad也為一個Variable。那么x.grad.data就為梯度的值。總結:Pytorch Variable與Pytorch Tensor有着相同的API,Tensor上的所有操作幾乎都可用在Variable上。兩者不同之處在於利用Variable定義一個計算圖,可以實現自動求導。
重要屬性如下:
requires_grad:
指定要不要更新這個參數(通過梯度(迭代)來更新),對於不需要更新的參數,可以把它設定為False,可以加快運算。Variable默認是不需要求導的,即requires_grad屬性默認為False,如果某一個節點requires_grad被設為True,那么所有依賴它的節點requires_grad都為True。
用戶在手動定義Variable時,參數requires默認值是False。而在Module中的層在定義時,相關的Variable的requires_grad參數默認是True。在計算圖中,如果有一個輸入的requires_grad是True,那么輸出的requires_grad也是True。只有在所有輸入的requires_grad都為False時,輸出的requires_grad才為False。
Valatile:
指定需不需要保留記錄用的參數。指定參數為True代表不需要記錄(即還要接着更新),可以加快運算。如果有一個參數的volatile是True,則它的requires_grad一定是False。簡單來說,對於需要更新的Variable記得將requires_grad設成True,當只需要得到結果而不需要更新的Variable可以將volatile設成True加快運算速度。
Variable的volatile屬性默認為False,如果某一個Variable的volatile屬性被設為True,那么所有依賴它的節點的volatile屬性都為True。volatile屬性為True的節點不會求導,volatile的優先級比requires_grad的高。
當有一個輸入的volatile=True時,那么輸出的volatile=True。volatile=True推薦在模型推理過程(測試)中使用,這時只需要令輸入的volatile=True,保證用最小的內存來執行推理,不會保存任何中間狀態。在使用volatile=True的時候,變量是不存儲creator屬性的,這樣減少內存的使用。
torch.autograde.Variable是Autograde的核心類,它封裝了Tensor,並整合了反向傳播相關實現
Variable包含三個屬性:
data:存儲了Tensor,是本體數據
grad:保存了data的梯度,是個Variable而非Tensor,與data形狀一致
grad_fn:指向Function對象,用於反向傳播的梯度計算之用
1、data
import torch from torch.autograd import Variable x = Variable(torch.ones(2, 2), requires_grad=True) print(x) print("---------") print(x.data) 輸出: tensor([[ 1., 1.], [ 1., 1.]]) --------- tensor([[ 1., 1.], [ 1., 1.]])
2、梯度求解
構建一個簡單的方程:y=x[0,0] + x[0,1]+ x[1,0]+ x[1,1],variable的運算結果也是Variable,但是,中間結果(Variable類型)反向傳播中不會被求導。
這和Tensorflow不太一致,Tensorflow中中間運算結果的數據結構是Tensor,
y=x.sum() print(y)#tensor(4.)
可以查看目標函數的.grad_fn方法,它用來求梯度,
y.grad_fn # grad_fn:指向Function對象,用於反向傳播的梯度計算之用 print(y.grad_fn) # <SumBackward0 object at 0x00000000021CB908> y.backward() # 反向傳播 x.grad # Variable的梯度保存在Variable.grad中 print(x.grad) #tensor([[ 1., 1.], [ 1., 1.]])
grad屬性保存在Variable中,新的梯度下來會進行累加,可以看到再次求導結果會變成了2
y.backward() x.grad # 可以看到變量梯度是累加的 print(x.grad) #tensor([[ 2., 2.], [ 2., 2.]])
所以要有歸0的操作:
print(x.grad.data.zero_()) #tensor([[ 0., 0.], [ 0., 0.]])
匯總:
1 x = Variable(torch.ones(2, 2), requires_grad=True) 2 print(x) # 1 3 print("---------") 4 print(x.data) # 1 5 y = x.sum() 6 print(y) # tensor(4.) 7 8 y.backward() # 反向傳播 9 x.grad # Variable的梯度保存在Variable.grad中 10 print(x.grad) # 1 11 12 y.backward() 13 x.grad # 可以看到變量梯度是累加的 14 print(x.grad) # 2 15 16 x.grad.data.zero_() 17 print(x.grad) # 0
對比Variable和Tensor的接口,相差無兩:
import torch from torch.autograd import Variable # Variable和Tensor的接口近乎一致,可以無縫切換 x = Variable(torch.ones(2, 2)) y = torch.cos(x) # 傳入Variable x_tensor_cos = torch.cos(x.data) # 傳入Tensor print(y) print(x_tensor_cos) #tensor([[ 0.5403, 0.5403], [ 0.5403, 0.5403]]) tensor([[ 0.5403, 0.5403], [ 0.5403, 0.5403]])
3、自動求導
torch.qutograd包提供Tensor所有操作的自動求導。
3.1、數據結構介紹
autograd.Variable是這個包最核心的類。它包裝一個Tensor,並且幾乎支持所有的定義在其上的操作。一旦完成你的運算,你可以調用.backward()來自動計算出所有的梯度,Variable有三個屬性:

訪問原始的tensor使用屬性.data;
關於這一Variable的梯度則集中於.grad;
.creator反映了創建者,標識了是否由用戶使用.Variable直接創建(None)。
'''求導數''' x = Variable(torch.ones(2, 2), requires_grad=True) y = x + 2 # AttributeError: 'Tensor' object has no attribute 'creator' # print(x.creator) #None,用戶直接創建沒有creater屬性 print(y.creator) # <torch.autograd._functions.basic_ops.AddConstant object at 0x7fb9b4d4b208>
3.2、求導運算
如果你想要進行求導計算,你可以在Variable上調用.backward()。
- 如果Variable是一個標量(例如它包含一個單元素數據),你無需對backward指定任何參數
'''求導數''' x = Variable(torch.ones(2, 2), requires_grad=True) y = x + 2 z = y*y*3 o = z.mean() o.backward() print(x) print(y) print(z) print(x.grad) # 輸出對o對x求倒結果 print(y.grad) # y不是自動求導變量requires_grad沒設為True #tensor([[ 1., 1.], [ 1., 1.]]) tensor([[ 3., 3.], [ 3., 3.]]) tensor([[ 27., 27.], [ 27., 27.]]) tensor([[ 4.5000, 4.5000], [ 4.5000, 4.5000]]) None Process finished with exit code 0
- 如果它有更多的元素(矢量),你需要指定一個和tensor的形狀匹配的grad_output參數(y在指定方向投影對x的導數)
'''求導數''' x = torch.randn(3) x = Variable(x, requires_grad=True) y = x * 2 gradients = torch.FloatTensor([0.5, 0.5, 1]) y.backward(gradients) # 沿着某方向的梯度 print(x.grad) #tensor([ 1., 1., 2.])
參考:
參考3:Pytorch細節記錄
參考4:
