【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)

本文目录

  • 多分类问题:实际上求解的是随机事件的分布
    • 问题引入
    • 网络设计
  • Loss:
  • 课后练习1:交叉熵损失vsNLL损失
    • 解答:
  • MNIST问题:
    • 模型设计:
    • 实现代码:
  • 1. 准备数据
  • 转为格式为C*W*H值为0-1的Tensor transform = transforms.Compose([
    • 2. 模型设计 class Net(torch.nn.Module):
  • 3. 损失、优化器
  • 4. 训练和测试 def train(epoch):
    • 结果:
  • 课后练习2:kaggle商品分类
    • 实现代码:
    • 结果:
  • 学习资料
  • 系列文章索引

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

问题引入

前篇中,对糖尿病数据集的问题是一个二分类问题,但实际问题中,二分类问题较少,更多的是以MINIST、CIFAR为例的多分类问题。
【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第1张图片

网络设计

转换为二分类问题进行判断(eg:当输出为1时,对其他的非1输出都规定为0,以此来进行判断。)
【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第2张图片

但这种情况下,类别之间所存在的互相抑制的关系没有办法体现,当一个类别出现的概率较高时,其他类别出现的概率仍然有可能很高。
换言之,当计算输出为1的概率之后,再计算输出为2的概率时,并不是在输出为非1的条件下进行的,也就是说,所有输出的概率之和实际上是大于1的。
即对于一个多分类问题,其解决方案应该基于如下要求:

(1)每个分类的出现概率大于等于0
(2)各个分类出现概率之和为1
【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第3张图片

综上,多分类输出之间是需要有竞争性的。
改进网络:改最后的sigmod层为softmax层,来实现多分类问题的基本要求。
【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第4张图片

SoftMax层:假定Zl为最后一层线性层的输出,Zi为第i类的输出,则最终softmax层函数应为:
【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第5张图片

【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第6张图片

事实上,对于多分类问题输出,Softmax会先对所有输出进行指数运算,以满足(1)式要求,再对结果进行归一化处理,以满足(2)式要求。

Loss:

交叉熵的计算公式如下:
[图片]

在多分类问题中,该公式可扩展为:
[图片]

其中各个符号含义如下:
【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第7张图片

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

其中,X表示事件预测值与实际值相同,Y表示非0即1的指示变量,Y^表示SoftMax的输出。
此时Y其实是作为独热编码(One-hot)输入的,以对离散的变量进行分类,即只在实际值处为1,其他均为0。
【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第8张图片

代码:

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)

上述代码封装在CrossEntropyLoss()函数中
【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第9张图片

原代码可以重写成:

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)

课后练习1:交叉熵损失vsNLL损失

  • https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html#torch.nn.CrossEntropyLoss
  • https://pytorch.org/docs/stable/generated/torch.nn.NLLLoss.html#torch.nn.NLLLoss

【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第10张图片

解答:

https://blog.csdn.net/u010995990/article/details/109450959

  • NLLLoss全称是Negative Log Likelihood Loss,即最大似然函数。
  • CrossEntropyLoss就是交叉熵代价函数,就是把上面的我们执行的softmax+log+NLLLoss合并起来了,一步执行完。

请看下图:
【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第11张图片

读文档困难户选择在csdn学习

MNIST问题:

MINIST数据集中每个数字都是一个28∗28=784大小的灰度图,将灰度图中的每个像素值映射到(0,1)区间内,可以进行映射。
【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第12张图片

模型设计:

【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第13张图片

实现代码:

import torch
#组建DataLoader 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

1. 准备数据

#Dataset&Dataloader必备 batch_size = 64
#pillow(PIL)读的原图像格式为WHC,原值较大

转为格式为CWH值为0-1的Tensor transform = transforms.Compose([

#变为格式为C*W*H的Tensor
transforms.ToTensor(),
#第一个是均值,第二个是标准差,变值为0-1
transforms.Normalize((0.1307, ), (0.3081, )) ])   train_dataset = datasets.MNIST(root='./mnist_data/',
                           train=True,
                           download=False,
                           transform = transform)   train_loader = DataLoader(train_dataset,shuffle=True,batch_size=batch_size)  

test_dataset = datasets.MNIST(root=‘./mnist_data/’,
train=False,
download=False,
transform = transform) test_loader = DataLoader(test_dataset, shuffle=False, batch_size=batch_size)

2. 模型设计 class Net(torch.nn.Module):

def __init__(self):
    super(Net, self).__init__()
    # 线性层1,input784维 output512维
    self.l1 = torch.nn.Linear(784, 512)
    # 线性层2,input512维 output256维
    self.l2 = torch.nn.Linear(512, 256)
    # 线性层3,input256维 output128维
    self.l3 = torch.nn.Linear(256, 128)
    # 线性层4,input128维 output64维
    self.l4 = torch.nn.Linear(128, 64)
    # 线性层5,input64维 output10维
    self.l5 = torch.nn.Linear(64, 10)

def forward(self, x):
    # 改变张量形状view\reshape
    # view 只能用于内存中连续存储的Tensor,transpose\permute之后的不能用
    # 变为二阶张量(矩阵),-1用于计算填充batch_size
    x = x.view(-1, 784)
    # relu 激活函数
    x = F.relu(self.l1(x))
    x = F.relu(self.l2(x))
    x = F.relu(self.l3(x))
    x = F.relu(self.l4(x))
    # 第五层不再进行relu激活
    return self.l5(x)   model = Net()

3. 损失、优化器

#交叉熵损失 criterion = torch.nn.CrossEntropyLoss()
#随机梯度下降,momentum表冲量,在更新时一定程度上保留原方向 optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

