【PyTorch】在PyTorch中使用线性层和交叉熵损失函数进行数据分类

news2025/2/24 23:19:06

在PyTorch中使用线性层和交叉熵损失函数进行数据分类

前言:

在机器学习的众多任务中,分类问题无疑是最基础也是最重要的一环。本文将介绍如何在PyTorch框架下,使用线性层和交叉熵损失函数来解决分类问题。我们将以简单的Iris数据集作为起点,探讨线性模型在处理线性可分数据上的有效性。随后,我们将尝试将同样的线性模型应用于复杂的CIFAR-10图像数据集,并分析其性能表现。

背景:

  • Iris数据集:一个经典的线性可分数据集,包含三个类别的鸢尾花,每个类别有50个样本,每个样本有4个特征。
    请添加图片描述

  • CIFAR-10数据集:一个由10个类别组成的图像数据集,每个类别有6000张32x32彩色图像,总共有60000张图像。
    请添加图片描述

Iris数据集分类

数据读取与预处理:

read_data函数负责从CSV文件中读取数据,随机打乱,划分训练集和测试集,并进行标准化处理。

def read_data(file_path, only_test = False, normalize = True):
    np_data = pd.read_csv(file_path).values
    np.random.shuffle(np_data)
    
    classes = np.unique(np_data[:,-1])
    class_dict = {}
    for index, class_name in enumerate(classes):
        class_dict[index] = class_name
        class_dict[class_name] = index
        
    train_src = np_data[:int(len(np_data)*0.8)]
    test_src = np_data[int(len(np_data)*0.8):]
    train_data = train_src[:,:-1]
    train_labels = train_src[:, -1].reshape(-1,1)
    test_data = test_src[:, :-1]
    test_labels = test_src[:, -1].reshape(-1,1)
    if (normalize):
        mean = np.mean(train_data)
        std = np.std(train_data)
        train_data = (train_data - mean) / std
        mean = np.mean(test_data)
        std = np.std(test_data)
        test_data = (test_data - mean) / std
    if (only_test):
        return test_data, test_labels, class_dict
    return train_data, train_labels, test_data, test_labels, class_dict

模型构建:

Linear_classify类定义了一个简单的线性模型,其中包含一个线性层。

class Linear_classify(th.nn.Module):
    def __init__(self, *args, **kwargs) -> None:
        super(Linear_classify, self).__init__()
        self.linear = th.nn.Linear(args[0], args[1])
        
    def forward(self, x):
        y_pred = self.linear(x)
        return y_pred

训练过程: 在main函数中,我们初始化模型、损失函数和优化器。然后,通过多次迭代来训练模型,并记录损失值的变化。

file_path = "J:\\MachineLearning\\数据集\\Iris\\iris.data"
train_data, train_labels, test_data, test_labels, label_dict = read_data(file_path)
print(train_data.shape)
print(train_labels.shape)
print(label_dict)

int_labels = np.vectorize(lambda x: int(label_dict[x]))(train_labels).flatten()
print(int_labels[:10])

tensor_labels = th.from_numpy(int_labels).type(th.long) 
num_classes = int(len(label_dict)/2)
train_data = th.from_numpy(train_data.astype("float32"))

print (train_data.shape)
print (train_data[:2])
linear_classifier = Linear_classify(int(train_data.shape[1]), int(len(label_dict)/2))
loss_function = th.nn.CrossEntropyLoss()
optimizer = th.optim.SGD(linear_classifier.parameters(), lr = 0.001)
epochs = 10000
best_loss = 100
turn_to_bad_loss_count = 0
loss_history = []
for epoch in range(epochs):
    y_pred = linear_classifier(train_data)
    #print(y_pred)
    #print(y_pred.shape)
    loss = loss_function(y_pred, tensor_labels)
    if (float(loss.item()) > best_loss):
        turn_to_bad_loss_count += 1
    else:
        best_loss = float(loss.item())
    if (turn_to_bad_loss_count > 1000):
        break
    if (epoch % 10 == 0):
        print("epoch {} loss is {}".format(epoch, loss))
        loss_history.append(float(loss.item()))
    loss.backward()
    optimizer.step()
plt.plot(loss_history)
plt.show()

