?使用nn.BCEWithLogitsLoss()
#pred和label都是2d的情况,行数表示有几个样本
#第1列是预测为标签0的分数,第2列是预测为标签1的分数,第3列是预测为标签2的概率,有3种标签
# 下面为nn.BCEWithLogitsLoss()的输入概率,和正确标签(float类型)的格式(输入概率和正确标签的shape相同,2d情况)
pred_1 = torch.tensor([[-0.2,0.6,0.4],
[0.2,0.1,0.5],
[0.3,0.8,0.9]])
label_1 = torch.tensor([[1,0,1], #表示第一个样本既属于标签0也属于标签2
[1,0,0], #表示第二个样本仅仅属于标签0
[0,1,1]]) #表示第三个样本既属于标签1也属于标签2
print('nn.BCEWithLogitsLoss())(pred,label) = ',nn.BCEWithLogitsLoss()(pred_1,label_1.float())) #tensor(0.6924)
print('nn.BCEWithLogitsLoss()(pred,label) = nn.BCELoss()(torch.sigmoid(pred),label)=',nn.BCELoss()(torch.sigmoid(pred_1),label_1.float()))
print('下面分3个步骤计算')
print('step 1,使用sigmoid归一化预测概率pred')
pred_1_sigmoid = torch.sigmoid(pred_1) #;print(pred_1_sigmoid)
# tensor([[0.4502, 0.6457, 0.5987],
# [0.5498, 0.5250, 0.6225],
# [0.5744, 0.6900, 0.7109]])
print('step 2,分别计算每个样本的损失')
#计算第一个样本的损失,第一个样本的标签为 (1,0,1)
sample_1_loss = -1*(1*torch.log(torch.tensor(0.4502)) + 0*torch.log(1-torch.tensor(0.4502)) +
0*torch.log(torch.tensor(0.6457)) + 1*torch.log(1-torch.tensor(0.6457)) +
1*torch.log(torch.tensor(0.5987)) +0*torch.log(1-torch.tensor(0.5987)))/3
print('计算第一个样本的损失:',sample_1_loss) #tensor(0.7829)
#计算第二个样本的损失,第一个样本的标签为 (1,0,0)
sample_2_loss = -1*(1*torch.log(torch.tensor(0.5498)) + 0*torch.log(1-torch.tensor(0.5498)) +
0*torch.log(torch.tensor(0.5250)) + 1*torch.log(1-torch.tensor(0.5250)) +
0*torch.log(torch.tensor(0.6225)) +1*torch.log(1-torch.tensor(0.6225)))/3
print('计算第二个样本的损失:',sample_2_loss) #tensor(0.7723)
#计算第仨个样本的损失,第一个样本的标签为 (0,1,1)
sample_3_loss = -1*(0*torch.log(torch.tensor(0.5744)) + 1*torch.log(1-torch.tensor(0.5744)) +
1*torch.log(torch.tensor(0.6900)) + 0*torch.log(1-torch.tensor(0.6900)) +
1*torch.log(torch.tensor(0.7109)) +0*torch.log(1-torch.tensor(0.7109)))/3
print('计算第三个样本的损失:',sample_3_loss) #tensor(0.5222)
#三个样本平均损失
print('step 3,计算三个样本的平均损失:',(sample_1_loss+sample_2_loss+sample_3_loss)/3) #tensor(0.6924)
结果
nn.BCEWithLogitsLoss())(pred,label) = tensor(0.6924)
nn.BCEWithLogitsLoss()(pred,label) = nn.BCELoss()(torch.sigmoid(pred),label)= tensor(0.6924)
下面分3个步骤计算
step 1,使用sigmoid归一化预测概率pred
step 2,分别计算每个样本的损失
计算第一个样本的损失: tensor(0.7829)
计算第二个样本的损失: tensor(0.7723)
计算第三个样本的损失: tensor(0.5222)
step 3,计算三个样本的平均损失: tensor(0.6924)
使用nn.CrossEntropyLoss()
#下面为nn.CrossEntropyLoss()的输入概率,和正确标签的格式(输入概率必须是2d,正确标签为1d,为每个样本正确类别的索引)
pred_2 = torch.tensor([[-0.2,0.6,0.4],
[0.2,0.1,0.5],
[0.3,0.8,0.3]])
#所有样本正确概率的ont_hot形式是下面的格式
# label_2 = torch.tensor([[0,0,1], #必须是ont—hot形式,每个样本仅能属于一个类别
# [0,1,0],
# [0,0,1]])
# 但是nn.CrossEntropyLoss()类的输入标签是下面1d的格式
label_2 = torch.tensor([2,1,2]) #表示第0个样本索引为2的元素对应正确标签3的概率,第1个样本索引为1的元素对应正确标签1的概率
print('nn.CrossEntropyLoss()(pred_2,label_2)=',nn.CrossEntropyLoss()(pred_2,label_2))
print('分步骤计算')
print('step 1,使用softmax归一化预测概率')
pred_softmax = torch.softmax(pred_2,dim=1)
# print(pred_softmax)
# tensor([[0.1981, 0.4409, 0.3610],
# [0.3072, 0.2780, 0.4147],
# [0.2741, 0.4519, 0.2741]])
print('step 2,求每个样本的损失')
sample_1_loss = -1*torch.log(pred_softmax[0,2]) ;print('第一个样本的损失',sample_1_loss) #tensor(1.0189)
sample_2_loss = -1*torch.log(pred_softmax[1,1]) ;print('第二个样本的损失',sample_2_loss) #tensor(1.2801)
sample_3_loss = -1*torch.log(pred_softmax[2,2]) ;print('第三个样本的损失',sample_3_loss) #tensor(1.2944)
print('step 3,所有样本的平均损失',(sample_1_loss+sample_2_loss+sample_3_loss)/3) #tensor(1.1978)
结果
nn.CrossEntropyLoss()(pred_2,label_2)= tensor(1.1978)
分步骤计算
step 1,使用softmax归一化预测概率
step 2,求每个样本的损失
第一个样本的损失 tensor(1.0189)
第二个样本的损失 tensor(1.2801)
第三个样本的损失 tensor(1.2944)
step 3,所有样本的平均损失 tensor(1.1978)
# 下面为nn.BCEWithLogitsLoss()的输入概率,和正确标签的格式为1d的情况)
# 下面为nn.BCEWithLogitsLoss()的输入概率,和正确标签的格式为1d的情况)
#即只有一个样本
pred_3 = torch.tensor([-0.2,0.6,0.4,0.5])
label_3 = torch.tensor([0,0,1,1]) #表示该样本既属于标签2也属于标签3
print(nn.BCEWithLogitsLoss()(pred_3,label_3.float()))
pred_3_sigmoid = torch.sigmoid(pred_3) ;print(pred_3_sigmoid)
# tensor([0.4502, 0.6457, 0.5987, 0.6225])
sample_loss =-1*(
0*torch.log(pred_3_sigmoid[0]) + 1*torch.log(1-pred_3_sigmoid[0]) +
0*torch.log(pred_3_sigmoid[1]) + 1*torch.log(1-pred_3_sigmoid[1]) +
1*torch.log(pred_3_sigmoid[2]) + 0*torch.log(1-pred_3_sigmoid[2]) +
1*torch.log(pred_3_sigmoid[3]) + 0*torch.log(1-pred_3_sigmoid[3])
)/4 #一个样本,4个类别,计算每个样本的损失除以类别的个数
print(sample_loss)
结果
tensor(0.6557)
tensor([0.4502, 0.6457, 0.5987, 0.6225])
tensor(0.6557)
总结:nn.BCEWithLogitsLoss()(pred,label)? label为float形式,pred和label同shape
自带归一化函数为sigmoid
nn.CrossEntropyLoss()(pred,label)? label为int形式,label为1dshape
自带归一化函数为softmax
番外篇
nn.BCEWithLogitsLoss(pred,label) = nn.BCELoss()(torch.sigmoid(pred),label)
当使用nn.BCELoss()(torch.softmax(pred,dim=1),label)时,并且标签为one_hot形式的2d标签,等同于标签为1d形式的nn.CrossEntroyLoss()(pred,label)
当nn.CrossEntroyLoss()分步骤计算使用sigmoid而不是softmax,有损失网络不会收敛,分类精度始终为50%左右
联系和区别:对一个样本的损失而言,nn.BCEWithLogitsLoss计算时sigmoid函数得到的归一化概率使得各个类别的概率没有产生关系,所以然后计算损失时,会计算所有类别产生的损失求平均,使得各个类别的概率强行产生联系,得到该样本的损失
对一个样本的损失而言,nn.CrossEntroyLoss()计算时softmax函数计算的归一化概率,就是各个类别的分数联合作用产生的归一化概率,即各个类别之间已经产生了联系,所以然后,会直接用这个正确索引对应的概率取负对数,得到该样本的损失
两种损失,nn.BCEWithLogitsLoss在得到归一化概率后,所有类别概率产生联系
nn.CrossEntroyLoss()在得到归一化概率前,所有类别分数产生联系
一前一后,都是为了使类别间产生联系的
|