<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          你真的理解backward方法了么?

          共 5225字,需瀏覽 11分鐘

           ·

          2022-06-01 11:00


          點(diǎn)擊上方小白學(xué)視覺(jué)”,選擇加"星標(biāo)"或“置頂

          重磅干貨,第一時(shí)間送達(dá)

          轉(zhuǎn)自https://blog.csdn.net/douhaoexia/article/details/78821428


          接觸pytorch很久了,也自認(rèn)為對(duì) backward 方法有一定了解,但看了這篇總結(jié)之后覺(jué)得自己先前真是所知甚少,下面就把這篇對(duì)backward方法的深刻總結(jié)分享給大家!

          ?

          關(guān)于backward()的一些理解


          1. requires_grad 的含義及標(biāo)志位說(shuō)明

          requires_gard 是Tensor變量的一個(gè)屬性,一般默認(rèn)為False。另外,0.4.0版本的 Pytorch 將 Variable 和 Tensor 合并,統(tǒng)稱(chēng)為 Tensor,在過(guò)去的版本中,requires_grad屬性是Variable封裝的屬性

          • 如果對(duì)于某Variable 變量 x ,其?x.requires_grad == True, 則表示 它可以參與求導(dǎo),也可以從它向后求導(dǎo)。默認(rèn)情況下,一個(gè)新的Variables 的 requires_grad 和 volatile 都等于 False
          • requires_grad == True?具有傳遞性:

            如果:x.requires_grad == Truey.requires_grad == False?,?z=f(x,y)則,?z.requires_grad == True

          • 凡是參與運(yùn)算的變量(包括 輸入量,中間輸出量,輸出量,網(wǎng)絡(luò)權(quán)重參數(shù)等),都可以設(shè)置 requires_grad?

          • volatile==True?就等價(jià)于?requires_grad==False?。volatile==True?同樣具有傳遞性。一般只用在inference過(guò)程中。若是某個(gè)過(guò)程,從 x 開(kāi)始 都只需做預(yù)測(cè),不需反傳梯度的話,那么只需設(shè)置x.volatile=True?,那么 x 以后的運(yùn)算過(guò)程的輸出均為?volatile==True?,即?requires_grad==False?。

            雖然inference 過(guò)程不必backward(),所以requires_grad 的值為False 或 True,對(duì)結(jié)果是沒(méi)有影響的,但是對(duì)程序的運(yùn)算效率有直接影響;所以使用volatile=True?,就不必把運(yùn)算過(guò)程中所有參數(shù)都手動(dòng)設(shè)一遍requires_grad=False?了,方便快捷

          • detach()?,如果 x 為中間輸出,x' = x.detach?表示創(chuàng)建一個(gè)與 x 相同,但requires_grad==False?的variable, (實(shí)際上是把x’ 以前的計(jì)算圖 grad_fn 都消除了),x’ 也就成了葉節(jié)點(diǎn)。原先反向傳播時(shí),回傳到x時(shí)還會(huì)繼續(xù),而現(xiàn)在回到x’處后,就結(jié)束了,不繼續(xù)回傳求到了。另外值得注意, x (variable類(lèi)型) 和 x’ (variable類(lèi)型)都指向同一個(gè)Tensor ,即 x.data,而detach_()?表示不創(chuàng)建新變量,而是直接修改 x 本身

          • retain_graph?,每次 backward() 時(shí),默認(rèn)會(huì)把整個(gè)計(jì)算圖free掉。一般情況下是每次迭代,只需一次 forward() 和一次 backward() ,前向運(yùn)算forward() 和反向傳播backward()是成對(duì)存在的,一般一次backward()也是夠用的。但是不排除,由于自定義loss等的復(fù)雜性,需要一次forward(),多個(gè)不同loss的backward()來(lái)累積同一個(gè)網(wǎng)絡(luò)的grad,來(lái)更新參數(shù)。于是,若在當(dāng)前backward()后,不執(zhí)行forward() 而可以執(zhí)行另一個(gè)backward(),需要在當(dāng)前backward()時(shí),指定保留計(jì)算圖,即backward(retain_graph)


          2. 反向求導(dǎo)和權(quán)重更新

          • 求導(dǎo)和優(yōu)化(權(quán)重更新)是兩個(gè)獨(dú)立的過(guò)程,只不過(guò)優(yōu)化時(shí)一定需要對(duì)應(yīng)的已求取的梯度值。所以求得梯度值很關(guān)鍵,而且,經(jīng)常會(huì)累積多種loss對(duì)某網(wǎng)絡(luò)參數(shù)造成的梯度,一并更新網(wǎng)絡(luò)

          • 反向傳播過(guò)程中,肯定需要整個(gè)過(guò)程都鏈?zhǔn)角髮?dǎo)。雖然中間參數(shù)參與求導(dǎo),但是卻可以不用于更新該處的網(wǎng)絡(luò)參數(shù)。參數(shù)更新可以只更新想要更新的網(wǎng)絡(luò)的參數(shù)

          • 如果obj是函數(shù)運(yùn)算結(jié)果,且是標(biāo)量,則 obj.backward() (注意,backward()函數(shù)中沒(méi)有填入任何tensor值, 就相當(dāng)于?backward(torch.tensor([1]))?

          • 對(duì)于繼承自 nn.Module 的某一網(wǎng)絡(luò) net 或網(wǎng)絡(luò)層,定義好后,發(fā)現(xiàn) 默認(rèn)情況下,net.paramters 的 requires_grad 就是 True 的(雖然只是實(shí)驗(yàn)證明的,還未從源碼處找到證據(jù)),這跟普通的Variable張量不同。因此,當(dāng)x.requires_grad == False?,?y = net(x)?后, 有?y.requires_grad == True?;但值得注意,雖然nn.xxloss和激活層函數(shù),是繼承nn.Module的,但是這兩種并沒(méi)有網(wǎng)絡(luò)參數(shù),就更談不上 paramters.requires_grad 的值了。所以類(lèi)似這兩種函數(shù)的輸出,其requires_grad只跟輸入有關(guān),不一定是 True


          3. 計(jì)算圖相關(guān)

          • 計(jì)算圖就是模型 前向forward() 和后向求梯度backward() 的流程參照

          • 能獲取回傳梯度(grad)的只有計(jì)算圖的葉節(jié)點(diǎn)。注意是獲取,而不是求取。中間節(jié)點(diǎn)的梯度在計(jì)算求取并回傳之后就會(huì)被釋放掉,沒(méi)辦法獲取。想要獲取中間節(jié)點(diǎn)梯度,可以使用 register_hook (鉤子)函數(shù)工具。當(dāng)然, register_hook 不僅僅只有這個(gè)作用

          • 只有標(biāo)量才能直接使用 backward(),即loss.backward()?, pytorch 框架中的各種nn.xxLoss(),得出的都是minibatch 中各結(jié)果 平均/求和 后的值。如果使用自定義的函數(shù),得到的不是標(biāo)量,則backward()時(shí)需要傳入 grad_variable 參數(shù)

          • 經(jīng)常會(huì)有這樣的情況:

            x1 —> |net1| —> y1 —> |net2| —> z1 , net1和net2是兩個(gè)不同的網(wǎng)絡(luò)。x1 依次通過(guò) 兩個(gè)網(wǎng)絡(luò)運(yùn)算,生成 z1 。比較擔(dān)心一次性運(yùn)算后,再backward(),是不是只更新net1 而不是net1、net2都更新呢?

            類(lèi)比 x2 —> |f1| —> y2 —> |f2| —> z2 , f1 、f2 是兩個(gè)普通的函數(shù),z2=f2(y2)?,?y2=f1(x2)?


          按照以下格式實(shí)驗(yàn):
          w1 = torch.Tensor([2]) #認(rèn)為w1 與 w2 是函數(shù)f1 與 f2的參數(shù)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 運(yùn)算z2 = w2*y2+1           # f2 運(yùn)算z2.backward()print(x2.grad)print(y2.grad)print(w1.grad)print(w2.grad)


          發(fā)現(xiàn) x2.grad,w1.grad,w2.grad 是個(gè)值 ,但是 y2.grad 卻是?None, 說(shuō)明x2,w1,w2的梯度保留了,y2 的梯度獲取不到。實(shí)際上,仔細(xì)想一想會(huì)發(fā)現(xiàn),x2,w1,w2均為葉節(jié)點(diǎn)。在這棵計(jì)算樹(shù)中 ,x2 與w1 是同一深度(底層)的葉節(jié)點(diǎn),y2與w2 是同一深度,w2 是單獨(dú)的葉節(jié)點(diǎn),而y2 是x2 與 w1 的父節(jié)點(diǎn),所以只有y2沒(méi)有保留梯度值, 印證了之前的說(shuō)法。同樣這也說(shuō)明,計(jì)算圖本質(zhì)就是一個(gè)類(lèi)似二叉樹(shù)的結(jié)構(gòu)。

          那么對(duì)于 兩個(gè)網(wǎng)絡(luò),會(huì)是怎么樣呢?我使用pytorch 的cifar10 例程,稍作改動(dòng)做了實(shí)驗(yàn)。把例程中使用的一個(gè) Alexnet 拆成了兩個(gè)net ------ net1 和 net2 。

          optimizer = torch.optim.SGD(itertools.chain(net1.parameters(), net2.parameters()),lr=0.001, momentum=0.9) # 這里 net1 和net2 優(yōu)化的先后沒(méi)有區(qū)別 !!#optimizer.zero_grad() #將參數(shù)的grad值初始化為0## forward + backward + optimizeoutputs1 = net1(inputs) #input 未置requires_grad為T(mén)rue,但不影響outputs2 = net2(outputs1)loss = criterion(outputs2, labels) #計(jì)算損失loss.backward() #反向傳播#print("inputs.requires_grad:")print(inputs.requires_grad) # Falseprint("the grad of inputs:")print(inputs.grad) # None    print("outputs1.requires_grad:")print(outputs1.requires_grad) # Trueprint("the grad of outputs1:")print(outputs1.grad) # None#print("the grad of net1:")print(net1.conv1.bias.grad) # no-Noneprint("the grad of net2:")print(net2.fc3.bias.grad) # no-None#optimizer.step() #用SGD更新參數(shù)

          后綴注釋就是打印的結(jié)果。可以看出,只有網(wǎng)絡(luò)參數(shù)的grad是直接可獲取的。而且是兩個(gè)網(wǎng)絡(luò)都可以獲取grad 值,獲取grad后,當(dāng)然就可以更新網(wǎng)絡(luò)的參數(shù)了,兩個(gè)網(wǎng)絡(luò)都是可以更新的。

          類(lèi)比上邊例子的解釋?zhuān)瑑蓚€(gè)網(wǎng)絡(luò)其實(shí)就是處在葉節(jié)點(diǎn)的位置,只不過(guò)深度不同。同理,網(wǎng)絡(luò)內(nèi)部的運(yùn)算,每一層網(wǎng)絡(luò)權(quán)重參數(shù)其實(shí)也是處在葉節(jié)點(diǎn)上,只不過(guò)在樹(shù)中的深度不同罷了,前向運(yùn)算時(shí)按照二叉樹(shù)的結(jié)構(gòu),不斷生成父節(jié)點(diǎn)。


          事實(shí)上,原先是以為 網(wǎng)絡(luò) 與 普通函數(shù)不同,因?yàn)樗哂衦egister_xx_hook()這個(gè)類(lèi)函數(shù)工具,所以認(rèn)為它可以默認(rèn)保存權(quán)重參數(shù)的grad來(lái)用于更新,后來(lái)才明白,本質(zhì)上與普通函數(shù)的參數(shù)一樣,都是處在葉節(jié)點(diǎn),就可以保存參數(shù)的grad,至于register_xx_hook(),看來(lái)是另做它用,或者說(shuō)用register_xx_hook()可以記錄甚至更改中間節(jié)點(diǎn)的grad值。


          4. 一些特殊情況

          如果想把網(wǎng)絡(luò)某一部分參數(shù)固定,不讓其被訓(xùn)練,可以使用requires_grad.
          for p in sub_module.parameters():  p.requires_grad = False


          可以這樣理解,因?yàn)槭侨~節(jié)點(diǎn)(而不是中間節(jié)點(diǎn)),所以不求grad(grad為’None’),也不會(huì)影響網(wǎng)絡(luò)的正常反向傳播

          好消息!?

          小白學(xué)視覺(jué)知識(shí)星球

          開(kāi)始面向外開(kāi)放啦??????




          下載1:OpenCV-Contrib擴(kuò)展模塊中文版教程
          在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):擴(kuò)展模塊中文教程即可下載全網(wǎng)第一份OpenCV擴(kuò)展模塊教程中文版,涵蓋擴(kuò)展模塊安裝、SFM算法、立體視覺(jué)、目標(biāo)跟蹤、生物視覺(jué)、超分辨率處理等二十多章內(nèi)容。

          下載2:Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目52講
          小白學(xué)視覺(jué)公眾號(hào)后臺(tái)回復(fù):Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目即可下載包括圖像分割、口罩檢測(cè)、車(chē)道線檢測(cè)、車(chē)輛計(jì)數(shù)、添加眼線、車(chē)牌識(shí)別、字符識(shí)別、情緒檢測(cè)、文本內(nèi)容提取、面部識(shí)別等31個(gè)視覺(jué)實(shí)戰(zhàn)項(xiàng)目,助力快速學(xué)校計(jì)算機(jī)視覺(jué)。

          下載3:OpenCV實(shí)戰(zhàn)項(xiàng)目20講
          小白學(xué)視覺(jué)公眾號(hào)后臺(tái)回復(fù):OpenCV實(shí)戰(zhàn)項(xiàng)目20講即可下載含有20個(gè)基于OpenCV實(shí)現(xiàn)20個(gè)實(shí)戰(zhàn)項(xiàng)目,實(shí)現(xiàn)OpenCV學(xué)習(xí)進(jìn)階。

          交流群


          歡迎加入公眾號(hào)讀者群一起和同行交流,目前有SLAM、三維視覺(jué)、傳感器自動(dòng)駕駛、計(jì)算攝影、檢測(cè)、分割、識(shí)別、醫(yī)學(xué)影像、GAN算法競(jìng)賽等微信群(以后會(huì)逐漸細(xì)分),請(qǐng)掃描下面微信號(hào)加群,備注:”昵稱(chēng)+學(xué)校/公司+研究方向“,例如:”張三?+?上海交大?+?視覺(jué)SLAM“。請(qǐng)按照格式備注,否則不予通過(guò)。添加成功后會(huì)根據(jù)研究方向邀請(qǐng)進(jìn)入相關(guān)微信群。請(qǐng)勿在群內(nèi)發(fā)送廣告,否則會(huì)請(qǐng)出群,謝謝理解~


          瀏覽 35
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧洲国产在线视频 | 天天射天天干天天做 | 成人做爱网址 | 日韩免费视频一区二区三区四区 | 天天爱三级 |