当前位置: 首页 > news >正文

【PyTorch】softmax回归

文章目录

  • 1.理论介绍
  • 2. 代码实现
    • 2.1. 主要代码
    • 2.2. 完整代码
    • 2.3. 输出结果
  • 3. Q&A
    • 3.1. 运行过程中出现以下警告:
    • 3.2. 定义的神经网络中的nn.Flatten()的作用是什么?
    • 3.3. num_workers有什么作用?它的值怎么确定?

1.理论介绍

  • 背景
    在分类问题中,模型的输出层是全连接层,每个类别对应一个输出。我们希望模型的输出 y ^ j \hat{y}_j y^j可以视为属于类 j j j的概率,然后选择具有最大输出值的类别作为我们的预测。
    softmax函数能够将未规范化的输出变换为非负数并且总和为1,同时让模型保持可导的性质,而且不会改变未规范化的输出之间的大小次序。
  • softmax函数
    y ^ = s o f t m a x ( o ) \mathbf{\hat{y}}=\mathrm{softmax}(\mathbf{o}) y^=softmax(o)其中 y ^ j = e x p ( o j ) ∑ k e x p ( o k ) \hat{y}_j=\frac{\mathrm{exp}({o_j})}{\sum_{k}\mathrm{exp}({o_k})} y^j=kexp(ok)exp(oj)
  • softmax是一个非线性函数,但softmax回归的输出仍然由输入特征的仿射变换决定,因此,softmax回归是一个线性模型
  • 为了避免将softmax的输出直接送入交叉熵损失造成的数值稳定性问题,需要将softmax和交叉熵损失结合在一起,具体做法是:不将softmax概率传递到损失函数中, 而是在交叉熵损失函数中传递未规范化的输出,并同时计算softmax及其对数。因此定义交叉熵损失函数时也进行了softmax运算

2. 代码实现

2.1. 主要代码

criterion = nn.CrossEntropyLoss(reduction='none')

2.2. 完整代码

import torch
from torchvision.datasets import FashionMNIST
from torchvision import transforms
from torch.utils.data import DataLoader
from torch import nn
from tensorboardX import SummaryWriterdef load_dataset(batch_size, num_workers):"""加载数据集"""root = "./dataset"transform = transforms.Compose([transforms.ToTensor()])mnist_train = FashionMNIST(root=root, train=True, transform=transform, download=True)mnist_test = FashionMNIST(root=root, train=False, transform=transform, download=True)dataloader_train = DataLoader(mnist_train, batch_size, shuffle=True, num_workers=num_workers)dataloader_test = DataLoader(mnist_test, batch_size, shuffle=False,num_workers=num_workers)return dataloader_train, dataloader_testdef init_network(net):"""初始化模型参数"""def init_weights(m):if type(m) == nn.Linear:nn.init.normal_(m.weight, mean=0, std=0.01)nn.init.constant_(m.bias, val=0)if isinstance(net, nn.Module):net.apply(init_weights)class Accumulator:"""在n个变量上累加"""def __init__(self, n):self.data = [0.0] * ndef add(self, *args):self.data = [a + float(b) for a, b in zip(self.data, args)]def reset(self):self.data = [0.0] * len(self.data)def __getitem__(self, idx):return self.data[idx]def accuracy(y_hat, y):"""计算预测正确的数量"""if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:y_hat = y_hat.argmax(axis=1)cmp = y_hat.type(y.dtype) == yreturn float(cmp.type(y.dtype).sum())def train(net, dataloader_train, criterion, optimizer, device):"""训练模型"""if isinstance(net, nn.Module):net.train()train_metrics = Accumulator(3)  # 训练损失总和、训练准确度总和、样本数for X, y in dataloader_train:X, y = X.to(device), y.to(device)y_hat = net(X)loss = criterion(y_hat, y)optimizer.zero_grad()loss.mean().backward()optimizer.step()train_metrics.add(float(loss.sum()), accuracy(y_hat, y), y.numel())train_loss = train_metrics[0] / train_metrics[2]train_acc = train_metrics[1] / train_metrics[2]return train_loss, train_accdef test(net, dataloader_test, device):"""测试模型"""if isinstance(net, nn.Module):net.eval()with torch.no_grad():    test_metrics = Accumulator(2)   # 测试准确度总和、样本数for X, y in dataloader_test:X, y = X.to(device), y.to(device)y_hat = net(X)test_metrics.add(accuracy(y_hat, y), y.numel())test_acc = test_metrics[0] / test_metrics[1]return test_accif __name__ == "__main__":# 全局参数设置batch_size = 256num_workers = 3num_epochs = 20learning_rate = 0.1device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')# 创建记录器writer = SummaryWriter()# 加载数据集dataloader_train, dataloader_test = load_dataset(batch_size, num_workers)# 定义神经网络net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10)).to(device)# 初始化神经网络init_network(net)# 定义损失函数criterion = nn.CrossEntropyLoss(reduction='none')# 定义优化器optimizer = torch.optim.SGD(net.parameters(), lr=learning_rate)for epoch in range(num_epochs):train_loss, train_acc = train(net, dataloader_train, criterion, optimizer, device)test_acc = test(net, dataloader_test, device)writer.add_scalars("metrics", {'train_loss': train_loss, 'train_acc': train_acc, 'test_acc': test_acc}, epoch)writer.close()   