评估与测试

使用测试集数据评估模型的准确率,并通过可视化损失值的变化来分析模型的学习过程。

accuracy = []
for _ in range(10):
    test_data, test_labels, label_dict = read_data(file_path, only_test = True)
    test_result = linear_classifier(th.from_numpy(test_data.astype("float32")))
    print(test_result[:10])
    
    result_index = test_result.argmax(dim=1)
    iris_name_result = np.vectorize(lambda x: str(label_dict[x]))(result_index).reshape(-1,1)
    accuracy.append(len(iris_name_result[iris_name_result == test_labels]) / len(test_labels))
    
print("Accuracy is {}".format(np.mean(accuracy)))

结果

收敛很好很快

请添加图片描述

准确率较高

Accuracy is 0.9466666666666667

CIFAR-10数据集分类

关键改动

使用unpickle和read_data函数处理数据集,这部分是和前面不一样的
def unpickle(file):
    import pickle
    with open(file, 'rb') as fo:
        dict = pickle.load(fo, encoding='bytes')
    return dict

def read_data(file_path, gray = False, percent = 0, normalize = True):
    data_src = unpickle(file_path)
    np_data = np.array(data_src["data".encode()]).astype("float32")
    np_labels = np.array(data_src["labels".encode()]).astype("float32").reshape(-1,1)
    single_data_length = 32*32 
    image_ret = None
    if (gray):
        np_data = (np_data[:, :single_data_length] + np_data[:, single_data_length:(2*single_data_length)] + np_data[:, 2*single_data_length : 3*single_data_length])/3
        image_ret = np_data.reshape(len(np_data),32,32)
    else:
        image_ret = np_data.reshape(len(np_data),32,32,3)
    
    if(normalize):
        mean = np.mean(np_data)
        std = np.std(np_data)
        np_data = (np_data - mean) / std
    if (percent == 0):
        return np_data, np_labels, image_ret 
    else:
        return np_data[:int(len(np_data)*percent)], np_labels[:int(len(np_labels)*percent)], image_ret[:int(len(image_ret)*percent)]

运行结果

损失可以收敛,但收敛的幅度有限

可见只是从2.x 下降到了1.x
请添加图片描述

准确率比瞎猜准了3倍,非常的nice

请添加图片描述

train Accuracy is 0.6048

test Accuracy is 0.282

注意点:

  • 数据标准化:为了提高模型的收敛速度和准确率,对数据进行标准化处理是非常重要的,在本例中,不使用标准化会出现梯度爆炸,亲测。
  • 类别标签处理:在使用交叉熵损失函数时,需要确保类别标签是整数形式。

优化点:

  • 学习率调整:适当调整学习率可以帮助模型更快地收敛。
  • 早停法:当连续多次迭代损失值不再下降时,提前终止训练可以防止过拟合。
  • 损失函数选择:对于不同的问题,选择合适的损失函数对模型性能有显著影响,在多分类问题中,使用交叉熵损失函数是常见的选择,在pytorch中,交叉熵模块包含了softmax激活函数,这是其可以进行多分类的关键。

Softmax函数的推导过程如下:

首先,我们有一个未归一化的输入向量 z z z,其形状为 ( n , ) (n,) (n,),其中 n n n 是类别的数量。我们希望将这个向量转化为一个概率分布,其中所有元素的总和为1。

我们可以通过以下步骤来计算 softmax 函数:

  1. z z z 中的每个元素应用指数函数,得到一个新的向量 e z e^z ez

  2. 计算 e z e^z ez 中的最大值,记作 z ^ \hat{z} z^

  3. e z e^z ez 中的每个元素减去 z ^ \hat{z} z^,得到一个新的向量 v v v

  4. v v v 中的每个元素应用指数函数,得到一个新的向量 e v e^v ev

  5. 计算 e v e^v ev 中的最大值,记作 v ^ \hat{v} v^

  6. e v e^v ev 中的每个元素除以 v ^ \hat{v} v^,得到最终的概率分布。

以上步骤可以用以下的公式表示:

