一、误差平方和SSE
回归类神经网络最常见损失函数SSE
全部样本的评价损失MSE
from torch.nn import MSELoss #导入类
yhat = torch.randn(size=(50,),dtype=torch.float32)
y = torch.randn(size=(50,),dtype=torch.float32)
criterion = MSELoss() #实例化一个类
loss = criterion(yhat,y)
loss #没有设置随机数种子,所以每次运行的数字都会不一致
#在MSELoss中有重要的参数,reduction
#当reduction = "mean" (默认也是mean),则输出MSE
#当reduction = "sum",则输出SSE
criterion = MSELoss(reduction = "mean") #实例化
criterion(yhat,y)
criterion = MSELoss(reduction = "sum")
criterion(yhat,y)
二、二分类交叉熵损失函数
1、Pytorch实现二分类交叉熵损失
#tensor实现二分类交叉熵损失
import torch
#Loss=-(y*ln(sigma)+(1-y)*ln(1-sigma))
#y - 真实标签
#sigma - sigmoid(z)
#z=Xw
#X,w 假设M个样本
m = 3*pow(10,3)
torch.random.manual_seed(99)
X = torch.rand((m,4),dtype=torch.float32)
w = torch.rand((4,1),dtype=torch.float32)
y = torch.randint(low=0,high=2,size=(m,1),dtype=torch.float32)
zhat = torch.mm(X,w) #矩阵相乘用torch.mm
sigma = torch.sigmoid(zhat)
sigma.shape
loss = -(1/m)*torch.sum(y*torch.log(sigma) + (1-y)*torch.log(1-sigma))
loss
2、调用类实现二分类交叉熵损失
nn模块中的类
class BCEWithLogitsLoss
class BCELoss
BCEWithLogitsLoss内置了sigmoid函数与交叉熵函数,它会自动计算输入值的sigmoid值,因此需要输入zhat与真实标签,且顺序不能变化,zhat必须在前。
BCELoss中只有交叉熵函数,没有sigmoid层,因此需要输入sigma与真实标签,且顺序不能变化。
同时,这两个函数都要求预测值与真实标签的数据类型以及结构(shape)必须相同,否则运行就会报错。
import torch.nn as nn
criterion = nn.BCELoss(reduction="mean") #实例化
loss = criterion(sigma,y)
loss
#当你有较高的精度要求,使用如下
criterion = nn.BCEWithLogitsLoss(reduction="sum")
loss = criterion(zhat,y)
loss
三、多分类交叉熵损失函数
1、Pytorch实现多分类交叉熵损失
import torch
import torch.nn as nn
m = 3*pow(10,3)
torch.random.manual_seed(99)
X = torch.rand((m,4),dtype=torch.float32)
w = torch.rand((4,3),dtype=torch.float32)
y = torch.randint(low=0,high=3,size=(m,),dtype=torch.float32)
zhat = torch.mm(X,w)
#sigma = torch.softmax(zat)
#Logsoftmax - long + softmax,输入为zhat
#NLLLoss
logsm = nn.LogSoftmax(dim=1) #实例化完成
logsm
logsigma = logsm(zhat)
logsigma
criterion = nn.NLLLoss()
criterion(logsigma,y.long())
2、调用类实现多分类交叉熵损失
criterion = nn.CrossEntropyLoss()#(reduction = "mean"/"sum"/"None")
criterion(zhat,y.long())
运行结果相同:
无论时二分类还是多分类,PyTorch都提供了包含输出层激活函数和不包含输出层激活函数的类两种选择。在实际神经网络建模中,类可以被放入定义好的Model类中去构建神经网络的结构,因此是否包含激活函数,就需要由用户来自行选择。
重视展示网络结构和灵活性,应该使用不包含输出层激活函数的类
通常在Model类中,__init__中层的数量与forward函数中对应的激活函数的数量是一致的,如果我们使用内置sigmoid/logsoftmax功能的类来计算损失函数,forward函数在定义时就会少一层(输出层),网络结构展示就不够简单明了,对于结构复杂的网络而言,结构清晰就更为重要。同时,如果激活函数是单独写的,要修改激活函数就变得很容易,如果混在损失函数中,要修改激活函数时就得改掉整个损失函数的代码,不利于维护。
重视稳定性和运算精度,使用包含输出层激活函数的类
如果在一个Model中,很长时间我们都不会修改输出层的激活函数,并且模型的稳定运行更为要紧,我们就使用内置了激活函数的类来计算损失函数。同时,就像之前提到的,内置激活函数可以帮助我们推升运算的精度。