【PyTorch深度学习实践】-- 多分类问题

学习视频:B站 刘二大人《PyTorch深度学习实践》完结合集

八、多分类问题(Softmax Classifier)

多分类问题实际上求解的是随机事件的分布:

如果有10个输出:

将其转换为二分类问题,在这种情况下,类别之间所存在的互相抑制的关系没有办法体现,当一个类别出现的概率较高时,其他类别出现的概率仍然有可能很高

解决方案应具有以下要求:

  • 每个分类的出现概率大于等于0
  • 各个分类出现概率之和为1

image-20230227194036318

在最后一层使用softmax层,之前的层使用sigmoid层

Softmax Layer

  • 把线性层的输出都变为大于等于零
  • 分类的输出值的和为1

softmax层函数为:

image-20230227194255205

举例:

image-20230227194458129

上述就是先进行指数运算,然后再对结果进行归一化处理

损失函数

交叉熵的计算公式为:
image-20230227203050385

再多分类问题中,该公式可扩展为:

image-20230227203115527

其中m表示类别数量,n表示样本数量,P(Xij)表示预测样本i的结果与实际结果j相同取1,反之取0;Q(Xij)表示对于观测样本i预测值为j的概率

由于上述计算过程中P(Xij)非0即1,且有且只能有一个1,因此一个样本所有分类的loss计算过程可以简化为:

image-20230227203250813

其中,X表示事件预测值与实际值相同,Y表示非0即1的指示变量,Y^表示SoftMax的输出。
此时Y其实是作为独热编码(One-hot)输入的,以对离散的变量进行分类,即只在实际值处为1,其他均为0。

image-20230227194713545

代码为:

import numpy as np
 
y = np.array([1, 0, 0])
z = np.array([0.2, 0.1, -0.1])
 
y_pred = np.exp(z) / np.exp(z).sum()
 
loss = (-y*np.log(y_pred)).sum()
 
print(loss)

image-20230227194855253

Pytorch实现:

image-20230227194916024

import torch
#需要时LongTensor
y = torch.LongTensor([0])
z = torch.Tensor([[0.2,0.1,-0.1]])
criterion = torch.nn.CrossEntropyLoss()
loss = criterion(z,y)
print(loss)

MNIST问题

MINIST数据集中每个数字都是一个28∗28=784大小的灰度图,将灰度图中的每个像素值映射到(0,1)区间内,可以进行映射。

img

设计模型:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H5YKGBUC-1677719693756)(E:/Typora-user-images/202302272009970.png)]

代码实现

image-20230227195350528

准备数据:

image-20230227200144450

定义模型:

image-20230227200938709

损失函数和优化器:

image-20230227201350103

训练数据:

image-20230227201812031

测试:

image-20230227201822324

image-20230227202217917

代码实现:

import numpy as np
import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim
import matplotlib.pyplot as plt

#1.准备数据
batch_size = 64
transform = transforms.Compose([
    transforms.ToTensor(),  #把PIL图像变为pytorch中的tensor
    transforms.Normalize((0.1307,),(0.3081,)) #归一化,0.1301为均值,0.3081为标准差
])
train_dataset = datasets.MNIST(root='./mnist_data/',
                               train=True,
                               download=True,
                               transform=transform)
train_loader = DataLoader(train_dataset,shuffle=True,batch_size=batch_size)
test_dataset = datasets.MNIST(root='./mnist_data/',
                               train=False,
                               download=True,
                               transform=transform)
test_loader = DataLoader(train_dataset,shuffle=False,batch_size=batch_size)

#设计模型
class Net(torch.nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        self.l1 = torch.nn.Linear(784,512)
        self.l2 = torch.nn.Linear(512, 256)
        self.l3 = torch.nn.Linear(256,128)
        self.l4 = torch.nn.Linear(128,64)
        self.l5 = torch.nn.Linear(64,10)

    def forward(self,x):
        x = x.view(-1,784)
        x = F.relu(self.l1(x))
        x = F.relu(self.l2(x))
        x = F.relu(self.l3(x))
        x = F.relu(self.l4(x))
        return self.l5(x)
model = Net()
#损失函数、优化器
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(),lr=0.01,momentum=0.5)

#训练
def train(epoch):
    running_loss = 0.0
    for batch_idx,data in enumerate(train_loader,0):
        inputs,target = data
        optimizer.zero_grad()

        #forward+backward+update
        outputs = model(inputs)
        loss = criterion(outputs,target)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if batch_idx % 300 == 299:
            print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
            running_loss = 0.0
epoch_list = []
acc_list = []

#测试
def test():
    correct = 0
    total = 0
    # 避免计算梯度
    with torch.no_grad():
        for data in test_loader:
            images, labels = data
            outputs = model(images)
            # 取每一行(dim=1表第一个维度)最大值(max)的下标(predicted)及最大值(_)
            _, predicted = torch.max(outputs.data, dim=1)
            # 加上这一个批量的总数(batch_size),label的形式为[N,1]
            total += labels.size(0)
            correct += (predicted == labels).sum().item()

        acc_list.append(100 * correct / total)
        print('Accuracy on test set: %d %%' % (100 * correct / total))

if __name__ =='__main__':
    for epoch in range(10):
        train(epoch)
        epoch_list.append(epoch + 1)
        test()

#画图
plt.plot(epoch_list,acc_list)
plt.xlabel('epoch')
plt.ylabel('acc')
plt.grid()
plt.show()

运行结果:

image-20230227205327931

参考资料

https://blog.csdn.net/qq_43800119/article/details/126415767

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值