2.3. 输出结果

softmax回归

3. Q&A

3.1. 运行过程中出现以下警告:

UserWarning: The given NumPy array is not writeable, and PyTorch does not support non-writeable tensors. This means you can write to the underlying (supposedly non-writeable) NumPy array using the tensor. You may want to copy the array to protect its data or make it writeable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at …\torch\csrc\utils\tensor_numpy.cpp:180.)
return torch.from_numpy(parsed.astype(m[2], copy=False)).view(*s)

该警告的大致意思是给定的NumPy数组不可写,并且PyTorch不支持不可写的张量。这意味着你可以使用张量写入底层(假定不可写)NumPy数组。在将数组转换为张量之前,可能需要复制数组以保护其数据或使其可写。在本程序的其余部分,此类警告将被抑制。因此需要修改C:\Users\%UserName%\anaconda3\envs\%conda_env_name%\lib\site-packages\torchvision\datasets\mnist.py的第498行,将return torch.from_numpy(parsed.astype(m[2], copy=False)).view(*s)中的False改成True

3.2. 定义的神经网络中的nn.Flatten()的作用是什么?

net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10)).to(device)

nn.Flatten()的作用是将图像数据张量展成一维,方便输入后续的全连接层。

3.3. num_workers有什么作用?它的值怎么确定?

num_workers表示加载batch数据的进程数,num_workers=0时只有主进程去加载batch数据。要实现多进程加载数据,加载函数一定要位于if __name__ == "__main__"下。一般开始是将num_workers设置为等于计算机上的CPU内核数量,在此基础上,尝试减少num_workers的值,选择训练速度高时的值。查看CPU内核数量的方法:“任务管理器 > 性能 > CPU”。
CPU内核数

http://www.lryc.cn/news/256899.html

相关文章:

  • 12.8 作业 C++
  • 10.机器人系统仿真(urdf集成gazebo、rviz)
  • 城市基础设施智慧路灯改造的特点
  • 配置BFD多跳检测示例
  • 爬虫学习-基础库的使用(requests)
  • 4.8 构建onnx结构模型-Less
  • Java调试技巧之垃圾回收机制解析
  • logstash插件简单介绍
  • 联邦多任务蒸馏助力多接入边缘计算下的个性化服务 | TPDS 2023
  • 【python爬虫】设计自己的爬虫 3. 文件数据保存封装
  • pta模拟题——7-34 刮刮彩票
  • 【补题】 1
  • IP地址定位技术为网络安全建设提供全新方案
  • Redis中HyperLogLog的使用
  • 新版Spring Security6.2架构 (一)
  • 名字的漂亮度
  • 机器学习基本概念2
  • Spring Cloud 与微服务学习总结(19)—— Spring Cloud Alibaba 之 Nacos 2.3.0 史上最大更新版本发布
  • 八、C#笔记
  • 利用Node.js和cpolar实现远程访问,无需公网IP和路由器设置的完美解决方案
  • C++如何通过调用ffmpeg接口对H264文件进行编码和解码
  • 使用MetaMask + Ganache搭建本地私有网络并实现合约部署与互动
  • 目标检测、目标跟踪、重识别
  • 高防IP防御效果怎么样,和VPN有区别吗
  • 探秘MSSQL存储过程:功能、用法及实战案例
  • 我们常说的流应用到底是什么?
  • ELK 日志解决方案
  • 本项目基于Spring boot的AMQP模块,整合流行的开源消息队列中间件rabbitMQ,实现一个向rabbitMQ
  • freeswitch webrtc video_demo客户端进行MCU的视频会议
  • 【鸿蒙学习网络】