4. 训练和测试 def train(epoch):

running_loss = 0.0
#提取数据
for batch_idx, data in enumerate(train_loader, 0):
    inputs, target = data
    #优化器清零
    optimizer.zero_grad()
    #前馈+反馈+更新
    outputs = model(inputs)
    loss = criterion(outputs, target)
    loss.backward()
    optimizer.step()
    #累计loss
    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()

【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第14张图片

【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第15张图片

【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第16张图片

【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第17张图片

结果:

【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第18张图片

【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第19张图片

课后练习2:kaggle商品分类

数据集: https://www.kaggle.com/c/otto-group-product-classification-challenge/data

【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第20张图片

实现代码:

  • https://blog.csdn.net/weixin_42320758/article/details/114024209
    主要参考博客,可以看看下面这篇学一下另外的写法!包含保存模型和可视化
  • https://blog.csdn.net/kids_budong_c/article/details/123271950
import torch
from torchvision import datasets
from torch.utils.data import DataLoader
from torch.utils.data import Dataset
import torch.nn.functional as F
import torch.optim as optim
import pandas as pd
import numpy as np


# 1. 准备数据
    # 定义函数将类别标签转为id表示,方便后面计算交叉熵
def lables2id(lables):
        target_id = []
        target_lables = ['Class_1', 'Class_2', 'Class_3', 'Class_4', 'Class_5', 'Class_6', 'Class_7', 'Class_8', 'Class_9']
        for lable in lables:
            target_id.append(target_lables.index(lable))
        return target_id
    #定义数据集
class OttoDataset(Dataset):
    def __init__(self,filepath):
        data = pd.read_csv(filepath)
        self.len = data.shape[0] #获取data行列数
        labels = data['target']
        self.x_data = torch.tensor(np.array(data)[:,1:-1].astype(float)) # 读取所以有行,从第一列开始,最后一列不要,转成float矩阵再存储成tensor 
        self.y_data = lables2id(labels)

    def __getitem__(self, index):
        return self.x_data[index], self.y_data[index]
 
    def __len__(self):
        return self.len

train_data=OttoDataset('./OttoGroupProduct/train.csv')
#建立数据集加载器
batch_size = 64
train_loader = DataLoader(dataset=train_data,shuffle=True,batch_size=batch_size)

## 2. 模型设计
class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # 输入93种特征
        self.l1 = torch.nn.Linear(93, 64)
        self.l2 = torch.nn.Linear(64, 32)
        self.l3 = torch.nn.Linear(32, 16)
        # 输出9类
        self.l4 = torch.nn.Linear(16, 9)
        self.relu=torch.nn.ReLU()
    
    def forward(self, x):
        x = F.relu(self.l1(x))
        x = F.relu(self.l2(x))
        x = F.relu(self.l3(x))
        # 最后一层不再进行relu激活
        return self.l4(x)

    def predict(self, x):
        with torch.no_grad():
            x = self.relu(self.l1(x))
            x = self.relu(self.l2(x))
            x = self.relu(self.l3(x))
            x = self.l4(x)
            # 这里先取出最大概率的索引,即是所预测的类别。
            _, predicted = torch.max(x, dim=1)
            # 将预测的类别转为one-hot表示,方便保存为预测文件。
            y = pd.get_dummies(predicted)
            return y
 
model = Net()

# 3. 损失、优化器
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

# 4. 训练和测试
def train(epoch):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        inputs, target = data
        inputs=inputs.float()

        optimizer.zero_grad()
        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
        
if __name__ == '__main__':
    for epoch in range(100):
        train(epoch)
# 定义预测保存函数,用于保存预测结果。
def predict_save():
    test_data = pd.read_csv('./OttoGroupProduct/test.csv')
    test_inputs = torch.tensor(np.array(test_data)[:,1:].astype(float))
    out = model.predict(test_inputs.float())

    lables=['Class_1', 'Class_2', 'Class_3', 'Class_4', 'Class_5', 'Class_6', 'Class_7', 'Class_8', 'Class_9']
    # 添加列标签
    out.columns = lables
    # 插入id行
    out.insert(0,'id',test_data['id'])
    output = pd.DataFrame(out)
    output.to_csv('./OttoGroupProduct/my_predict.csv', index=False)

predict_save()

结果:

【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第21张图片

【PyTorch】深度学习实践之 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)_第22张图片


学习资料

  • https://blog.csdn.net/qq_42585108/article/details/108200584
  • https://blog.csdn.net/jackydyy/article/details/117233150?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_title~default-1-117233150-blog-108200584.pc_relevant_multi_platform_whitelistv3&spm=1001.2101.3001.4242.2&utm_relevant_index=4

系列文章索引

教程指路:【《PyTorch深度学习实践》完结合集】 https://www.bilibili.com/video/BV1Y7411d7Ys?share_source=copy_web&vd_source=3d4224b4fa4af57813fe954f52f8fbe7

  1. 线性模型 Linear Model
  2. 梯度下降 Gradient Descent
  3. 反向传播 Back Propagation
  4. 用PyTorch实现线性回归 Linear Regression with Pytorch
  5. 逻辑斯蒂回归 Logistic Regression
  6. 多维度输入 Multiple Dimension Input
  7. 加载数据集Dataset and Dataloader
  8. 用Softmax和CrossEntroyLoss解决多分类问题(Minst数据集)
  9. CNN基础篇——卷积神经网络跑Minst数据集
  10. CNN高级篇——实现复杂网络
  11. RNN基础篇——实现RNN
  12. RNN高级篇—实现分类

你可能感兴趣的:(#,PyTorch深度学习实践,深度学习,pytorch,分类)