pytorch系列 --3 Variable,Tensor 和 Gradient

Variable & Automatic Gradient Calculation

  • Tensor vs Variable
  • graph and gradient
    注意,在pytorch0.4中,tensor和pytorch合併了。
    https://pytorch.org/blog/pytorch-0_4_0-migration-guide/
    torch.Tensor 和 torch.autograd.Variable 是同一個類,更準確的說,torch.Tensor 也能像舊的Variable一樣
    追蹤歷史,進行梯度計算等。Variable 仍然正常工作,但是返回的對象是torch.Tensor,這意味着不需要在代碼中使用Variable(Tensor)了。

但是此篇文章主要講述Variable的相關知識,將在下一篇在文章中講述pytorch0.4的具體變化

引進庫


import torch
from torch.autograd import Variable

Tensor 和 Variable

Variable:
在這裏插入圖片描述

autograde.Variable是一個類,在使用tensor_variable = autograde.Variable(tensor)後,
tensor_variable 有三個重要的屬性:

  • data:保存着tensor_variable 的tensor向量
  • grad: 保存tensor_variable 的梯度值
  • grad_fn: 保存創建tensor_variable 的函數
    此外,還有一個屬性requires_grad確定tensor_variable 是否具有求導的功能。
    以上Variable就是pytorch實現反向傳播最核心的先決條件。
    接下里來看一下Variable的具體功能:

1) 聲明 declaration

x_tensor = torch.Tensor(3,4)
x_tensor

out:

-12170.8672 0.0000 -12170.8672 0.0000
0.0000 0.0000 0.0000 0.0000
-12170.9453 0.0000 -12170.9453 0.0000
[torch.FloatTensor of size 3x4]

使用Variale轉換Tensor

x_variable = Variable(x_tensor)
x_variable

out:

12170.8672 0.0000 -12170.8672 0.0000
0.0000 0.0000 0.0000 0.0000
-12170.9453 0.0000 -12170.9453 0.0000
[torch.FloatTensor of size 3x4]

2)Variable的屬性

.data :Variable的Tensor數據

# .data -> wrapped tensor 
x_variable.data

out:

-12170.8672 0.0000 -12170.8672 0.0000
0.0000 0.0000 0.0000 0.0000
-12170.9453 0.0000 -12170.9453 0.0000
[torch.FloatTensor of size 3x4]

.grad: variable的梯度值

# .grad -> gradient of the variable
print(x_variable.grad)

out:

None

.reqires_grad: variable是否能進行梯度計算

# .requires_grad -> whether variable requres gradient
print(x_variable.requires_grad)

x_variable = Variable(x_tensor,requires_grad=True)
x_variable.requires_grad

.grad_fn: variable的創建函數

y = x_variable * 2

print(y.grad_fn)

out:

<MulBackward object at 0x0000012641CF6F98>

3. Graph & Variables

先看一個簡單的計算圖的例子:
可以簡單的計算出w的梯度是x,也就是2,其餘x,b的同樣的可以簡單計算出。

w = Variable(torch.Tensor([1]), requires_grad=True)
x = Variable(torch.Tensor([2]), requires_grad=True)
b = Variable(torch.Tensor([3]), requires_grad=True)
y=w*x+b  # y=1*x +2

y.backward()
print(w.grad, x.grad, b.grad)

out:

2 1 1

接下來,將x的requires_grad=True改爲requires_grad=False,此時求x的grad:

可以發現x的grad是None,也就是沒有計算保留x的梯度

w = Variable(torch.Tensor([1]), requires_grad=True)
x = Variable(torch.Tensor([2]),  requires_grad=False)
b = Variable(torch.Tensor([3]), requires_grad=True)
y=w*x+b  # y=1*x +2

y.backward()
print(x.grad)

out:

2 None 1

如果求梯度的值是一個向量張量,而非標量張量呢?假設對於z是一個長度爲4的一維張量。那要求z,4個維度上的梯度值了,這個概念在數學中並不陌生,比如y是多維輸出,那麼要在y每一個維度上求梯度值。此時要使用gradients參數,要求gradients的size和y的size相同.同時:
gradientsygradgradients每一維度上的值 *y每一維度上的梯度值 爲 最終參數中grad保留的值

下面通過例子看一下:
看一下輸出:
第2行只計算了z第一個值得梯度,第3行只計算了z第2個值得梯度,
而第4行計算了z所有是個值得輸出,第5行將第四行的輸出在乘以gradients的每一個值得到最終的梯度。


x = Variable(torch.FloatTensor([1, 2, 3, 4]), requires_grad=True)
z = 2*x
print(z, z.size())
# do backward for first element of z
z.backward(torch.FloatTensor([1, 0, 0, 0]))
print(x.grad.data)
x.grad.data.zero_() #remove gradient in x.grad, or it will be accumulated

# do backward for second element of z
z.backward(torch.FloatTensor([0, 1, 0, 0]))
print(x.grad.data)
x.grad.data.zero_()

# do backward for all elements of z, with weight equal to the derivative of
# loss w.r.t z_1, z_2, z_3 and z_4
z.backward(torch.FloatTensor([1, 1, 1, 1]))
print(x.grad.data)
x.grad.data.zero_()

z.backward(torch.FloatTensor([1, 0.1, 0.01, 0.001]))
print(x.grad.data)

out:

tensor([2., 4., 6., 8.], grad_fn=) torch.Size([4])
tensor([2., 0., 0., 0.])
tensor([0., 2., 0., 0.])
tensor([2., 2., 2., 2.])
tensor([2.0000, 0.2000, 0.0200, 0.0020])

對於神經網絡而言,最後的loss都是一個標量形式,所以不需要傳入gradients,採用標量形式的梯度計算即可。

from torch.autograd import Variable
import torch
x = Variable(torch.FloatTensor([[1, 2, 3, 4]]), requires_grad=True)
z = 2*x
loss = z.sum(dim=1)

# do backward for first element of z
z.backward(torch.FloatTensor([[1, 0, 0, 0]]))
print(x.grad.data)
x.grad.data.zero_() #remove gradient in x.grad, or it will be accumulated

# do backward for second element of z
z.backward(torch.FloatTensor([[0, 1, 0, 0]]))
print(x.grad.data)
x.grad.data.zero_()

# do backward for all elements of z, with weight equal to the derivative of
# loss w.r.t z_1, z_2, z_3 and z_4
z.backward(torch.FloatTensor([[1, 1, 1, 1]]))
print(x.grad.data)
x.grad.data.zero_()

# or we can directly backprop using loss
loss.backward() # equivalent to loss.backward(torch.FloatTensor([1.0]))
print(x.grad.data)

代碼最後一行的輸出爲:
out:

2 2 2 2
[torch.FloatTensor of size 1x4]

可以看出使用loss可以達到與調用z.backward(gradients)相同的作用。該問題參考stackoverflowhttps://stackoverflow.com/questions/43451125/pytorch-what-are-the-gradient-arguments

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章