網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
目前pytorch中的交叉熵?fù)p失函數(shù)主要分為以下三類,我們將其使用的要點(diǎn)以及場(chǎng)景做一下總結(jié)。
類型一:F.cross_entropy()與torch.nn.CrossEntropyLoss()
- 輸入:非onehot label + logit。函數(shù)會(huì)自動(dòng)將logit通過(guò)softmax映射為概率。
- 使用場(chǎng)景:都是應(yīng)用于互斥的分類任務(wù),如典型的二分類以及互斥的多分類。
- 網(wǎng)絡(luò):分類個(gè)數(shù)即為網(wǎng)絡(luò)的輸出節(jié)點(diǎn)數(shù)
類型二:F.binary_cross_entropy_with_logits()與torch.nn.BCEWithLogitsLoss()
- 輸入:logit。函數(shù)會(huì)自動(dòng)將logit通過(guò)sidmoid映射為概率。
- 使用場(chǎng)景:① 二分類 ② 非互斥多分類
- 網(wǎng)絡(luò):使用這類損失函數(shù)需要將網(wǎng)絡(luò)輸出的每一個(gè)節(jié)點(diǎn)當(dāng)作一個(gè)二分類的節(jié)點(diǎn)? ? ? ? ? ? ? ? ??
①當(dāng)為標(biāo)準(zhǔn)的二分類時(shí),網(wǎng)絡(luò)的輸出節(jié)點(diǎn)為1
②當(dāng)為非互斥的多分類時(shí),分類個(gè)數(shù)即為網(wǎng)絡(luò)的輸出節(jié)點(diǎn)數(shù)
類型三:F.binary_cross_entropy()與torch.nn.BCELoss()
- 輸入:prob(概率)。這個(gè)概率可以由softmax計(jì)算而來(lái),也可以由sigmoid計(jì)算而來(lái)。兩種不同的概率映射方式對(duì)應(yīng)不同的分類任務(wù)。
- 使用場(chǎng)景:① 二分類 ② 非互斥多分類
- 網(wǎng)絡(luò):①標(biāo)準(zhǔn)的二分類任務(wù):網(wǎng)絡(luò)的輸出節(jié)點(diǎn)可以為1,此時(shí)概率必須由sigmoid進(jìn)行映射;? ? ? ? ? ? ? ? ? ? ??
網(wǎng)絡(luò)的輸出節(jié)點(diǎn)可以為2,此時(shí)概率必須由softmax進(jìn)行映射。
②當(dāng)為非互斥的多分類時(shí),分類個(gè)數(shù)即為網(wǎng)絡(luò)的輸出節(jié)點(diǎn)數(shù),此時(shí)概率必須由sigmoid進(jìn)行映射
1.二分類
類型一:F.cross_entropy()與torch.nn.CrossEntropyLoss()
- 網(wǎng)絡(luò)的輸出節(jié)點(diǎn)為2,表示real和fake(類別1和類別2)
類型二:F.binary_cross_entropy_with_logits()與torch.nn.BCEWithLogitsLoss()
- 由于這兩個(gè)函數(shù)自帶sigmoid函數(shù),要想完成二分類,網(wǎng)絡(luò)的輸出節(jié)點(diǎn)個(gè)數(shù)必須設(shè)置為1
類型三:F.binary_cross_entropy()與torch.nn.BCELoss(),以下兩種情況都可以使用:
- 當(dāng)網(wǎng)絡(luò)輸出的節(jié)點(diǎn)為2時(shí),一個(gè)節(jié)點(diǎn)為real另一個(gè)節(jié)點(diǎn)為fake,那么必然要采用softmax將logits映射為概率(兩個(gè)節(jié)點(diǎn)的概率和為1),此時(shí)該函數(shù)輸入為onehot label + softmax prob,計(jì)算出的交叉熵?fù)p失與類型一結(jié)算結(jié)果相同。
- 當(dāng)網(wǎng)絡(luò)的輸出節(jié)點(diǎn)為1時(shí),也就是后面我們要講的GAN的交叉熵?fù)p失的實(shí)現(xiàn),那么則需要使用sigmoid函數(shù)來(lái)進(jìn)行映射。
這里我們以網(wǎng)絡(luò)輸出節(jié)點(diǎn)為2為例,由于類型二要求網(wǎng)絡(luò)的輸出節(jié)點(diǎn)為1,因此暫時(shí)不納入討論,主要討論類型和類型三。
測(cè)試代碼如下:
(網(wǎng)絡(luò)輸出節(jié)點(diǎn)為1的二分類就是目前GAN的實(shí)現(xiàn)方式,該方式下類型一的函數(shù)不可用,只能采用類型二和類型三,后面將會(huì)詳細(xì)討論)
softmax = torch.nn.Softmax()
logits = np.array([[0.7, -0.1],
? ? ? ? ? ? ? ? ? ? [-1.587, ?-0.5907]])
classes = 2
label = torch.tensor([1, 1])
logits = torch.from_numpy(logits).float()
?
#F.cross_entropy
loss1 = F.cross_entropy(logits, label) ?
print(loss1)
?
#nn.CrossEntropyLoss()
criterion = nn.CrossEntropyLoss()
loss2 = criterion(logits, label)
print(loss2)
?
#可以看到,loss1是等于loss2的
?
prob = softmax(logits) ?#計(jì)算概率
one_hot_label = one_hot(label, classes)
?
#F.binary_cross_entropy
loss3 = F.binary_cross_entropy(prob, one_hot_label) #輸入概率和one-hot
print(loss3)
?
#torch.nn.BCELoss()
adversarial_loss = torch.nn.BCELoss()
loss4 = adversarial_loss(prob, one_hot_label)
print(loss4)
?
#同理,loss3是等于loss4的
?
#手動(dòng)實(shí)現(xiàn)二分類的交叉熵?fù)p失
shixian = -torch.mean(torch.sum(one_hot_label * torch.log(prob), axis = 1)) ?#手動(dòng)實(shí)現(xiàn)
print(shixian)
2.多分類
此時(shí)網(wǎng)絡(luò)輸出時(shí)多節(jié)點(diǎn),每一個(gè)節(jié)點(diǎn)代表一個(gè)類別。
類型一:F.cross_entropy()與torch.nn.CrossEntropyLoss()
- 可以用于多分類的互斥任務(wù),輸入非onehot label + logit。但是不能用于多分類多標(biāo)簽任務(wù)。因?yàn)檫@兩個(gè)函數(shù)中自帶的softmax將網(wǎng)絡(luò)的每一個(gè)節(jié)點(diǎn)都當(dāng)作時(shí)互斥的獨(dú)立節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)的概率和為1,因?yàn)楦怕首畲蟮哪莻€(gè)節(jié)點(diǎn)的類別會(huì)被當(dāng)為最終的預(yù)測(cè)類別
類型二:F.binary_cross_entropy_with_logits()與torch.nn.BCEWithLogitsLoss()
- 不能用于多分類的互斥任務(wù),只能用于多分類的非互斥任務(wù)
類型三:F.binary_cross_entropy()與torch.nn.BCELoss()
- 與類型二一樣,不能用于多分類的互斥任務(wù),只能用于多分類的非互斥任務(wù)。
這里我們首先討論下類型一和類型三,為什么類型三不能用于多分類的互斥任務(wù),只能用于多分類多標(biāo)簽的分類任務(wù)?我們來(lái)看一段代碼,這里有三個(gè)類別,兩個(gè)樣本。
softmax = torch.nn.Softmax()
logits = np.array([[0.7, -0.1, 0.2],
? ? ? ? ? ? ? ? ? ? [-1.587, ?-0.5907, 0.3]])
classes = 3
label = torch.tensor([1, 2])
logits = torch.from_numpy(logits).float()
?
### F.cross_entropy
loss1 = F.cross_entropy(logits, label) ?
print(loss1)
?
### nn.CrossEntropyLoss()
criterion = nn.CrossEntropyLoss()
loss2 = criterion(logits, label)
print(loss2)
##loss1 = loss2
上面是采用類型一的兩個(gè)函數(shù)計(jì)算而來(lái),loss1 = loss2 = 0.9833
然后我們用類型三的函數(shù)來(lái)實(shí)現(xiàn),同樣將logit通過(guò)softmax映射為概率,運(yùn)行后的結(jié)果可以看loss3 =loss4 = 0.5649,不等于類型一的函數(shù)的結(jié)果的。
prob_softmax = softmax(logits) ?#計(jì)算概率
one_hot_label = one_hot(label, classes)
?
## F.binary_cross_entropy
loss3 = F.binary_cross_entropy(prob_softmax, one_hot_label) #輸入概率和one-hot
print(loss3)
?
## torch.nn.BCELoss()
adversarial_loss = torch.nn.BCELoss()
loss4 = adversarial_loss(prob_softmax, one_hot_label)
print(loss4)
最后我們?cè)偈謩?dòng)實(shí)現(xiàn)類型三的損失究竟是怎么得到的:
#手動(dòng)實(shí)現(xiàn)
shixian = -torch.mean(one_hot_label * torch.log(prob_softmax) + (1-one_hot_label) * torch.log(1-prob_softmax))
print(shixian)
可以看出來(lái),F(xiàn).binary_cross_entropy()與torch.nn.BCELoss()是將網(wǎng)絡(luò)的每個(gè)節(jié)點(diǎn)看作是一個(gè)二分類的節(jié)點(diǎn)來(lái)計(jì)算交叉熵?fù)p失的。
進(jìn)一步來(lái)討論下類型二和類型三的一致性,代碼如下。由于類型二中函數(shù)自動(dòng)將logit通過(guò)sigloid函數(shù)映射為概率,為了檢驗(yàn)一致性性,我門也需要通過(guò)sigmoid計(jì)算類型三所需要的概率。
最后可以看到下面的輸出均為0.6378
sigmoid = nn.Sigmoid()
prob_sig = sigmoid(logits) ?#計(jì)算概率
?
##類型二
##F.binary_cross_entropy_with_logits
loss5 = F.binary_cross_entropy_with_logits(logits, one_hot_label)
print(loss5)
?
##torch.nn.BCEWithLogitsLoss()
BCEWithLogitsLoss = torch.nn.BCEWithLogitsLoss()
loss6 = BCEWithLogitsLoss(logits, one_hot_label)
print(loss6)
?
##類型三
##F.binary_cross_entropy
loss7 = F.binary_cross_entropy(prob_sig, one_hot_label) #輸入概率和one-hot
print(loss7)
?
## torch.nn.BCELoss()
adversarial_loss = torch.nn.BCELoss()
loss8 = adversarial_loss(prob_sig, one_hot_label)
print(loss8)
?
#手動(dòng)實(shí)現(xiàn)
shixian = -torch.mean(one_hot_label * torch.log(prob_sig) + (1-one_hot_label) * torch.log(1-prob_sig))
print(shixian)
3. GAN中的實(shí)現(xiàn):二分類
GAN中的判別器出的損失就是典型的最小化二分類的交叉熵?fù)p失。但是在實(shí)現(xiàn)上,與二分類網(wǎng)絡(luò)不同。
- 一般的二分類網(wǎng)絡(luò),輸出有兩個(gè)節(jié)點(diǎn),分別表示real和fake的logit(或者概率)。
- GAN的判別器,輸出只有一個(gè)節(jié)點(diǎn),表示的是樣本屬于real的logit(或者概率)。
正因?yàn)榕袆e器的輸出是一維,類型一的兩個(gè)函數(shù)F.cross_entropy()與torch.nn.CrossEntropyLoss()是沒有辦法使用的,因?yàn)檫@兩個(gè)函數(shù)要求輸入是二維的,即分別在real和fake的logit。因此只能采用類型二或者類型三的函數(shù)。
很多GAN網(wǎng)絡(luò)采用的二分類交叉熵?fù)p失函數(shù)如下:
#類型二:
adversarial_loss_2 = torch.nn.BCEWithLogitsLoss(logit,y)
#類型三:
adversarial_loss_3 = torch.nn.BCELoss(p,y)
前面我們講到,類型二和類型三的函數(shù)都是將每一個(gè)節(jié)點(diǎn)視為一個(gè)二分類的節(jié)點(diǎn),因此對(duì)于每一個(gè)給節(jié)點(diǎn),其具體的表達(dá)式可以寫為:
#類型二:
torch.nn.BCEWithLogitsLoss(logit,y) = - (ylog(sigmoid(logit)) + (1-y)log(1-sigmoid(logit)))
# 其中l(wèi)ogit表示判斷為real的logit
# y=1表示real
# y=0表示fake
?
#類型三:
torch.nn.BCELoss(p, y) = - (ylog(p) + (1-y)log(1-p))
# 其中p表示判斷為real的概率
# y=1表示real
# y=0表示fake
3.1 判別器損失計(jì)算
判別器輸出維度為1,輸出logit,有兩個(gè)樣本,都為fake圖像
logits = np.array([1.2, -0.5])
logits = torch.from_numpy(logits).float()
sigmoid = nn.Sigmoid()
prob_sig = sigmoid(logits) ?#計(jì)算概率
?
label = torch.tensor([1, 1]).float()
?
#類型二:
adversarial_loss_2 = torch.nn.BCEWithLogitsLoss()
loss_2 = adversarial_loss_2(logits, 1-label) ?#因?yàn)槭莊ake,需要將y設(shè)置為0
print(loss_2)
?
#類型三:
adversarial_loss_3 = torch.nn.BCELoss()
loss_3 = adversarial_loss_3(prob_sig, 1-label) #因?yàn)槭莊ake,需要將y設(shè)置為0
print(loss_3)
#輸出均為0.9687
?通過(guò)上述代碼可以分析如下:
(1)當(dāng)樣本為fake時(shí),網(wǎng)絡(luò)輸出其為real的logit:
- 對(duì)于類型二:torch.nn.BCEWithLogitsLoss(logit,0),即直接輸入logit。由于樣本的實(shí)際類別為fake,根據(jù)交叉熵?fù)p失公式,要將為y設(shè)置為0,相當(dāng)于告訴函數(shù)我輸入的樣本是fake。
- 對(duì)于類型三:torch.nn.BCELoss(prob, 0),此時(shí)prob等于公式中的p,由于樣本的實(shí)際類別為fake,與類型二一致,要將為y設(shè)置為0。
(2)樣本為real,網(wǎng)絡(luò)輸出其為real的logit:
- 對(duì)于類型二:torch.nn.BCEWithLogitsLoss(logit,1),即直接輸入logit。由于樣本的實(shí)際類別也為real,根據(jù)交叉熵?fù)p失公式,要將為y設(shè)置為1,這樣就計(jì)算了 ylog(sigmoid(logit))
- 對(duì)于類型三:torch.nn.BCELoss(prob, 1),此時(shí)prob等于公式中的p,樣本的實(shí)際類別也為real,與類型二一致,要將為y設(shè)置為1,這樣就計(jì)算了 ylog(p)
GAN網(wǎng)絡(luò)在更新判別器時(shí),代碼一般如下:
criterion = torch.nn.BCELoss()
real_out = D(real_img) ?# 將真實(shí)圖片放入判別器中
d_loss_real = criterion(real_out, 1) ?# 真實(shí)樣本的損失
?
fake_img = G(z) ?# 隨機(jī)噪聲放入生成網(wǎng)絡(luò)中,生成一張假的圖片
fake_out = D(fake_img) ?# 判別器判斷假的圖片,
d_loss_fake = criterion(fake_out, 0) ?# 生成樣本的損失
?
d_loss = d_loss_real + d_loss_fake ?# ?兩個(gè)相加 就是標(biāo)準(zhǔn)的交叉熵?fù)p失
?
optimizer_D.zero_grad()
d_loss.backward()
optimizer_D.step()
3.2 生成器的損失計(jì)算
前面判別器處的損失是最小化交叉熵?fù)p失:
min - (ylog(p) + (1-y)log(1-p))
那么生成器與之相反就是最大化交叉熵?fù)p失:
max - (ylog(p) + (1-y)log(1-p))
因?yàn)檎鎸?shí)樣本于與生成器無(wú)關(guān),因此可以轉(zhuǎn)變?yōu)閙in log(1-p)
max - ((1-y)log(1-p)) = min (1-y)log(1-p) = min log(1-p)
上述形式為飽和形式,轉(zhuǎn)變?yōu)榉秋柡腿缦隆?/p>
min -log(p)
可以看到上式子在形式上就是將fake圖像當(dāng)作real圖像進(jìn)行優(yōu)化。
可以這么理解:生成器的作用的就是盡可能生成逼近與real的fake,由于判別器判斷的結(jié)果p就是表示圖像為real的概率,那么生成器就希望p越高越好。而在訓(xùn)練判別器時(shí),判別器對(duì)real的優(yōu)化就是讓其p越高越好,即盡可能的區(qū)分real和fake。
因此在更新生成器時(shí),fake處的損失與更新判別器在real處的損失在邏輯上是一致的。
criterion = torch.nn.BCELoss()
fake_img = G(z) ?# 隨機(jī)噪聲放入生成網(wǎng)絡(luò)中,生成一張假的圖片
fake_out = D(fake_img) ?# 判別器判斷假的圖片,
G_loss = criterion(fake_out, 1) ?# 假樣本的損失
?
?
optimizer_G.zero_grad()
G_loss .backward()
optimizer_G.step()
3.3 小結(jié)
在GAN網(wǎng)絡(luò)中,由于輸出網(wǎng)絡(luò)只有一個(gè)節(jié)點(diǎn),表示圖像屬于real的logit或者prob,因此一般使用類型二和類型三的損失函數(shù)。
兩類函數(shù)的實(shí)現(xiàn)如下:
torch.nn.BCEWithLogitsLoss(logit,y) = - (ylog(sigmoid(logit)) + (1-y)log(1-sigmoid(logit)))
torch.nn.BCELoss(p, y) = - (ylog(prob) + (1-y)log(1-prob))
因?yàn)樯鲜鰧?shí)現(xiàn):
- 在更新判別器時(shí):real圖像后面label為1,fake圖像后面label為0。分別計(jì)算real和fake的損失相加。
- 在更新判別器時(shí):與real圖像無(wú)關(guān),fake圖像后面label為1,更新。
總結(jié)
原文鏈接:https://blog.csdn.net/Mr_health/article/details/122865070
相關(guān)推薦
- 2022-09-13 c++實(shí)現(xiàn)排序算法之希爾排序方式_C 語(yǔ)言
- 2022-09-08 Go語(yǔ)言通道之無(wú)緩沖通道_Golang
- 2021-12-11 Docker容器編譯LNMP的實(shí)現(xiàn)示例_docker
- 2022-07-06 python?pandas中的agg函數(shù)用法_python
- 2022-03-30 Android中圖片占用內(nèi)存的深入分析_Android
- 2022-08-16 R語(yǔ)言繪制維恩圖ggvenn示例詳解_R語(yǔ)言
- 2023-03-30 Regex正則表達(dá)式判斷密碼強(qiáng)度_正則表達(dá)式
- 2022-08-13 微信公眾號(hào)--根據(jù)用戶的opneId發(fā)送模版消息
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支