z = ( z 1 , z 2 , … , z n ) T e z = ( e z 1 , e z 2 , … , e z n ) T z ^ = m a x ( e z ) v = e z − z ^ e v = ( e v 1 , e v 2 , … , e v n ) T v ^ = m a x ( e v ) p = e v v ^ \begin{align*} z &= (z_1, z_2, \ldots, z_n)^T \\ e^z &= (e^{z_1}, e^{z_2}, \ldots, e^{z_n})^T \\ \hat{z} &= max(e^z) \\ v &= e^z - \hat{z} \\ e^v &= (e^{v_1}, e^{v_2}, \ldots, e^{v_n})^T \\ \hat{v} &= max(e^v) \\ p &= \frac{e^v}{\hat{v}} \end{align*} zezz^vevv^p=(z1,z2,,zn)T=(ez1,ez2,,ezn)T=max(ez)=ezz^=(ev1,ev2,,evn)T=max(ev)=v^ev

其中, p p p 是最终的概率分布。

结论:
通过实验,我们发现线性模型在Iris数据集上表现良好,但在CIFAR-10数据集上效果不佳。这说明线性模型在处理复杂的非线性问题时存在局限性。为了解决这一问题,我们将在后续的博客中介绍如何使用卷积神经网络来提高图像分类的准确率。

后记:
感谢您的阅读,希望本文能够帮助您了解如何在PyTorch中使用线性层和交叉熵损失函数进行数据分类。敬请期待我们的下一篇博客——“在PyTorch中使用卷积神经网络进行图像分类”。

完整代码

分类Iris数据集

import torch as th
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import torchvision

def read_data(file_path, only_test = False, normalize = True):
    np_data = pd.read_csv(file_path).values
    np.random.shuffle(np_data)
    
    classes = np.unique(np_data[:,-1])
    class_dict = {}
    for index, class_name in enumerate(classes):
        class_dict[index] = class_name
        class_dict[class_name] = index
        
    train_src = np_data[:int(len(np_data)*0.8)]
    test_src = np_data[int(len(np_data)*0.8):]
    train_data = train_src[:,:-1]
    train_labels = train_src[:, -1].reshape(-1,1)
    test_data = test_src[:, :-1]
    test_labels = test_src[:, -1].reshape(-1,1)
    if (normalize):
        mean = np.mean(train_data)
        std = np.std(train_data)
        train_data = (train_data - mean) / std
        mean = np.mean(test_data)
        std = np.std(test_data)
        test_data = (test_data - mean) / std
    if (only_test):
        return test_data, test_labels, class_dict
    return train_data, train_labels, test_data, test_labels, class_dict


class Linear_classify(th.nn.Module):
    def __init__(self, *args, **kwargs) -> None:
        super(Linear_classify, self).__init__()
        self.linear = th.nn.Linear(args[0], args[1])
        
    def forward(self, x):
        y_pred = self.linear(x)
        return y_pred



def main():
    file_path = "J:\\MachineLearning\\数据集\\Iris\\iris.data"
    train_data, train_labels, test_data, test_labels, label_dict = read_data(file_path)
    print(train_data.shape)
    print(train_labels.shape)
    print(label_dict)
    
    int_labels = np.vectorize(lambda x: int(label_dict[x]))(train_labels).flatten()
    print(int_labels[:10])
    
    tensor_labels = th.from_numpy(int_labels).type(th.long) 
    num_classes = int(len(label_dict)/2)
    train_data = th.from_numpy(train_data.astype("float32"))

    print (train_data.shape)
    print (train_data[:2])
    linear_classifier = Linear_classify(int(train_data.shape[1]), int(len(label_dict)/2))
    loss_function = th.nn.CrossEntropyLoss()
    optimizer = th.optim.SGD(linear_classifier.parameters(), lr = 0.001)
    epochs = 10000
    best_loss = 100
    turn_to_bad_loss_count = 0
    loss_history = []
    for epoch in range(epochs):
        y_pred = linear_classifier(train_data)
        #print(y_pred)
        #print(y_pred.shape)
        loss = loss_function(y_pred, tensor_labels)
        if (float(loss.item()) > best_loss):
            turn_to_bad_loss_count += 1
        else:
            best_loss = float(loss.item())
        if (turn_to_bad_loss_count > 1000):
            break
        if (epoch % 10 == 0):
            print("epoch {} loss is {}".format(epoch, loss))
            loss_history.append(float(loss.item()))
        loss.backward()
        optimizer.step()
    plt.plot(loss_history)
    plt.show()
    plt.show()
    
    accuracy = []
    for _ in range(10):
        test_data, test_labels, label_dict = read_data(file_path, only_test = True)
        test_result = linear_classifier(th.from_numpy(test_data.astype("float32")))
        print(test_result[:10])
        
        result_index = test_result.argmax(dim=1)
        iris_name_result = np.vectorize(lambda x: str(label_dict[x]))(result_index).reshape(-1,1)
        accuracy.append(len(iris_name_result[iris_name_result == test_labels]) / len(test_labels))
        
    print("Accuracy is {}".format(np.mean(accuracy)))
    
