• 【分类器 Softmax-Classifier softmax数学原理与源码详解 深度学习 Pytorch笔记 B站刘二大人(8/10)】


    分类器 Softmax-Classifier softmax数学原理与源码详解 深度学习 Pytorch笔记 B站刘二大人 (8/10)

    在进行本章的数学推导前,有必要先粗浅的介绍一下,笔者在广泛查找后发现当前并没有官方定义什么是softmax分类器:
    softmax分类器在本质上也是激活函数的一种,可以看作激活函数sigmoid的拓展版,目标是将输出的多个数值转换为多个分类结果的概率。

    数学推导

    首先回归上一期的多输入模型,通过多个线性层之间的非线性连接,成功完成了通过8个维度的评价数据对样本是否为糖尿病患者进行了01判断:
    在这里插入图片描述
    多输入单输出问题虽然比单输入单输出问题更为普遍,但是现实中最多的是多输入多输出问题。
    在这里插入图片描述
    如果按照多输入单输出模型的思路对数据进行训练,也能得到相关的预测概率,但是会遇到一个非常明显的问题,就是输出的数据将是各个类别的相似概率总和不为1,而每一个概率都在(0,1)之间,显然这与平常的认知是有冲突,我们更希望输出的分类概率总和为1,从而确定最大可能的类别进行判断。

    因此该结构理论上可行,但是存在问题,输出结果之间由于相互概率互斥,应该存在相互抑制。在构建中出现输出值为负值或者多个输出概率大于0.7的清楚,不满足分布: y>0 && Σy = 1,希望输出值是一个分布,讲结构进行改进:

    在这里插入图片描述
    在此就引入Softmax处理层:
    在这里插入图片描述
    可以发现softmax运算的本质是将各个预测结果的单个可能性转换为整体预测中的概率,即输出的分类概率加和为1

    在此使用NLLLoss损失函数,通过与独热向量结合得到损失值
    在这里插入图片描述
    损失函数的代码实现环节:
    在这里插入图片描述

    按照数学原理编程实现softmax

    ''' coding:utf-8 '''
    """
    作者:shiyi
    日期:年 09月 07日
    """
    
    import torch
    import numpy as np
    
    # 实现 softmax + log 输出 + one_hot向量计算loss=-Yln_Y_
    y = np.array([1, 0, 0])
    z = np.array([0.2, 0.1, -0.1])
    y_pred = np.exp(z) / np.exp(z).sum()      # 将输出值进行softmax处理,是的输出的预测值在0-1之间,输出的各个概率和为1
    loss = (-y * np.log(y_pred).sum())
    print("Loss1 = ", loss,  "\n")
    
    # 使用torch中的CrossEntropyLoss()
    y = torch.LongTensor([0])          # longtensor 数据类型的
    z = torch.Tensor([[0.2, 0.1, -0.1]])
    criterion = torch.nn.CrossEntropyLoss()     # 交叉熵模块
    loss = criterion(z, y)
    print("loss2 = ", loss)
    
    # 通过交叉熵模块进行对比,虽然得到相同的预测结果,但是由于输入的值不同导致损失有不同
    criterion = torch.nn.CrossEntropyLoss()
    Y = torch.LongTensor([2, 0, 1])
    Y_pred1 = torch.Tensor([[0.1, 0.2, 0.9],
                            [1.1, 0.1, 0.2],
                            [0.2, 2.1, 0.3]])
    Y_pred2 = torch.Tensor([[0.8, 0.2, 0.3],
                            [0.2, 0.3, 0.5],
                            [0.2, 0.2, 0.5]])
    
    l1 = criterion(Y_pred1, Y)
    l2 = criterion(Y_pred2, Y)
    print("Batch Loss1 = ", l1.data, "\nBatch Loss2 = ", l2.data)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    代码模块解读与实现

    代码关键细节:

    1.pytorch 在进行分类的过程中,softmax环节和多分类的loss求解,以及backward梯度解算过程都已经完成了相关封装工作,可以直接调用

    2.在定义y的数据类型时,由于y属于多标签输入,需要定义为LongTensor类型,因为需要通过独热向量进行比对并求取损失

    在这里插入图片描述

    对比交叉熵的预测运算结果,虽然最后的预测结果相同,但是获得的损失函数值有所不同
    在这里插入图片描述
    显然l1在线性层预测过程中结果更为贴近实际数据标签,因此损失值更小

    作业1

    课堂作业:阅读文档,解析交叉熵CrossEntropyLoss损失和NLL损失NLLLOSS的差别,了解在什么需求下使用对应的损失函数:

    在这里插入图片描述

    实例

    Minist 数据集,预处理:用矩阵表示图像
    在这里插入图片描述

    步骤:1.准备数据2.设计模型计算输出y 3.设计损失和优化函数4.训练循环与测试
    在这里插入图片描述

    代码细节:读取图像,使用pillow进行读取,深度学习希望读取的图像的输入数值较小,在-1 - 1之间
    在这里插入图片描述

    Cv基础:单通道多通道图像相关知识,不再赘述。转换作用:将二维tensor转换为三维tensor,提供通道信息。同时Normalize进行标准化,将像素值转换为对应的零一分布

    保证上一层的out与下一层的input数值相同,注意由于使用softmax函数,最后一层不使用激活函数

    在这里插入图片描述
    在这里插入图片描述

    损失计算与优化器选择,由于模型较大,使用冲量优化momentum设置为0.5

    在这里插入图片描述

    定义训练实例:

    在这里插入图片描述

    整体代码

    ''' coding:utf-8 '''
    """
    作者:shiyi
    日期:年 09月 03日
    softmax 分类器实现线性层的minist分类
    """
    
    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
    
    batch_size = 64         # 设置一次训练的数据集batch大小
    # transform 将数据转化为tensor数据类型,并进行标准化处理
    transform = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.137, ), (0.3081, ))
    ])
    # 构建训练集数据
    train_dataset = datasets.MNIST(root='../dataset/minist/',
                                train=True,
                                download=True,
                                transform=transform)
    train_loader = DataLoader(train_dataset,
                              shuffle=True,
                              batch_size=batch_size)
    # 构建测试集数据
    test_dataset = datasets.MNIST(root='../dataset/minist',
                                  train=False,
                                  download=True,
                                  transform=transform)
    test_loader = DataLoader(test_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      # 将之前计算累计loss清零
        for batch_idx, data in enumerate(train_loader, 0):   # enumerate返回枚举对象,将索引从0开始修改为索引从1开始
            inputs, target = data
            optimizer.zero_grad()
    
            # forward
            outputs = model(inputs)
            loss = criterion(outputs, target)
            # backward
            loss.backward()
            # updata
            optimizer.step()
    
            running_loss += loss.item()
            if batch_idx % 300 == 299:
                print('[%d, 5%d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
                running_loss = 0.0
    
    
    def test():
        correct = 0
        total = 0
        with torch.no_grad():
            for data in test_loader:
                images, labels = data
                outputs = model(images)     # 输出为一个长度为10的列向量,其中的数值代表0-9识别的可能概率
                # 由于输出的是一个列向量,因此通过max函数找到预测的标签,返回值1是最大值,并不需要直接_释放,predicted返回标签
                _, predicted = torch.max(outputs.data, dim=1)           # 其中dim=1表示对output进行列向量查找,.data运算防止生成计算图
                total += labels.size(0)     # 通过标签size计算测试集样本个数
                correct += (predicted == labels).sum().item()   # 计算预测准确的次数
            print('Accuracy on test set: %d %%' % (100 * correct / total))
    
    
    if __name__ == '__main__':
        for epoch in range(10):
            train(epoch)
            test()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102

    运算结果:

    [9, 5300] loss: 0.039
    [9, 5600] loss: 0.041
    [9, 5900] loss: 0.046
    Accuracy on test set: 97 %
    [10, 5300] loss: 0.033
    [10, 5600] loss: 0.035
    [10, 5900] loss: 0.035
    Accuracy on test set: 97 %
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    作业2

    作业:
    在这里插入图片描述
    多分类进行训练
    (挖坑+1。。。代填。。。。)

  • 相关阅读:
    图神经网络综述:模型与应用
    【SpringMVC】@RequestMapping注解
    如何实现IT基础设施的全面监控和智能运维?
    代码随想录图论 第三天 | 130. 被围绕的区域 417. 太平洋大西洋水流问题
    python创建分类器小结
    物质的相平衡和化学平衡
    Web前端系列技术之JavaScript基础(从入门开始)④
    【考研】数据结构考点——顺序查找
    Day24.1:抽象类的详解
    通过AWS ALB Nginx代理Jenkins引发的一个问题
  • 原文地址:https://blog.csdn.net/qq_43649786/article/details/126897157