[Pytorch]The `requires_grad` attribute of Tensor

Posted by John on 2018-10-15
Words 954 and Reading Time 3 Minutes
Viewed Times

前陣子死沉keras海裡面……最近好不容易稍微浮上來了結果因為作業需要好像又得去學Pytorch…(再度倒地)

在剛學的時候難免會遇到一些奇奇怪怪的問題,把學習中遇到的問題紀錄一下好讓未來的我看看自己以前有多蠢順便證明我還在新竹活得好好的,最近都沒什麼動態絕對不是因為沒東西吃餓死了。

好的開始講故事:萌新如我,最近透過莫煩大大大概知道pytorch搭建一個神經網絡的模式了,首先

  1. 資料必須是Tensor的型式(注意注意在pytorch 0.4.0 ver之前資料必須是Variable的,不過0.4.0之後Variable和Tensor合併再一起啦~)
  2. 透過class搭建神經網路模型,好久沒碰類別和繼承了,這花了我不少的時間去熟悉。
  3. 重載(?)torch.nn.Module這個class的__init__()和forward()兩個function,建立網絡模型
  4. 建立optimizer, loss function,然後手刻迴圈進行training(keras中這裡都幫你寫好了,只要跟他說epochs要幾次就好了…懷念QQ)

因為是神經網路模型,我們需要用神奇的back propagation(BP)去反向傳遞gradient,達到優化loss的目的,為了達到這個目的我們資料(Tensor)必須是可以求倒數的。

然後我最近練習的時候自己創了一個資料如下:

1
2
x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1)
y = x.pow(2) + 0.2 * torch.rand(x.size())

問題來了,如果去查文件會發現Tensor預設是不能求導數的(Tensor 預設requires_grad是False,再度重申在0.4.0後Tensor和Variable合併了,requires_grad原本是Variable的屬性。),一開始沒注意到這個問題我就傻傻地把資料丟到回歸模型去訓練了,訓練結果也很正常。

然後突然覺得哪裡怪怪的…不對啊?Tensor不是預設不能求導數媽?我沒有更改預設的requires_grad=False屬性為啥還能在模型中正常的做BP????

然後百思不得其解的我就去看了一下我搭建的模型

1
2
3
4
5
6
7
8
9
10
11
12
13
class Net(torch.nn.Module):
def __init__(self, n_feature, n_hidden, n_output):
# 定義網路架構
super(Net, self).__init__() #初始化父類別
self.hidden = torch.nn.Linear(n_feature, n_hidden)
self.predict = torch.nn.Linear(n_hidden, n_output )
def forward(self, x):
print(x.requires_grad)
print((self.hidden(x)).requires_grad)
x = F.relu(self.hidden(x))

x = self.predict(x) # in regression problem, we dont need activation function at output layer
return x

看起來很正常R,可是理論上應該是要有問題的,黑人問號???

我想說一定有某個地方會自動幫我轉requires_grad的屬性,於是我又去一步一步看source code,看到底哪步我的Tensor默默的被轉屬性了,最後我發現在torch.nn.Linear中:

1
2
3
4
5
6
7
8
9
10
11
class Linear(Module):
def __init__(self, in_features, out_features, bias=True):
super(Linear, self).__init__()
self.in_features = in_features
self.out_features = out_features
self.weight = Parameter(torch.Tensor(out_features, in_features))
if bias:
self.bias = Parameter(torch.Tensor(out_features))
else:
self.register_parameter('bias', None)
self.reset_parameters()

用到了torch.nn.Parameter這個,我們在追下去看他是怎麼寫的 :

1
2
3
4
5
6
7
8
9
class Parameter(torch.Tensor):
def __new__(cls, data=None, requires_grad=True):
if data is None:
data = torch.Tensor()
return torch.Tensor._make_subclass(cls, data, requires_grad)
def __repr__(self):
return 'Parameter containing:\n' + super(Parameter, self).__repr__()
def __reduce_ex__(self, proto):
return Parameter, (super(Parameter, self), self.requires_grad)

有沒有看到def __new__(cls, data=None, requires_grad=True)了!!哎呀呀原來是在將Linear Model轉成Parameters的時候自動幫我們將資料屬性轉成requires_grad=True了呢,所以後續的才能正常地進行BP求導。

好啦結論是解決了為啥我忘記對資料的Tensor加上requires_grad=True也能正常的訓練模型呢?因為在Linear模型中某一個步驟(torch.nn.Paramenter)自動幫我們將資料的屬性轉換了。

好啦這篇只是寫給自己看的xD應該也沒人想知道這個吧。


>