P22_损失函数与反向传播
22.1损失函数的作用
- 计算实际输出和目标之间的差距
- 为我们更新输出提供一定的依据(反向传播)
22.2几种官方文档中的损失函数
打开torch.nn—Loss Functions:
【注意:损失函数只能处理float类型的张量,可在张量设置时加入dtype=torch.float或者张量中出现小数点】
1.L1Loss:
(1)其参数如下:
class torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')
其中reduction默认是mean,也可以设置为sum
(2)举个例子
输入X:1,2,3
对应的目标Y:1,2,5
则
mean:L1loss = (0+0+2)/3 = 0.6667
sum:LL1loss = 0+0+2 = 2
(3)将上例写入代码
点击查看代码
import torch
from torch.nn import L1Loss
#损失函数只能处理float类型的张量
inputs = torch.tensor([1,2,3],dtype=torch.float32)
targets = torch.tensor([1,2,5],dtype=torch.float32)
#将inputs和targets变成1batch_size、1channel,1行3列
inputs = torch.reshape(inputs,(1,1,1,3))
targets = torch.reshape(targets,(1,1,1,3))
loss = L1Loss()
result = loss(inputs,targets)
print(result)
(4)输出:
tensor(0.6667)
(5)设置reduction为sum
loss = L1Loss(reduction='sum')
输出为:
tensor(2.)
2.MSELoss(平方差):
(1)举个例子
输入X:1,2,3
对应的目标Y:1,2,5
则MSE=(0+0+2^2)/3 = 4/3 = 1.333
(2)写入代码:
点击查看代码
import torch
from torch.nn import L1Loss, MSELoss
from torch import nn
#损失函数只能处理float类型的张量
inputs = torch.tensor([1,2,3],dtype=torch.float32)
targets = torch.tensor([1,2,5],dtype=torch.float32)
#将inputs和targets变成1batch_size、1channel,1行3列
inputs = torch.reshape(inputs,(1,1,1,3))
targets = torch.reshape(targets,(1,1,1,3))
loss_mse = MSELoss()
result_mse = loss_mse(inputs,targets)
print(result_mse)
(3)输出:
tensor(1.3333)
3.CrossEntropyLoss(交叉熵):
(1)交叉熵计算公式
想要loss小,就要使x[class]大(其前有负号)以及log的部分小;
假设要分成三类:person、dog、cat,现在给他们分别赋上标签:0,1,2
设person假如经过神经网络的输出output为[0.1,0.2,0.3],target是1(狗的标签是1);
此时,代入到计算公式里面,output就是x,target就是class:

则计算结果为:loss(x,class) = -0.2 + log(exp(0.1)+exp(0.2)+exp(0.3)),计算机里面log默认是以e为底,即loss(x,class) = -0.2 + ln(exp(0.1)+exp(0.2)+exp(0.3)),得到1.1019

(2)CrossEntropyLoss的shape要求
Input:(N,C),C是类别数,N是batch_size
Target:N
Output:scalar
(3)写入代码:
点击查看代码
x = torch.tensor([0.1,0.2,0.3])
y = torch.tensor([1])
#按照Input的shape要求,把Input:(N,C),C是类别数,N是batch_size
#即分成三类:person,cat,dog;batch_size为一个
x = torch.reshape(x,(1,3))
#新建交叉熵
loss_cross = nn.CrossEntropyLoss()
result_cross = loss_cross(x,y)
print(result_cross)
22.3在神经网络中使用Loss Function:
1.将CIFAR10的数据集放到神经网络
点击查看代码
import torchvision.transforms
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
#定义数据集
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10("./dataset",train=False,
transform=torchvision.transforms.ToTensor(),download=True)
dataloader = DataLoader(dataset,batch_size=1)
#定义神经网络
class DYL_seq(nn.Module):
def __init__(self):
super(DYL_seq, self).__init__()
self.model1 = Sequential(
Conv2d(in_channels=3, out_channels=32, kernel_size=5, padding=2),
MaxPool2d(kernel_size=2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(kernel_size=2),
Conv2d(32, 64, 5, padding=2),
MaxPool2d(kernel_size=2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self,x):
x = self.model1(x)
return x
#创建网络
dyl_seq = DYL_seq()
#从dataloader去取数据
for data in dataloader:
imgs,targets = data
outputs = dyl_seq(imgs)
print(outputs)
print(targets)
2.输出:
点击查看代码
Files already downloaded and verified
tensor([[ 0.1075, -0.0205, -0.0137, -0.1302, 0.0355, -0.0131, 0.0246, -0.0382,
0.1338, 0.0322]], grad_fn=<AddmmBackward0>)
tensor([3])
tensor([[ 0.0851, 0.0023, 0.0055, -0.1246, 0.0670, -0.0242, 0.0132, -0.0222,
0.1512, 0.0251]], grad_fn=<AddmmBackward0>)
tensor([8])
......
输入的图片放在神经网络中得到一个输出:一共有10个输出,每个值代表预测是这个类别的概率
[ 0.1075, -0.0205, -0.0137, -0.1302, 0.0355, -0.0131, 0.0246, -0.0382,0.1338, 0.0322]
其对应的tensor([3])代表其真实类别是3;
3.使用Loss Function
(1)添加代码:
点击查看代码
loss = nn.CrossEntropyLoss()
#创建网络
dyl_seq = DYL_seq()
#从dataloader去取数据
for data in dataloader:
imgs,targets = data
outputs = dyl_seq(imgs)
result_loss = loss(outputs,targets)
#CrossEntropyLoss的计算公式中,x就是神经网络的输出outputs,class就是targets
print(result_loss)
(2)输出结果如下:
点击查看代码
Files already downloaded and verified
tensor(2.3312, grad_fn=<NllLossBackward0>)
tensor(2.1667, grad_fn=<NllLossBackward0>)
.......
我们得到的这些数:就是神经网络的输出和真实输出的误差
4.lossfunction的第二个作用:为我们更新输出提供一定的依据(反向传播)
(1)即grad
给每一个卷积核中的参数设置了一个grad梯度,当我们采用反向传播时,每一个要更新的参数就会求出对应多个梯度,在优化过程中,就会对其中参数进行一个优化
(2)代码如下
点击查看代码
x for data in dataloader: imgs,targets = data outputs = dyl_seq(imgs) result_loss = loss(outputs,targets) #CrossEntropyLoss的计算公式中,x就是神经网络的输出outputs,class就是targets result_loss.backward() #print(result_loss) print("ok")
(3)把断点打在: result_loss.backward(),然后debug
可见:dyl_seq的modules下边的‘model1’中的modules的第一层‘0’里面的weight下边的gard为None

(4)然后调试进入到下一步:
其gard梯度就计算出来了:

但是如果删掉了result_loss.backward,就会发现gard始终为none
所以:
要用backward去做反向传播,他就可以计算出每一个节点的参数,就得到各个节点的参数的梯度,接下里就可以选用合适的优化器,对其参数极限那优化,对loss达到降低的目的。
浙公网安备 33010602011771号