<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>

          實操教程|Pytorch常用損失函數(shù)拆解

          共 2243字,需瀏覽 5分鐘

           ·

          2022-01-09 15:28

          點擊上方視學(xué)算法”,選擇加"星標(biāo)"或“置頂

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

          作者 | 小新?
          來源 | https://lhyxx.top?
          編輯 | 極市平臺

          導(dǎo)讀

          ?

          本文從理論和實踐兩方面來全面梳理一下常用的損失函數(shù)。(避免自己總是一瓶子不滿半瓶子晃蕩……)。要么理論滿分,編碼時不會用;要么編碼是會調(diào)包,但是不明白其中的計算原理。本文來科普一下。?

          本文從理論和實踐兩方面來全面梳理一下常用的損失函數(shù)。(避免自己總是一瓶子不滿半瓶子晃蕩……)。要么理論滿分,編碼時不會用;要么編碼是會調(diào)包,但是不明白其中的計算原理。本文來科普一下。

          我們將每個損失函數(shù)分別從理論和pytorch中的實現(xiàn)兩個方面來拆解一下。

          另外,解釋一下torch.nn.Module 和 torch.nn.functional(俗稱F)中損失函數(shù)的區(qū)別。

          Module的損失函數(shù)例如CrossEntropyLoss、NLLLoss等是封裝之后的損失函數(shù)類,是一個類,因此其中的變量可以自動維護(hù)。經(jīng)常是對F中的函數(shù)的封裝。而F中的損失函數(shù)只是單純的函數(shù)。

          當(dāng)然我們也可以自己構(gòu)造自己的損失函數(shù)對象。有時候損失函數(shù)并不需要太復(fù)雜,沒有必要特意封裝一個類,直接調(diào)用F中的函數(shù)也是可以的。使用哪種看具體實現(xiàn)需求而定。

          CrossEntropyLoss

          交叉熵?fù)p失,是分類任務(wù)中最常用的一個損失函數(shù)。

          理論

          直接上理論公式:

          其中 是真實標(biāo)簽, 是預(yù)測的類分布(通常是使用softmax將模 型輸出轉(zhuǎn)換為概率分布), 也就是 中的元素分別表示對應(yīng)類 別的概率。

          舉個例子,清晰明了:

          # 假設(shè)該樣本屬于第二類 # 因為是分布, 所以屬于各個類的和為 1

          pytorch-實現(xiàn)

          from?torch.nn?import?CrossEntropyLoss

          舉例:

          實際使用中需要注意幾點:

          • torch.nn.CrossEntropyLoss(input, target)中的標(biāo)簽target使用的不是one-hot形式,而是類別的序號。形如 target = [1, 3, 2] 表示3個樣本分別屬于第1類、第3類、第2類。

          • torch.nn.CrossEntropyLoss(input, target)input沒有歸一化的每個類的得分,而不是softmax之后的分布。

          舉例,輸入的形式大概就像相面這種格式:

          然后就將他們?nèi)拥紺rossEntropyLoss函數(shù)中,就可以得到損失。

          loss?=?CrossEntropyLoss(input,?target)

          我們看CrossEntropyLoss函數(shù)里面的實現(xiàn),是下面這樣子的:

          def?forward(self,?input,?target):
          ????return?F.cross_entropy(input,?target,?weight=self.weight,
          ???????????????????????????ignore_index=self.ignore_index,?reduction=self.reduction)

          是調(diào)用的torch.nn.functional(俗稱F)中的cross_entropy()函數(shù)。

          參數(shù)

          • input:預(yù)測值,(batch,dim),這里dim就是要分類的總類別數(shù)

          • target:真實值,(batch),這里為啥是1維的?因為真實值并不是用one-hot形式表示,而是直接傳類別id。

          • weight:指定權(quán)重,(dim),可選參數(shù),可以給每個類指定一個權(quán)重。通常在訓(xùn)練數(shù)據(jù)中不同類別的樣本數(shù)量差別較大時,可以使用權(quán)重來平衡。

          • ignore_index:指定忽略一個真實值,(int),也就是手動忽略一個真實值。

          • reduction:在[none, mean, sum]中選,string型。none表示不降維,返回和target相同形狀;mean表示對一個batch的損失求均值;sum表示對一個batch的損失求和。

          其中參數(shù)weight、ignore_index、reduction要在實例化CrossEntropyLoss對象時指定,例如:

          loss?=?torch.nn.CrossEntropyLoss(reduction='none')

          我們再看一下F中的cross_entropy的實現(xiàn)

          return?nll_loss(log_softmax(input,?dim=1),?target,?weight,?None,?ignore_index,?None,?reduction)

          可以看到就是先調(diào)用log_softmax,再調(diào)用nll_loss

          log_softmax就是先softmax再取log

          nll_loss 是negative log likelihood loss:

          詳細(xì)介紹見下面torch.nn.NLLLoss,計算公式如下:

          例如假設(shè) , class ,則,class class

          源碼中給了個用法例子:

          #?input?is?of?size?N?x?C?=?3?x?5
          input?=?torch.randn(3,?5,?requires_grad=True)
          #?each?element?in?target?has?to?have?0?<=?value?
          target?=?torch.tensor([1,?0,?4])
          output?=?F.nll_loss(F.log_softmax(input),?target)
          output.backward()

          因此,其實CrossEntropyLoss損失,就是softmax + log + nll_loss的集成。

          CrossEntropyLoss(input,?target)?=?nll_loss(log_softmax(input,?dim=1),?target)

          CrossEntropyLoss中的target必須是LongTensor類型。

          實驗如下:

          pred?=?torch.FloatTensor([[2,?1],?[1,?2]])
          target?=?torch.LongTensor([1,?0])

          loss_fun?=?nn.CrossEntropyLoss()

          loss?=?loss_fun(pred,?target)??
          print(loss)??#?輸出為tensor(1.3133)
          loss2?=?F.nll_loss(F.log_softmax(pred,?dim=1),?target)
          print(loss2)??#?輸出為tensor(1.3133)

          數(shù)學(xué)形式就是:

          torch-nn-BCELoss

          理論

          CrossEntropy損失函數(shù)適用于總共有N個類別的分類。當(dāng)N=2時,即二分類任務(wù),只需要判斷是還是否的情況,就可以使用二分類交叉熵?fù)p失:BCELoss 二分類交叉熵?fù)p失。上公式 (y是真實標(biāo)簽,x是預(yù)測值)

          其實這個函數(shù)就是CrossEntropyLoss的當(dāng)類別數(shù)N=2時候的特例。因為類別數(shù)為2,屬于第一類的概率為y,那么屬于第二類的概率自然就是(1-y)。因此套用與CrossEntropy損失的計算方法,用對應(yīng)的標(biāo)簽乘以對應(yīng)的預(yù)測值再求和,就得到了最終的損失。

          實踐

          torch.nn.BCELoss(x,?y)

          x形狀(batch,*),y形狀與x相同。

          x與y中每個元素,表示的是該維度上屬于(或不屬于)這個類的概率。

          另外,pytorch中的BCELoss可以為每個類指定權(quán)重。通常,當(dāng)訓(xùn)練數(shù)據(jù)中正例和反例的比例差別較大時,可以為其賦予不同的權(quán)重,weight的形狀應(yīng)該是一個一維的,元素的個數(shù)等于類別數(shù)。

          實際使用如下例,計算BCELoss(pred, target):

          pred?=?torch.FloatTensor([0.4,?0.1])??#?可以理解為第一個元素分類為是的概率為0.4,第二個元素分類為是的概率為0.1。
          target?=?torch.FloatTensor([0.2,?0.8])??#?實際上第一個元素分類為是的概率為0.2,第二個元素分類為是的概率為0.8。
          loss_fun?=?nn.BCELoss(reduction='mean')??#?reduction可選?none,?sum,?mean,?batchmean
          loss?=?loss_fun(pred,?target)
          print(loss)??#?tensor(1.2275)

          a?=?-(0.2?*?np.log(0.4)?+?0.8?*?np.log(0.6)?+?0.8?*?np.log(0.1)?+?0.2?*?np.log(0.9))/2
          print(a)??#?1.2275294114572126

          可以看到,計算BCELoss(pred,target)與上面理論中的公式一樣。

          內(nèi)部實現(xiàn)

          pytorch 中的torch.nn.BCELoss類,實際上就是調(diào)用了F.binary_cross_entropy(input, target, weight=self.weight, reduction=self.reduction)

          torch.nn.BCEWithLogitsLoss

          理論

          該函數(shù)實際上與BCELoss相同,只是BCELoss的輸入x,在輸入之前需要先手動經(jīng)過sigmoid激活函數(shù)映射到(0, 1)區(qū)間,而該函數(shù)將sigmoid與BCELoss整合到一起了

          也就是先將輸入經(jīng)過sigmoid函數(shù),然后計算BCE損失。

          實踐

          torch.nn.BCEWithLogitsLoss(x,?y)

          x與y的形狀要求與BCELoss相同。

          pred?=?torch.FloatTensor([0.4,?0.1])
          target?=?torch.FloatTensor([0.2,?0.8])
          loss_fun?=?nn.BCEWithLogitsLoss(reduction='mean')??#?reduction可選?none,?sum,?mean,?batchmean
          loss?=?loss_fun(pred,?target)
          print(loss)??#?tensor(0.7487)

          #?上面的過程與下面的過程結(jié)果相同
          loss_fun?=?nn.BCELoss(reduction='mean')??#?reduction可選?none,?sum,?mean,?batchmean
          loss?=?loss_fun(torch.sigmoid(pred),?target)??#?先經(jīng)過sigmoid,然后與target計算BCELoss
          print(loss)??#?tensor(0.7487)

          可以看出,先對輸入pred調(diào)用sigmoid,在調(diào)用BCELoss,結(jié)果就等于直接調(diào)用BCEWithLogitsLoss。

          torch.nn.L1Loss

          理論

          L1損失很簡單,公式如下:

          x是預(yù)測值,y是真實值。

          實踐

          torch.nn.L1Loss(x,?y)

          x形狀:任意形狀

          y形狀:與輸入形狀相同

          pred?=?torch.FloatTensor([[3,?1],?[1,?0]])
          target?=?torch.FloatTensor([[1,?0],?[1,?0]])
          loss_fun?=?nn.L1Loss()
          loss?=?loss_fun(pred,?target)
          print(loss)??#?tensor(0.7500)

          其中L1Loss的內(nèi)部實現(xiàn)為:

          def?forward(self,?input,?target):
          ????return?F.l1_loss(input,?target,?reduction=self.reduction)

          我們可以看到,其實還是對F.l1_loss的封裝。

          torch.nn.MSELoss

          理論

          L1Loss可以理解為向量的1-范數(shù),MSE均方誤差就可以理解為向量的2-范數(shù),或矩陣的F-范數(shù)。

          x是預(yù)測值,y是真實值。

          實踐

          torch.nn.MSELoss(x,?y)

          x任意形狀,y與x形狀相同。

          pred?=?torch.FloatTensor([[3,?1],?[1,?0]])
          target?=?torch.FloatTensor([[1,?0],?[1,?0]])
          loss_fun?=?nn.MSELoss()
          loss?=?loss_fun(pred,?target)
          print(loss)??#?tensor(1.2500)

          其中MSELoss內(nèi)部實現(xiàn)為:

          def?forward(self,?input,?target):
          ????return?F.mse_loss(input,?target,?reduction=self.reduction)

          本質(zhì)上是對F中mse_loss函數(shù)的封裝。

          torch.nn.NLLLoss

          理論

          NLLLoss(Negative Log Likelihood Loss),其數(shù)學(xué)表達(dá)形式為:

          前面講到CrossEntropyLoss中用的nll_loss,實際上,該損失函數(shù)就是對F.nll_loss的封裝,功能也和nll_loss相同。

          正如前面所說,先把輸入x進(jìn)行softmax,在進(jìn)行log,再輸入該函數(shù)中就是CrossEntropyLoss

          實踐

          torch.nn.NLLLoss(x,?y)

          x是預(yù)測值,形狀為(batch,dim)

          y是真實值,形狀為(batch)

          形狀要求與CrossEntropyLoss相同。

          pred?=?torch.FloatTensor([[3,?1],?[2,?4]])
          target?=?torch.LongTensor([0,?1])??#target必須是Long型
          loss_fun?=?nn.NLLLoss()
          loss?=?loss_fun(pred,?target)
          print(loss)??#?tensor(-3.5000)

          其內(nèi)部實現(xiàn)實際上就是調(diào)用了F.nll_loss():

          def?forward(self,?input,?target):
          ????return?F.nll_loss(input,?target,?weight=self.weight,?ignore_index=self.ignore_index,?reduction=self.reduction)

          torch.nn.KLDivLoss

          理論

          KL散度通常用來衡量兩個連續(xù)分布之間的距離。兩個分布越相似,KL散度越接近0。

          KL散度又叫相對熵,具體理論可以參考:https://lhyxx.top/2019/09/15/%E4%BF%A1%E6%81%AF%E8%AE%BA%E5%9F%BA%E7%A1%80-%E7%86%B5/

          注意,這里 x 與 y 都是分布,分布就意味著其中所有元素求和概率為1。

          則:

          本例中計算的 都是以e為底的。

          實踐

          torch.nn.KLDivLoss(input,?target)

          試驗測試torch.nn.KLDivLoss,計算KL(pred|target)

          pred?=?torch.FloatTensor([0.1,?0.2,?0.7])
          target?=?torch.FloatTensor([0.5,?0.2,?0.3])
          loss_fun?=?nn.KLDivLoss(reduction='sum')??#?reduction可選?none,?sum,?mean,?batchmean
          loss?=?loss_fun(target.log(),?pred)
          print(loss)??#?tensor(0.4322)

          #上面的計算過程等價于下面
          a?=?(0.1?*?np.log(1/5)?+?0.2?*?np.log(1)?+?0.7?*?np.log(7/3))
          print(a)??#?0.43216

          input應(yīng)該是log-probabilities,target是probabilities。inputtarget形狀相同。

          該函數(shù)是對F.kl_div(input, target, reduction=self.reduction)的封裝。其原型為:torch.nn.functional.kl_div(input, target, size_average=None, reduce=None, reduction='mean')

          注意,使用nn.KLDivLoss計算KL(pred|target)時,需要將predtarget調(diào)換位置,而且target需要先取對數(shù):

          loss_fun(target.log(),?pred)

          如果覺得有用,就請分享到朋友圈吧!


          點個在看 paper不斷!

          瀏覽 67
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  午夜福利在线视频 | 女人荫蒂被添高潮视频 | 黄色免费在线观看 | 日本日批视频 | AV在线影音 |