PYTORCH学习记录

it2023-11-06  78

交叉熵

交叉熵的原理为什么使用交叉熵引出交叉熵 交叉熵的实际使用

交叉熵的原理

为什么使用交叉熵

当我们使用sigmoid函数作为激活函数,计算损失值时所用到的函数是二次代价函数(真实值减去与测试的平方),调整权值时的快慢与激活函数的导数有关. 当损失值较大的时候,应该调整的快一些, 当损失值较小的时候,可以调整的慢一些. 但是,使用二次代价函数,并不能实现这个功能.

引出交叉熵

因此改变计算损失值的代价函数改为交叉熵代价函数 t表示实际的值 y表示预测值 z = ω x z = \omega x z=ωx

E = − ( ln ⁡ y + ( 1 − t ) ln ⁡ ( 1 − y ) ) E = -(\ln y+(1-t)\ln (1-y)) E=(lny+(1t)ln(1y)) y = f ( z ) y = f(z) y=f(z) 对于sigmoid函数 f ( z ) ′ = f ( z ) ( 1 − f ( z ) ) f(z)' = f(z)(1-f(z)) f(z)=f(z)(1f(z)) 对E求对应的导数: ∂ E ∂ ω = − ( y f ( z ) − 1 − t 1 − f ( z ) ) ∂ f ∂ ω = x ( f ( z ) − t ) \frac{\partial E}{\partial \omega}=-(\frac{\mathrm y}{\mathrm f(z)}-\frac{1-t}{1-f(z)})\frac{\partial f}{\partial \omega}=x(f(z)-t) ωE=(f(z)y1f(z)1t)ωf=x(f(z)t)

通过观察上述求导式可知,权值改变的大小与 ( f ( z ) − t ) (f(z)-t) (f(z)t) ( y − t ) (y-t) (yt)有关, 因此当误差较大时,权值改变的速度会变快,误差较小时,权值更改速度变慢.

交叉熵的实际使用

代码如下:

import numpy as np from torch import nn, optim from torch.autograd import Variable import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader # 载入数据集 # 训练集 train_data = datasets.MNIST(root='./', train=True, # 表示载入训练集数据 transform=transforms.ToTensor(), # 将数据转换为Tensor的格式 download=True) # 将数据进行下载 test_data = datasets.MNIST(root='./', train=False, transform=transforms.ToTensor(), download=True) # 设置批次大小,每次训练传入的数据量 batch_size = 64 # 定义训练集的数据生成器 train_loader = DataLoader(dataset=train_data, batch_size=batch_size, # 每次生成64个数据 shuffle=True) # 生成之前将数据打乱 # 定义测试集的数据生成器 test_loader = DataLoader(dataset=test_data, batch_size=batch_size, shuffle=True) # 遍历 for i, data in enumerate(train_loader): inputs, labels = data # 数据带有输入和标签两个量 print(inputs.shape) # torch.Size([64, 1, 28, 28]),1表示通道数,彩色图片表示3,后面是图片大小 print(labels.shape) # 对应的是数字 break print(len(train_loader)) # 一共938个批次 # 定义网络结构 class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.fcl = nn.Linear(784, 10) self.softmax = nn.Softmax(dim=1) # dim=1表示转换维度为1,{64,10},将输出值转换为概率,就是将输出10个数据转换为对应的概率 def forward(self,x): #数据输入是4维数据,[64, 1, 28, 28]->[64,784] x = x.view(x.size()[0],-1)#获得值64,view相当于reshape,第一个值为64,第二个值为-1相当于自动匹配 x = self.fcl(x) x = self.softmax(x) return x #d定义模型: LR=0.5 model = Net() #定义代价函数 ce_loss = nn.CrossEntropyLoss() #定义优化器 optimizer = optim.SGD(model.parameters(),LR) #定义训练模型 def train(): for i,data in enumerate(train_loader): inputs,labels = data#获得一个批次的数据和标签 #模型预测结果 out = model(inputs)#(64,10) #交叉熵代价函数out(batch,C),labels(batch) #C表示类别的数量,就是10 #使用交叉熵之后不需要用到独热编码,已经封装好了 # #to onehot数据标签变成独热编码,(64)->(64,1) # labels = labels.reshape(-1,1) # #1表示对哪个维度进行独热编码 # #labels:将zeros中对应位置变成1 # #1对应位置需要改变的数 # one_hot = torch.zeros(inputs.shape[0],10).scatter(1,labels,1)#一行表示一个解 #计算loss,mse_loss的两个shape要相同 loss = ce_loss(out,labels) #梯度清零 optimizer.zero_grad() #计算梯度 loss.backward() #修改权值 optimizer.step() def test(): correct = 0 for i, data in enumerate(test_loader): inputs,labels = data out = model(inputs) #获得最大值以及最大值所在位置 _,predicted = torch.max(out,1)#1表示维度为1的位置->10 #用计算值与labels进行类比 correct +=(predicted==labels).sum() print("Test acc:{0}".format(correct.item()/len(test_data))) for epoch in range(10): print("epoch:",epoch) train() test()

下图是使用mse代价函数计算损失值,前几次迭代的准确率:

下图是使用交叉熵代价函数计算损失值,前几次迭代的准确率: 通过对比可知,使用交叉熵代价函数,能够使结果收敛速度更快.

最新回复(0)