[deeplearning]pytorch实现softmax多分类问题预测训练

2023-09-15 19:00:03

写在前面:俺这两天也是刚刚加入实验室,因为之前的学习过程中用到更多的框架是tensorflow,所以突然上手pytorch多少有些力不从心了。

这两个框架的主要区别在与tensorflow更偏向于工业使用,所以里面的很多函数和类都已经封装得很完整了,直接调用,甚至连w,b等尺寸都会自动调整。但是pytorch更加偏向于学术,。。。。或者说更加偏向于数学,很多功能都需要我们自己手动去实现:

刚刚跟这d2l的课程学习了如何去实现最基本的神经网络和计算,这里使用当时学过的solfmax作为经典案例,作为一个简单的补充,我会在这里面简单讲解一下softmax是怎么实现的,以及一些库函数

纯手动实现:

其实是有一些更高级别的api可以调用,比如损失函数就不用我们自己手写,但是训练的过程还是要的。

1.获取一些数据,这里我们通过一个特殊数据集合来或去数据
#先凑成一个数据集合
batch_size = 256
#这里好像就上面那么恶心了,直接从这个数据集合中获取数据
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

这里注意一个问题,batch_size不是你获取到的全部数据,而是你确定每一批数据的大小

接下来根据这个大小,获取多批数据,然后保存为训练集合以及测试集合

(由于我们这里要的事情非常简单,所以我们不验证)

2.我们开始创建一层神经元,输出为10个分量的估计数值
#初始化参数
num_inputs = 784      #输入,也就是特征值的数目为784
num_outputs = 10      #输出也就是softmax层神经元的数目,10

#这段代码用于构建某一层的w和b,并且先将其初始化
W = torch.normal(0, 0.01, size=(num_inputs, num_outputs), requires_grad=True)
b = torch.zeros (num_outputs, requires_grad=True)

这里w和b是仅仅是一对数字,而是一个完整的对象,除了基本的数值以外,还能存储一些注入诸如梯度等等信息。代表了这一层神经元的具体情况。

这个layer构建出来的神经元其实就是10个神经元,每个神经元支持的输入为784个特征。

3.创建solftmax函数,这个函数内部将会对神经网络的输出作出一些处理

#创建一个softmax函数,用来完成最后的softmax操作
#X在这里应该是一个10个分量的tensor,下面的函数就是正常的softmax操作
def softmax(X):
    X_exp = torch.exp(X)
    partition = X_exp.sum(1, keepdim=True) #沿着列展开的方向求和
    return X_exp / partition               #这里应用了广播机制

我们先进行指数化,然后求和,最后使用广播技术(其实这个所谓的广播也算是线性代数计算时候的基本特征了)得到一个(归一化)的tensor(所有分量相加为1,符合我们先是生活中对事物的预测逻辑,比如:连衣裙可能性0.55,鞋子可能性0.25,帽子可能性0.20)

4.然后是定义最核心的预测函数,称之为网络本身到也可以
#定义一个神经网络
#其实说是神经网络,这里只是进行了一个简单的数据变换,然后计算wx+b
#最后计算出来的结果因为是matmul的矩阵乘法,而且w和b本身也是size=10 的 tensor
#所以计算结果也是一样大小的tensor,然后就可以放心进行softmax操作
def net(X):
    return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b)

其实这个就是对于十个神经元,然后进行计算操作,得到估计数值

其实直接返回torch.matmul(X.reshape((-1, W.shape[0])), W) + b的话就变化成一个很常见的10线性回归了,在这里可以很清楚的看到softmax实现的是一个激活函数的作用

5.定义损失函数loss function

def cross_entropy(y_hat, y):
    return - torch.log(y_hat[range(len(y_hat)), y])

这个东西稍微有一点点复杂。。。

首先先解释一下这个东西

y_hat[  range(len(y_hat))  ,   y )

首先要先说明一点就是,y_hat是预测数值,一个二维tensor,比如说其中的第一条数据

[0.22,0.23,0.35.........]这代表的是某一个物体的预测结果,在10个标签中每一种可能性的概率

y则是一个一维tensor,每个分量代表的是该物体到底是什么,是确切数值

而这个[]中携带两个tensor的语法,被称为“高级索引”

#补充一下:这个语法的名字叫做高级索引,是从二维矩阵中选择出一个一维tensor
#第一个tensor是选择哪些行,这里选择所有行
#第二个是选择有哪些列
#在这个数据中我们实现的效果就是
#y-hat是一个二维tensor,每行是一个数据,每一列是对不同类型的预测
#y。。。严格来说是一个一维tensor,每个分量代表第i个数据到底是什么标签
#也就是说这个的逻辑意义是:每条数据猜对的概率?差不多可以这样子理解

