關於backward 的一些理解

2021-10-05 17:11:49 字數 2765 閱讀 5875

requires_gard 是tensor變數的乙個屬性,一般預設為false。另外,0.4.0版本的 pytorch 將 variable 和 tensor 合併,統稱為 tensor,在過去的版本中,requires_grad屬性是variable封裝的屬性

按照以下格式實驗:

w1 = torch.tensor([2

])#認為w1 與 w2 是函式f1 與 f2的引數

w1 = variable(w1,requires_grad=

true

)w2 = torch.tensor([2

])w2 = variable(w2,requires_grad=

true

)x2 = torch.rand(1)

x2 = variable(x2,requires_grad=

true

)y2 = x2**w1 # f1 運算

z2 = w2*y2+

1# f2 運算

z2.backward(

)print

(x2.grad)

print

(y2.grad)

print

(w1.grad)

print

(w2.grad)

發現 x2.grad,w1.grad,w2.grad 是個值 ,但是 y2.grad 卻是 none, 說明x2,w1,w2的梯度保留了,y2 的梯度獲取不到。實際上,仔細想一想會發現,x2,w1,w2均為葉節點。在這棵計算樹中 ,x2 與w1 是同一深度(底層)的葉節點,y2與w2 是同一深度,w2 是單獨的葉節點,而y2 是x2 與 w1 的父節點,所以只有y2沒有保留梯度值, 印證了之前的說法。同樣這也說明,計算圖本質就是乙個類似二叉樹的結構。

那麼對於 兩個網路,會是怎麼樣呢?我使用pytorch 的cifar10 例程,稍作改動做了實驗。把例程中使用的乙個 alexnet 拆成了兩個net ------ net1 和 net2 。

optimizer = torch.optim.sgd(itertools.chain(net1.parameters(

), net2.parameters())

,lr=

0.001

, momentum=

0.9)

# 這裡 net1 和net2 優化的先後沒有區別 !!

#optimizer.zero_grad(

)#將引數的grad值初始化為0

## forward + backward + optimize

outputs1 = net1(inputs)

#input 未置requires_grad為true,但不影響

outputs2 = net2(outputs1)

loss = criterion(outputs2, labels)

#計算損失

loss.backward(

)#反向傳播

#print

("inputs.requires_grad:"

)print

(inputs.requires_grad)

# false

print

("the grad of inputs:"

)print

(inputs.grad)

# none

print

("outputs1.requires_grad:"

)print

(outputs1.requires_grad)

# true

print

("the grad of outputs1:"

)print

(outputs1.grad)

# none

#print

("the grad of net1:"

)print

(net1.conv1.bias.grad)

# no-none

print

("the grad of net2:"

)print

(net2.fc3.bias.grad)

# no-none

#optimizer.step(

)#用sgd更新引數

字尾注釋就是列印的結果。可以看出,只有網路引數的grad是直接可獲取的。而且是兩個網路都可以獲取grad 值,獲取grad後,當然就可以更新網路的引數了,兩個網路都是可以更新的。

模擬上邊例子的解釋,兩個網路其實就是處在葉節點的位置,只不過深度不同。同理,網路內部的運算,每一層網路權重引數其實也是處在葉節點上,只不過在樹中的深度不同罷了,前向運算時按照二叉樹的結構,不斷生成父節點。

事實上,原先是以為 網路 與 普通函式不同,因為它具有register_xx_hook()這個類函式工具,所以認為它可以預設儲存權重引數的grad來用於更新,後來才明白,本質上與普通函式的引數一樣,都是處在葉節點,就可以儲存引數的grad,至於register_xx_hook(),看來是另做它用,或者說用register_xx_hook()可以記錄甚至更改中間節點的grad值。

如果想把網路某一部分引數固定,不讓其被訓練,可以使用requires_grad.

for p in sub_module.parameters():

p.requires_grad =

false

可以這樣理解,因為是葉節點(而不是中間節點),所以不求grad(grad為』none』),也不會影響網路的正常反向傳播

關於熵的一些理解

對於理工科學生來說,熵 並不是乙個陌生的名詞。在諸如 大學物理 熱力學 和 資訊理論 等課程中都會有所介紹。但同時 熵 又是乙個顯得有點神秘的概念,看不見也摸不著。我最早是在高中物理課中聽說的,大概是在介紹 熱力學第二定律 時提到的。熱力學第二定律的內容是 熱力學過程是不可逆的 孤立系統自發地朝著熱...

關於float的一些理解

float是否脫離文件流,乙個父元素不設定overflow的話,子元素float,就不會把父元素撐開,換句話說,他就不會有高度,但是做個demo 父元素overflow hidden 子元素前兩個float,第三個不float,結果是第三個沒有clear浮動的元素,跟float的元素出現在同乙個位置...

關於android layout的一些理解

1 wrap content view的尺寸根據它的內容確定 match parent view的尺寸盡量和它的parent view group一樣大 2 獲得view的位置 position getleft gettop getright getleft getwidth getwidth 3 ...