直观比喻:
因此,损失函数的主要作用:
1.计算实际输出和目标之间的差距
2.为我们更新输出提供一定的依据(反向传播)
常见的几种Loss Functions:
-
nn.L1Loss
官方文档公式如下:
其中,
Shape:
Input: (∗)(∗), where ∗∗ means any number of dimensions.
Target: (∗)(∗), same shape as the input.
Output: scalar. If
reduction
is'none'
, then (∗)(∗), same shape as the input.
代码示例:
import torch
from torch.nn import L1Loss, MSELoss, CrossEntropyLoss
inputs=torch.tensor([1,2,3],dtype=torch.float32)
targets=torch.tensor([1,2,5],dtype=torch.float32)
#
loss = L1Loss()
result=loss(inputs,targets)
loss1= L1Loss(reduction="sum")
result1=loss1(inputs,targets)
print(result) #tensor(0.6667) (0+0+2)/3=0.6667
print(result1) #tensor(2.) 0+0+2
2.nn.MSELoss(平方差)
官方文档:
Shape:
Input: (∗)(∗), where ∗∗ means any number of dimensions.
Target: (∗)(∗), same shape as the input.
代码示例:
import torch
from torch.nn import L1Loss, MSELoss, CrossEntropyLoss
inputs=torch.tensor([1,2,3],dtype=torch.float32)
targets=torch.tensor([1,2,5],dtype=torch.float32)
#均方差
loss_mse=MSELoss()
result=loss_mse(inputs,targets)
print(result) #tensor(1.3333) MSE=(0*0+0*0+2*2)/3
3.nn.CrossEntropyLoss (交叉熵)
适用于训练一个具有C个类别的分类问题
计算公式并举例,便于理解:
示例代码:
import torch
from torch.nn import CrossEntropyLoss
#交叉熵损失函数
x=torch.tensor([0.1,0.2,0.3])
y=torch.tensor([1])
#input(N,C)or(C)...
x=torch.reshape(x,(1,3))
loss_cross=CrossEntropyLoss()
result=loss_cross(x,y)
print(result)
结果:tensor(1.1019)
之前博文中有创建了CIFAR10 network structure,下面代码直接调用过来,并下载CIFAR10的测试集(10000张),利用上面所学的交叉熵函数计算实际输出与目标之间的误差,代码如下
import torch
import torchvision
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
datasets=torchvision.datasets.CIFAR10("./datasets",train=False,transform=transforms.ToTensor(),download=True)
dataloader=DataLoader(datasets,batch_size=1)
class Tudui(nn.Module):
def __init__(self):
super(Tudui,self).__init__()
self.model1=Sequential(
Conv2d(in_channels=3,out_channels=32,kernel_size=5,padding=2),
MaxPool2d(kernel_size=2),
Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding=2),
MaxPool2d(kernel_size=2),
Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding=2),
MaxPool2d(kernel_size=2),
Flatten(),
Linear(in_features=1024, out_features=64),
Linear(in_features=64, out_features=10)
)
def forward(self,x):
# x=self.conv1(x)
# # x=self.maxpool1(x)
# # x=self.conv2(x)
# # x=self.maxpool2(x)
# # x=self.conv3(x)
# # x=self.maxpool3(x)
# # x=self.flatten(x)
# # x=self.linear1(x)
# # x=self.linear2(x)
x=self.model1(x) #简化代码
return x
tudui=Tudui()
loss=nn.CrossEntropyLoss()
for data in dataloader:
imgs,targets = data
outputs = tudui(imgs)
# print(outputs)
# print(targets)
"""
tensor([[ 0.0837, -0.0653, -0.0284, 0.1285, 0.0409, 0.0547, 0.1032, 0.1266,
-0.0809, -0.1192]], grad_fn=<AddmmBackward>) 10个输出,每个数字代表预测该类别的概率
tensor([3]) 代表真实的target是3
"""
# 求交叉熵
result_loss = loss(outputs, targets)
print(result_loss) # 神经网络输出与真实输出之间的误差
误差部分结果如下:
为什么说损失函数能为我们更新输出提供一定的依据 ?
因为它能给我们神经网络中每一个需要调节的参数,对卷积层来说,其中的每一个卷积核中的参数,为每一个卷积核参数设置了一个grad(梯度),当使用反向传输时,每一个节点都有一个梯度,优化的时候根据梯度对参数优化,最终使loss下降,就是所谓的梯度下降法。
在上面代码下面加上两行代码:
result_loss.backward() #反向传输,注意是result_loss,不是loss
print("ok") #为了debug
在代码result_loss.backward()所在行添加断点,debug一下,找到conv1下梯度,此时还未计算梯度,因为没有执行result_loss.backward()这行代码
点击 按钮,发现grad有计算值了,说明为每一个卷积层参数设置了一个grad(梯度)