if (__name__ == "__main__"):
    main()

分类CIFAR-10数据集

import torch as th
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt


def unpickle(file):
    import pickle
    with open(file, 'rb') as fo:
        dict = pickle.load(fo, encoding='bytes')
    return dict



def read_data(file_path, gray = False, percent = 0, normalize = True):
    data_src = unpickle(file_path)
    np_data = np.array(data_src["data".encode()]).astype("float32")
    np_labels = np.array(data_src["labels".encode()]).astype("float32").reshape(-1,1)
    single_data_length = 32*32 
    image_ret = None
    if (gray):
        np_data = (np_data[:, :single_data_length] + np_data[:, single_data_length:(2*single_data_length)] + np_data[:, 2*single_data_length : 3*single_data_length])/3
        image_ret = np_data.reshape(len(np_data),32,32)
    else:
        image_ret = np_data.reshape(len(np_data),32,32,3)
    
    if(normalize):
        mean = np.mean(np_data)
        std = np.std(np_data)
        np_data = (np_data - mean) / std
    if (percent == 0):
        return np_data, np_labels, image_ret 
    else:
        return np_data[:int(len(np_data)*percent)], np_labels[:int(len(np_labels)*percent)], image_ret[:int(len(image_ret)*percent)]
    
        
        
    


class Linear_classify(th.nn.Module):
    def __init__(self, *args, **kwargs) -> None:
        super(Linear_classify, self).__init__()
        self.linear = th.nn.Linear(args[0], args[1])
        
        
    def forward(self, x):
        x = self.linear(x)
        return x



def main():
    file_path = "J:\\MachineLearning\\数据集\\cifar-10-batches-py\\data_batch_1"
    train_data, train_labels, image_data = read_data(file_path, percent=0.5)
    print(train_data.shape)
    print(train_labels.shape)
    print(image_data.shape)
    '''
    fig, axs = plt.subplots(3, 3)
    
    for i, ax in enumerate(axs.flat):
        image = image_data[i]
        ax.imshow(image_data[i],cmap="rgb")
        ax.axis('off') # 关闭坐标轴
    
    plt.show()
    '''
    
    int_labels = train_labels.flatten()
    print(int_labels[:10])
    
    tensor_labels = th.from_numpy(int_labels).type(th.long) 
    num_classes = int(len(np.unique(int_labels)))
    train_data = th.from_numpy(train_data)

    print (train_data.shape)
    print (train_data[:2])
    linear_classifier = Linear_classify(int(train_data.shape[1]), num_classes)
    loss_function = th.nn.CrossEntropyLoss()
    optimizer = th.optim.SGD(linear_classifier.parameters(), lr = 0.01)
    epochs = 7000
    best_loss = 100
    turn_to_bad_loss_count = 0
    loss_history = []
    for epoch in range(epochs):
        y_pred = linear_classifier(train_data)
        #print(y_pred)
        #print(y_pred.shape)
        loss = loss_function(y_pred, tensor_labels)
        if (float(loss.item()) > best_loss):
            turn_to_bad_loss_count += 1
        else:
            best_loss = float(loss.item())
        if (turn_to_bad_loss_count > 100):
            break
        if (epoch % 10 == 0):
            print("epoch {} loss is {}".format(epoch, loss))
            loss_history.append(float(loss.item()))
        loss.backward()
        optimizer.step()
    plt.plot(loss_history)
    plt.show()
    plt.show()
    
    test_result = linear_classifier(train_data)
    print(test_result[:10])
    result_index = test_result.argmax(dim=1).reshape(-1,1)
    accuracy = (len(result_index[result_index.detach().numpy() == train_labels]) / len(train_labels))
    print("train Accuracy is {}".format(accuracy))
    
    file_path = "J:\\MachineLearning\\数据集\\cifar-10-batches-py\\test_batch"
    test_data, test_labels, image_data = read_data(file_path)
    test_result = linear_classifier(th.from_numpy(test_data))
    print(test_result[:10])
    result_index = test_result.argmax(dim=1).reshape(-1,1)
    accuracy = (len(result_index[result_index.detach().numpy() == test_labels]) / len(test_labels))
        
    print("test Accuracy is {}".format(accuracy))
    
