PYTORCH学习记录_交叉熵代价函数(分类模型)

交叉熵的原理

为什么使用交叉熵

当我们使用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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值