6.优化/迭代函数

其实这个部分就是我们迭代,gradient descent 时候的操作

所谓的梯度就是求得的偏导数

#优化函数,其实这玩意就是我们的迭代函数,就那个repeat部分的东西,0.1是learning rate
def updater(batch_size):
    return d2l.sgd([W, b], 0.1, batch_size)

sgd就是d2l包下内置的“随机 gd”函数,这个里面梯度已经保存起来了

7.创建单次训练函数
#把模型训练了
def train_epoch_ch3(net, train_iter, loss, updater):  #@save
    # 将模型设置为训练模式
    if isinstance(net, torch.nn.Module):
        net.train()
    for X, y in train_iter:
        # loss是已经封装好的损失计算函数
        l = loss(net(X), y)
        # 使用定制的优化器和损失函数
        l.sum().backward()           #计算梯度,也就是代价函数导的东西
        updater(X.shape[0])          #梯度在这里好像是没有传入进来,但是实际上已经保存在w和b中了,对所有的w和b进行迭代计算

这个函数执行一次也就是一次训练

8.训练10次
#训练函数

def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):  #@save
    """训练模型(定义见第3章)"""
    for epoch in range(num_epochs):
        train_epoch_ch3(net, train_iter, loss, updater) # 直接就是训练了,不验证了



#开始训练
num_epochs = 10
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, updater)

这里我们直接根据训练集合进行验证

9.最后进行预测以及可视化展示
#预测函数
def predict_ch3(net, test_iter, n=6):  #@save
    """预测标签(定义见第3章)"""
    for X, y in test_iter:
        break
    # 将真实标签转换为对应的类别名称
    trues = d2l.get_fashion_mnist_labels(y)
    # 使用net进行预测,并且寻找预测结果转化为名称
    preds = d2l.get_fashion_mnist_labels(net(X).argmax(axis=1))
    #转化为title(还是使用对列生成器语法)
    titles = [   true +'\n' + pred    for true, pred in zip(trues, preds)   ]
    #展示图片
    d2l.show_images( X[0:n].reshape((n, 28, 28)), 1, n, titles=titles[0:n])

#展示预测
predict_ch3(net, test_iter)

plt.show()

关于在训练和预测的时候我们需要干什么

其实前面也算是写了不少代码了(其实也就是单纯实现了一个单一神经元以及softmax的预测)

这里就简单总结一下,在这个“训练”部分,我们一般都会做一些什么事情:

我们先拿出一个很简单的单一线性回归预测来举个例子

for X, y in data_iter:
        l = loss(net(X) ,y)  #计算这个一批数据(10)个的损失
        trainer.zero_grad()  #清除已经有的梯度
        l.backward()         # 计算损失对当前模型的梯度
        trainer.step()       #根据梯度更新模型参数,梯度下降的根本操作

其实看这个代码,我们第一步做的就是遍历,通过一开始设置的数据批次进行分批次的训练

进入某一次训练中的时候,我们要先根据损失函数,计算出这一批的损失

(不同的框架和代码对这个玩应的实现和理解都完全不一样,但是你要记住这个东西的数学本质是损失函数之和,即为这个批次数据的代价函数,我们最后梯度下降的公式,最重要的一个步骤就是对代价函数求偏倒数,这也就是框架中常说的gradient梯度)

然后根据损失,通过一种称之为“反向传递”的技术,计算出偏导

最后这个step,就代表开始训练

大致架构就是这个样子实现的,如果这个样子还不是太明白具体要做什么,那么我们直接把上面是用softmax技术的东西简化一下再放出来:

#把模型训练了
    for X, y in train_iter:
        l = loss(net(X), y)          #loss是已经封装好的损失计算函数
        l.sum().backward()           #计算梯度,也就是代价函数导的东西
        updater(X.shape[0])          #梯度在这里好像是没有传入进来,但是实际上已经保存在w和b中了

也是进行分批次的训练

然后计算一下损失,再计算代价函数,对代价函数是用反向传播求偏导数

最后进行训练

最终总结一下,像这样子手动实现一个训练的过程中,我们能做的就是

(1)想办法得到代价函数(也许还要清除之前计算得到的梯度)

(2)获取代价函数的梯度(一般是反向传递)

(3)训练

至于在预测的时候做什么,就是一些预测结果的分析,精度计算什么的,那都是后话了

更多推荐