if (__name__ == "__main__"):
    main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1391451.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Matlab交互式的局部放大图

在数据可视化中,很多时候需要对某一区间的数据进行局部放大,以获得对比度更高的可视化效果。下面利用 MATLAB 语言实现一个交互式的局部放大图绘制。 源码自行下载: 链接:https://pan.baidu.com/s/1yItVSinh6vU4ImlbZW6Deg?pwd9d…

使用 Python 创造你自己的计算机游戏(游戏编程快速上手)第四版:第十九章到第二十一章

十九、碰撞检测 原文:inventwithpython.com/invent4thed/chapter19.html 译者:飞龙 协议:CC BY-NC-SA 4.0 碰撞检测涉及确定屏幕上的两个物体何时相互接触(即发生碰撞)。碰撞检测对于游戏非常有用。例如,如…

iphone 5s的充电时序原理图纸,iPAD充电讲解

上一篇写了iphone 5的时序。那是电池供电的开机时序。iphone 5s也是差不多的过程,不说了。现在看iphone5s手机充电时候的时序。iphone5s充电比iphone5充电简单了很多。 首先是usb接口接到手机上,usb线连接到J7接口上。J7接口不只是接usb,还能…

ZooKeeper 实战(五) Curator实现分布式锁

文章目录 ZooKeeper 实战(五) Curator实现分布式锁1.简介1.1.分布式锁概念1.2.Curator 分布式锁的实现方式1.3.分布式锁接口 2.准备工作3.分布式可重入锁3.1.锁对象3.2.非重入式抢占锁测试代码输出日志 3.3.重入式抢占锁测试代码输出日志 4.分布式非可重入锁4.1.锁对象4.2.重入…

canvas绘制美队盾牌

查看专栏目录 canvas示例教程100专栏,提供canvas的基础知识,高级动画,相关应用扩展等信息。canvas作为html的一部分,是图像图标地图可视化的一个重要的基础,学好了canvas,在其他的一些应用上将会起到非常重…

项目管理十大知识领域之项目整体管理

1. 项目整体管理的定义和范畴 项目整体管理是指在整个项目生命周期中对项目进行全面规划、组织、协调、控制和监督的过程。这包括对项目目标、范围、时间、成本、质量、沟通、风险和采购等方面进行统一的管理和协调。项目整体管理的范畴涵盖了项目管理的方方面面,旨…

【特征工程】分类变量:MultiLabelBinarizer对多标签数据进行编码

MultiLabelBinarizer 说明介绍 1. MultiLabelBinarizer 是什么? MultiLabelBinarizer是scikit-learn库中的一个用于处理多标签数据的编码器。通常用于将多标签的分类任务中的标签转化为二进制形式,便于机器学习模型的处理。该编码器的主要目标是将每个…

leecode1011 | 在D天内送达包裹的能力

传送带上的包裹必须在 days 天内从一个港口运送到另一个港口。 传送带上的第 i 个包裹的重量为 weights[i]。每一天,我们都会按给出重量(weights)的顺序往传送带上装载包裹。我们装载的重量不会超过船的最大运载重量。 返回能在 days 天内将传…

压力测试+接口测试(工具jmeter)

jmeter是apache公司基于java开发的一款开源压力测试工具,体积小,功能全,使用方便,是一个比较轻量级的测试工具,使用起来非常简单。因 为jmeter是java开发的,所以运行的时候必须先要安装jdk才可以。jmeter是…

