# 【深度学习】:《PyTorch入门到项目实战》第五天:从0到1实现Softmax回归

简介: softmax回归模型是logistic回归模型在多分类问题上的推广,在多分类问题中,类标签y可以取两个以上的值。本文基于MNIST手写数字数据集来演示如何使用Pytorch实现softmax回归
  • ✨本文收录于【深度学习】:《PyTorch入门到项目实战》专栏,此专栏主要记录如何使用PyTorch实现深度学习笔记,尽量坚持每周持续更新,欢迎大家订阅!
  • 🌸个人主页:JoJo的数据分析历险记
  • 📝个人介绍:小编大四统计在读,目前保研到统计学top3高校继续攻读统计研究生
  • 💌如果文章对你有帮助,欢迎✌关注、👍点赞、✌收藏、👍订阅专栏

参考资料:本专栏主要以沐神《动手学深度学习》为学习资料,记录自己的学习笔记,能力有限,如有错误,欢迎大家指正。同时沐神上传了的教学视频和教材,大家可以前往学习。

请添加图片描述

写在前面

softmax回归模型是logistic回归模型在多分类问题上的推广,在多分类问题中,类标签y可以取两个以上的值。本文基于MNIST手写数字数据集来演示如何使用Pytorch实现softmax回归。🎄 # 🍓1. 数据集导入 首先我们来简单的介绍一些`softmax`回归基本模型,基本思路如下: $$ P(class=i) = \frac{e^i}{\sum e^i} $$ 损失函数使用`交叉熵`: $$ l(y,\hat y) = -\frac{1}{m}\sum y_ilog{\hat y_i} $$ ```python # 当如相关库 import torch import torch.nn as nn from torchvision import datasets,transforms from torch.utils import data import matplotlib.pyplot as plt import numpy as np import torch.optim as optim ``` 在这里与之前不同的是我们导入了`torchvision`,它是处理计算机视觉常用的一个库。沐神在这里使用了`FashionMnis`t数据集,我在这里还是使用`Mnist`数据集,具体的下载代码如下所示。其中train参数可以设置训练集和测试集 ```python trans = transforms.ToTensor() train = datasets.MNIST(root='./data',download=True,train=True,transform=trans) test = datasets.MNIST(root='./data',download=True,train=False,transform=trans) ``` `Mnist数据集`由10个数字的图像组成的。其中训练集有60000张图片,测试集有10000张图片。训练集用于模型的拟合,测试集用于评估模型的好坏 ```python len(train), len(test) ``` (60000, 10000) 每张图片的像素均是`28*28`,并且是灰度图像,所以通道数为1 ```python train[0][0].shape ``` torch.Size([1, 28, 28]) 我们来看一下训练集中的特征和标签,. ```python X, y = next(iter(data.DataLoader(train, batch_size=25))) y ``` tensor([5, 0, 4, 1, 9, 2, 1, 3, 1, 4, 3, 5, 3, 6, 1, 7, 2, 8, 6, 9, 4, 0, 9, 1, 1]) y代表的是`0-9`的数字,下面我们将图形绘制出来 ```python def show_images(imgs, num_rows, num_cols, titles=None, scale=1.5): """绘制图像列表""" figsize = (num_cols * scale, num_rows * scale) _, axes = plt.subplots(num_rows, num_cols, figsize=figsize) axes = axes.flatten() for i, (ax, img) in enumerate(zip(axes, imgs)): if torch.is_tensor(img): # 图片张量 ax.imshow(img.numpy()) else: # PIL图片 ax.imshow(img) ax.axes.get_xaxis().set_visible(False) ax.axes.get_yaxis().set_visible(False) if titles: ax.set_title(titles[i]) return axes ``` ```python X, y = next(iter(data.DataLoader(train, batch_size=25))) show_images(X.reshape(25, 28, 28), 2, 9) ``` ​ ![png](https://ucc.alicdn.com/images/user-upload-01/img_convert/645b2c760297c075a3064eb7f9258269.png#pic_center) ​ 可以看到第一张图片是5,第二张图片是0。接下来我们想要做的事情是,给电脑一张图片,如何让其返回一个正确的数字。 # 🍅2.初始化参数 因为`softmax`回归需要输入的数据是一个向量,因此首先我们需要将数据进行转换,下面要注意初始化参数的大小。 ```python num_inputs = 784 num_outputs = 10 # 初始化为正态分布 W = torch.normal(0,0.01,size = (num_inputs,num_outputs),requires_grad = True) b = torch.zeros(num_outputs,requires_grad=True) ``` # 🍒3.定义softmax回归 根据`softmax`回归定义,我们可以通过以下三步实现: - 1.对每一项求指数 - 2.求和 - 3.用每一行的数除以和 具体实现代码如下 ```python def softmax(X): X_exp = torch.exp(X) s = X_exp.sum(1, keepdims=True) return X_exp / s ``` 下面我们举一个简单的例子看一下`softmax`函数是如何工作的 ```python z = torch.rand(3, 5) h = softmax(z) print(h) ``` tensor([[0.1768, 0.1426, 0.2773, 0.2582, 0.1450], [0.1580, 0.1307, 0.2118, 0.2411, 0.2583], [0.1863, 0.2572, 0.1148, 0.1996, 0.2420]]) 这样就得出了每一个样本中每一类的概率 进一步定义`softmax`回归模型 ```python def nex(X): return softmax((X.reshape((-1,W.shape[0])).matmul(W)+b)) ``` # 🍑4. 损失函数定义 在这里我们依然使用交叉熵函数处理多分类问题 损失函数: $$ l(y,\hat y) = -\frac{1}{m}\sum y_ilog{\hat y_i} $$ 其中$y_i=0,1$,$\hat{y}_i$是预测的概率 在这里我想介绍两种方法计算损失函数,一种的沐神介绍的,通过索引来进行计算,具体如下所示 ```python def cross_entropy(y_hat, y): return - torch.log(y_hat[range(len(y_hat)), y])# 这里使用y来进行索引 ``` 这里我们使用了y来进行索引,我们来看看一个具体的例子 ```python y_true = torch.tensor([0,1]) y_hat = torch.tensor([[0.1,0.2,0.7],[0.3,0.5,0.2]]) y_hat[[0,1],y_true] ``` tensor([0.1000, 0.5000]) 这里返回的是第一个样本中第一类是正确分类的,和第二个样本中的第二类是正确分类的。所以交叉熵的计算就是 $$-\frac{1}{2}(1\times log(0.1)+ 1\times log(0.5))$$ ```python cross_entropy(y_hat,y_true).mean() ``` tensor(1.4979) 等价于: ```python (-np.log(0.1)-np.log(0.5))/2 ``` 1.4978661367769954 上面这种方式虽然简洁,但是可能不太好理解,下面介绍一种更直观的方式。首先我们要将y转换成`one-hot`编码。 ```python y_true = torch.tensor([0,1]) y_hat = torch.tensor([[0.1,0.2,0.7],[0.3,0.5,0.2]]) y_one_hot = torch.zeros_like(y_hat) y_one_hot.scatter_(1, y_true.unsqueeze(1), 1) y_one_hot ``` tensor([[1., 0., 0.], [0., 1., 0.]]) 可以看出此时的y_one_hot和y_hat维度相同,并且y_one_hot对应类上的元素是1,其余元素为0,此时再根据公式计算交叉熵即可 $$ -\frac{1}{2}(1\times log(0.1)+0\times log(0.2)+0\times log(0.7) +0 \times log(0.2) +1\times log(0.5)+0\times log(0.3) $$ ```python cost = (y_one_hot * -torch.log(y_hat)).sum(dim=1).mean() cost ``` tensor(1.4979) 可以看出两种方法得到的结果一致 ```python def opt(W,b): return optim.SGD([W,b],lr=0.1) ``` # 🍐5.训练模型 ```python ''' 初始化参数 ''' W = torch.zeros((784, 10), requires_grad=True) b = torch.zeros(10, requires_grad=True) ''' 定义SGD优化器 ''' optimizer = optim.SGD([W, b], lr=0.1) ''' 训练模型 ''' nb_epochs = 1000 for epoch in range(nb_epochs + 1): z = net(X)#计算softmax回归结果 cost = cross_entropy(z,y)#计算损失函数 # SGD求解参数 optimizer.zero_grad()#初始化参数 cost.mean().backward()#后向传播求参数 optimizer.step()#更新参数 if epoch % 100 == 0 : print('Epoch {:4d}/{} Cost: {:.6f}'.format( epoch, nb_epochs, cost.mean().item() )) ``` Epoch 0/1000 Cost: 2.302585 Epoch 100/1000 Cost: 0.055274 Epoch 200/1000 Cost: 0.026265 Epoch 300/1000 Cost: 0.017182 Epoch 400/1000 Cost: 0.012762 Epoch 500/1000 Cost: 0.010150 Epoch 600/1000 Cost: 0.008425 Epoch 700/1000 Cost: 0.007202 Epoch 800/1000 Cost: 0.006290 Epoch 900/1000 Cost: 0.005582 Epoch 1000/1000 Cost: 0.005018 # 🍏6.模型预测 首先我们从测试集中随机抽取10个样本 ```python X_test, y_test = next(iter(data.DataLoader(test, batch_size=10))) show_images(X_test.reshape(10, 28, 28), 2, 5) ``` array([, , , , , , , , , ], dtype=object) ​ ![png](https://ucc.alicdn.com/images/user-upload-01/img_convert/dfad5e7c635a780847c79fd800a4bf56.png#pic_center) ​ 测试集拿到的十个数字为`7,2,1,0,4,1,4,9,5,9`下面我们用刚刚训练好的模型来预测,看看结果如何 ```python z = net(X_test) predict = z.argmax(dim=1) predict ``` tensor([7, 3, 1, 0, 4, 1, 4, 1, 4, 7]) 可以看出预测的结果有六个正确,四个错误,模型效果一般。因为我们刚刚只使用了训练集中的25个样本,所以在训练集上预测效果并不好。如何提升预测精度问题将在后续讨论。 # 🍎7.使用内置api简单实现softmax回归 上面我们演示了如何从0到1实现`softmax`回归,在`pytorch`中,有内置的api可以直接帮我们更简洁的实现,具体代码如下 ```python from torch import nn # 一样导入数据集 X, y = next(iter(data.DataLoader(train, batch_size=25))) # 定义模型 net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10))#nn.Flatten()的作用是将输入的特征转换为一个向量 def init_weights(m): if type(m) == nn.Linear: nn.init.normal_(m.weight, std=0.01)#初始化参数 net.apply(init_weights) #计算损失函数 loss = nn.CrossEntropyLoss(reduction='none') # 定义SGD优化器 trainer = torch.optim.SGD(net.parameters(), lr=0.1) nb_epochs = 1000 for epoch in range(nb_epochs + 1): z = net(X)#计算模型结果 cost = loss(z,y)#计算损失函数 # SGD求解参数 trainer.zero_grad()#初始化参数 cost.mean().backward()#后向传播求参数 trainer.step()#更新参数 if epoch % 100 == 0 : print('Epoch {:4d}/{} Cost: {:.6f}'.format( epoch, nb_epochs, cost.mean().item() )) ``` Epoch 0/1000 Cost: 2.318002 Epoch 100/1000 Cost: 0.062154 Epoch 200/1000 Cost: 0.028716 Epoch 300/1000 Cost: 0.018596 Epoch 400/1000 Cost: 0.013739 Epoch 500/1000 Cost: 0.010891 Epoch 600/1000 Cost: 0.009021 Epoch 700/1000 Cost: 0.007699 Epoch 800/1000 Cost: 0.006715 Epoch 900/1000 Cost: 0.005955 Epoch 1000/1000 Cost: 0.005349 本章的介绍到此介绍,如果文章对你有帮助,请多多点赞、收藏、评论、关注支持!!
相关文章
|
24天前
|
机器学习/深度学习 人工智能 TensorFlow
人工智能浪潮下的自我修养:从Python编程入门到深度学习实践
【10月更文挑战第39天】本文旨在为初学者提供一条清晰的道路,从Python基础语法的掌握到深度学习领域的探索。我们将通过简明扼要的语言和实际代码示例,引导读者逐步构建起对人工智能技术的理解和应用能力。文章不仅涵盖Python编程的基础,还将深入探讨深度学习的核心概念、工具和实战技巧,帮助读者在AI的浪潮中找到自己的位置。
|
3月前
|
机器学习/深度学习 人工智能 算法
深度学习入门:理解神经网络与反向传播算法
【9月更文挑战第20天】本文将深入浅出地介绍深度学习中的基石—神经网络,以及背后的魔法—反向传播算法。我们将通过直观的例子和简单的数学公式,带你领略这一技术的魅力。无论你是编程新手,还是有一定基础的开发者,这篇文章都将为你打开深度学习的大门,让你对神经网络的工作原理有一个清晰的认识。
|
6天前
|
机器学习/深度学习 人工智能 算法
深度学习入门:用Python构建你的第一个神经网络
在人工智能的海洋中,深度学习是那艘能够带你远航的船。本文将作为你的航标,引导你搭建第一个神经网络模型,让你领略深度学习的魅力。通过简单直观的语言和实例,我们将一起探索隐藏在数据背后的模式,体验从零开始创造智能系统的快感。准备好了吗?让我们启航吧!
26 3
|
1月前
|
机器学习/深度学习 监控 PyTorch
深度学习工程实践:PyTorch Lightning与Ignite框架的技术特性对比分析
在深度学习框架的选择上,PyTorch Lightning和Ignite代表了两种不同的技术路线。本文将从技术实现的角度,深入分析这两个框架在实际应用中的差异,为开发者提供客观的技术参考。
42 7
|
2月前
|
机器学习/深度学习 算法 PyTorch
深度学习笔记(十三):IOU、GIOU、DIOU、CIOU、EIOU、Focal EIOU、alpha IOU、SIOU、WIOU损失函数分析及Pytorch实现
这篇文章详细介绍了多种用于目标检测任务中的边界框回归损失函数,包括IOU、GIOU、DIOU、CIOU、EIOU、Focal EIOU、alpha IOU、SIOU和WIOU,并提供了它们的Pytorch实现代码。
230 1
深度学习笔记(十三):IOU、GIOU、DIOU、CIOU、EIOU、Focal EIOU、alpha IOU、SIOU、WIOU损失函数分析及Pytorch实现
|
3月前
|
机器学习/深度学习 PyTorch 调度
在Pytorch中为不同层设置不同学习率来提升性能,优化深度学习模型
在深度学习中,学习率作为关键超参数对模型收敛速度和性能至关重要。传统方法采用统一学习率,但研究表明为不同层设置差异化学习率能显著提升性能。本文探讨了这一策略的理论基础及PyTorch实现方法,包括模型定义、参数分组、优化器配置及训练流程。通过示例展示了如何为ResNet18设置不同层的学习率,并介绍了渐进式解冻和层适应学习率等高级技巧,帮助研究者更好地优化模型训练。
182 4
在Pytorch中为不同层设置不同学习率来提升性能,优化深度学习模型
|
2月前
|
机器学习/深度学习 算法 数据可视化
如果你的PyTorch优化器效果欠佳,试试这4种深度学习中的高级优化技术吧
在深度学习领域,优化器的选择对模型性能至关重要。尽管PyTorch中的标准优化器如SGD、Adam和AdamW被广泛应用,但在某些复杂优化问题中,这些方法未必是最优选择。本文介绍了四种高级优化技术:序列最小二乘规划(SLSQP)、粒子群优化(PSO)、协方差矩阵自适应进化策略(CMA-ES)和模拟退火(SA)。这些方法具备无梯度优化、仅需前向传播及全局优化能力等优点,尤其适合非可微操作和参数数量较少的情况。通过实验对比发现,对于特定问题,非传统优化方法可能比标准梯度下降算法表现更好。文章详细描述了这些优化技术的实现过程及结果分析,并提出了未来的研究方向。
33 1
|
2月前
|
机器学习/深度学习 编解码
深度学习笔记(三):神经网络之九种激活函数Sigmoid、tanh、ReLU、ReLU6、Leaky Relu、ELU、Swish、Mish、Softmax详解
本文介绍了九种常用的神经网络激活函数:Sigmoid、tanh、ReLU、ReLU6、Leaky ReLU、ELU、Swish、Mish和Softmax,包括它们的定义、图像、优缺点以及在深度学习中的应用和代码实现。
150 0
深度学习笔记(三):神经网络之九种激活函数Sigmoid、tanh、ReLU、ReLU6、Leaky Relu、ELU、Swish、Mish、Softmax详解
|
2月前
|
机器学习/深度学习 PyTorch 算法框架/工具
深度学习入门案例:运用神经网络实现价格分类
深度学习入门案例:运用神经网络实现价格分类
|
3月前
|
机器学习/深度学习 人工智能 自然语言处理
软件工程师,入门下深度学习吧
软件工程师,入门下深度学习吧
60 9