视觉设计师提升自己能力的经验优漫动游

1、业余时间视觉设计师提升自己能力的经验还经常听到一种抱怨”产品有限制,我所擅长发挥不出来”,这样无疑是把自己的设计专业成长寄托在产品上。认为产品不成功自己的设计就不能成长。这其实是个借口。其实面对这个问题,最好的办法就是把设计分2条线:1.项目线:公司的实际产品项目,理解并按照实际情况,满足产品设计需求并达到公司要求

Flask框架-2-[单聊]: flask-socketio实现websocket的功能,实现单对单聊天,flask实现单聊功能

一、概述和项目结构在使用flask-socketio实现单聊时,需要将会话id(sid)与用户进行绑定,通过emit('事件','消息',to=sid),就可以把消息单独发送给某个用户了。flask_websocket|--static|--js|--jquery-3.7.0.min.js|--socket.io_4.

基于STM32设计的校园一卡通(设计配套的手机APP)

一、功能介绍【1】项目介绍随着信息技术的不断发展,校园一卡通作为一种高效便捷的管理方式,已经得到了广泛的应用。而其核心部件——智能卡也被越来越多的使用者所熟知。本文介绍的项目是基于STM32设计的校园一卡通消费系统,通过RC522模块实现对IC卡的读写操作,利用2.8寸TFT触摸屏(驱动芯片是ILI9341)作为交互界

【自学开发之旅】Flask-前后端联调-异常标准化返回(六)

注册联调:前端修改:1.修改请求向后端的url地址文件:env.development修改成VITE_API_TARGET_URL=http://127.0.0.1:9000/v1登录:token验证校验forms/user.pyfromwerkzeug.securityimportcheck_password_has

redis漏洞修复:(CNVD-2019-21763)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、漏洞内容二、镜像准备1.确认镜像版本2.下载镜像三、配置文件准备1.获取配置文件2.修改配置文件四、启动redis容器五、修改iptables文件总结前言漏扫发现机器上基于容器运行的redis的访问权限没有限制,需要增加安全配置。现在使用的

Linux图形界面与字符界面切换

1.启动时进入字符界面,后来想切换到图形界面:使用startx或init5(注:startx只是在原有运行级别3上加了图形界面,运行级别没变,而init5则是切换到运行级别5,所以要重新登录。可用runlevel命令查看当前运行级别和上一次运行级别)2.启动时进入图形界面,后来想切换到字符界面:使用Ctrl+Alt+F

Unity中UI组件对Shader调色

文章目录前言一、原理在Shader中直接暴露的Color属性,不会与UI的Image组件中的Color形成属性绑定。因为UI的Image组件中更改的颜色是顶点颜色,如果需要在修改组件中的颜色时,使Shader中的颜色也同时改变。那么就需要在应用程序阶段传入到顶点着色器的数据增加一个变量,用于给顶点着色器使用。二、实现1

【C语言基础】枚举和联合体

📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】📢:文章若有幸对你有帮助,可点赞👍收藏⭐不迷路🙉📢:内容若有错误,敬请留言📝指正!原创文,转载请注明出处文章目录前言一、枚举1.1枚举的含义1.

群狼调研(长沙餐厅满意度调查)开展汽车制动厂商客户满意度调查

在当今的汽车市场中,客户满意度已经成为衡量汽车厂商服务水平的重要标准。为了更好地了解客户对汽车制动产品的需求和满意度,一些厂商会委托专业的市场调查公司进行客户满意度调查。群狼调研(长沙汽车经销商满意度调查)多年的客户满意度调查经验,通过本文介绍汽车制动厂商客户满意度调查的特点和优势。汽车制动系统是关乎汽车安全的重要部件

Unity 2021.x及以下全版本Crack

前言最近Unity那档子事不出来了吗,搞得所有人都挺烦的,顺便在公司内网需要我完成一个游戏的项目,就研究了一下如何将Unity给Crack掉。注意所有操作应有连接外网的权限以我选择的版本为例,我使用的是Unity2021.3.5f1与UnityHub3.3.0c-9。特别鸣谢:tylearymf首先到UniHacker

推荐一款可以快速抽取sap数据的ETL工具

使用SAP在数据分析上面临的问题SAPEnterpriseResourcePlanning(ERP)是国内最广泛使用的ERP系统之一。然而,使用SAPERP系统面临着一些数据分析不方便,数据导出困难等问题:数据集成困难:将SAP中的数据整合到其他系统或本地数据仓库通常是一项复杂的任务。SAP系统的复杂性和独特性导致数据

热文推荐