【架构师专题】架构师如何管理业务团队?

一个优秀的架构师一定是一个优秀的管理者,这个是没错的,反过来一个优秀的管理者不一定是一个优秀的架构师,这个是我做了这么对年的架构师心得。 曾经我也做过关于团队底下的一线开发人员对团队中架构师的调查报告,发现这些开发人…

从此不再为远程访问局域网发愁

下载地址 Windows 64位 (切勿直接在压缩文件中操作,全部解压到一处后再操作,请关闭某60(会胡乱拦截),可用其他任意安全软件)Mac OS X 64位 (给fastnat执行权限 chmod x ./fastnat.. 终端运行二进制,自行百度)Linux 64位 (给fastnat执行权限 chmod x ./fastnat..)Linux/ARM 32位…

自动驾驶中大火的AI大模型中有哪些研究方向,与Transformer何干?

摘要: 本文将针对大模型学习中可能遇见的问题进行分析梳理,以帮助开发者在利用大模型在自动驾驶场景处理中学习更好的策略,利用有关大模型性能评价的问题,制定一个科学的标准去判断大模型的长处和不足。 随着自动驾驶行业发展对于大数据量处理的强大需求,其要求处理数据的…

硬件知识积累 VPX 3U/6U 电源板的连接器引脚定义讲解 (简单说明)

本文章参考资料 :ANSI/VITA 62-2012 1. 首先参考资料里面引脚定义图: 1. 3U 的引脚定义图: (VPX引脚编号, 最大电流, 对应引脚的作用) 2. 6U的引脚定义图: (VPX引脚编号, 最大电流&#xff0c…

网络Yum仓库介绍、自定义Yum仓库、Yum仓库更新、邮件的收发、DNS服务介绍、构建DNS服务、递归解析、迭代解析、NTP时间同步

1 大鹏一日同风起,扶摇直上九万里 2 环境准备 所有虚拟机设置SELinux运行模式 [rootserver ~]# getenforceEnforcing[rootserver ~]# setenforce 0 #当前设置[rootserver ~]# getenforcePermissive[rootserver ~]# vim /etc/selinux/configSELINUXpermissive 所…

爬虫案例——使用超级鹰打码平台识别验证码

爬虫案例——使用超级鹰打码平台识别验证码 超级鹰是一个常用的打码平台,您可以按照以下步骤来使用它: 注册账户:首先,您需要在超级鹰网站上注册一个账户。访问超级鹰官方网站(https://www.chaojiying.com/&#xff…

Lua从电脑端爬取短视频评论并作商业化分析

之前有个大客户让我写一篇关于抓取短视频评论数据的单子,说是帮助公司寻找意向客户以及所对应产品在短视频里面的展现以及热门程度,通过数据采集方式并作数据自动化分析,从而实现商业上的价值。对于我来说写个爬虫还不简单,通过三…

使用scipy处理图片——滤镜处理

大纲 black_tophatwhite_tophatconvolvecorrelategaussian_filtergaussian_laplacemaximum_filtermedian_filterminimum_filterpercentile_filterprewittrank_filtersobelspline_filteruniform_filter基础代码代码仓库 在《使用numpy处理图片——模糊处理》一文中,我…

NodeJs 第十六章 JWT

JWT 概述令牌的组成headerpayloadsignature 令牌的验证一个简单的登陆服务总结 随着前后端分离的发展,以及数据中心的建立,越来越多的公司会创建一个中心服务器,服务于各种产品线。 而这些产品线上的产品,它们可能有着各种终端设备…

如何在云端加速缓存构建

缓存是指将某类数据存储起来以便以后重复使用的过程,它的运用在开发场景中非常普遍。类似于你习惯把最常用的调料放在厨房台面上,而不是橱柜里,这样你在准备大餐时就可以轻松取用。 但对于一个更为技术性、更精确的用例,比如像谷…

CSDN 年度总结|知识改变命运,学习成就未来

欢迎来到英杰社区: https://bbs.csdn.net/topics/617804998 欢迎来到阿Q社区: https://bbs.csdn.net/topics/617897397 📕作者简介:热爱跑步的恒川,致力于C/C、Java、Python等多编程语言,热爱跑步&#xff…