1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Pytorch 常用損失函數(shù)拆解

        共 2116字,需瀏覽 5分鐘

         ·

        2022-02-12 18:23

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

        本文從理論和實踐兩方面來全面梳理一下常用的損失函數(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)
        1. 準(zhǔn)備寫本書
        2. 【虎年大吉】技術(shù)年貨大禮包
        3. 人人都能看懂的EM算法推導(dǎo)
        4. 人工智能基礎(chǔ)設(shè)施發(fā)展態(tài)勢報告2021
        5. 騰訊發(fā)布國內(nèi)首份可解釋 AI 報告!
        6. 一次性總結(jié):64個數(shù)據(jù)分析常用術(shù)語!
        7. 205頁PDF!清華大學(xué)《元宇宙發(fā)展研究報告》
        8. 「沐神」B站教你讀論文:如何判斷研究價值
        9. 神經(jīng)網(wǎng)絡(luò) 3D 可視化,卷積、池化清清楚楚!

        三連在看,月入百萬??

        瀏覽 28
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            人人草人人草人人草 | 欧美午夜理伦三级在线观看潘金莲 | chinese麻豆videoxxxx年轻 | 午夜福礼一卡二卡 | 亚洲精品国产精华 | 成人视频无码在线观看 | 欧美操逼白浆hd | 老牛影视AV牛牛影视av | A片亚洲 精品人妻一区二区三区浪潮在线 | 人人爱人人做 |