新闻中心
解决PyTorch模型训练准确率不佳的问题:深入理解评估逻辑

本文旨在解决pytorch模型训练后准确率无法提升,甚至低于随机猜测的常见问题。文章将深入分析导致此问题的一个关键评估逻辑错误——即在测试循环中未正确累计预测结果,并提供详细的解决方案与pytorch模型评估的最佳实践,旨在帮助开发者构建更健壮、准确的机器学习模型。
引言
在深度学习模型开发过程中,我们经常会遇到模型训练效果不理想的情况,例如经过数百个 Epoch 后,模型的准确率仍然停滞不前,甚至低于随机猜测。这往往令人困惑,因为我们可能已经尝试调整了批量大小、网络层数、学习率等超参数。然而,有时问题的根源并非出在模型结构或训练参数上,而是隐藏在模型评估的逻辑中。本文将通过一个具体的案例,详细剖析这种常见的评估错误,并提供一套完善的解决方案和最佳实践。
问题诊断与代码分析
我们来看一个典型的PyTorch分类模型训练与评估代码示例,该模型旨在对SDSS数据集进行三分类。
import torch
import torch.nn as nn
import numpy as np
from torch.utils.data import Dataset, DataLoader
import torch.optim
# ... (device config, hyperparams, SDSS Dataset classes) ...
class NeuralNet(nn.Module):
def __init__(self, input_size, hidden_size, num_classes):
super(NeuralNet,self).__init__()
self.l1 = nn.Linear(input_size, hidden_size)
self.relu = nn.LeakyReLU()
self.l2 = nn.Linear(hidden_size, num_classes)
def forward(self, x):
out = self.l1(x)
out = self.relu(out)
out = self.l2(out)
return out
model = NeuralNet(input_size, hidden_size, num_classes)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
# ... (training loop) ...
# Test loop (problematic part)
with torch.no_grad():
n_correct = 0 # 初始化正确预测数
n_samples = 0 # 初始化样本总数
for inputs, labels in test_loader:
labels = labels.to(device)
outputs = model(inputs)
# inputs = torch.flatten(inputs) # 此行在模型前向传播后,不影响计算,但冗余
labels = torch.flatten(labels) # 将标签从 [batch_size, 1] 转换为 [batch_size]
_, predictions = torch.max(outputs, 1) # 获取预测类别
n_samples += labels.shape[0] # 累计样本总数
n_correct = (predictions == labels).sum().item() # 错误:每次循环都重新赋值,而非累计
acc = 100 * n_correct / n_samples
print(f'accuracy = {acc}')在上述代码中,模型训练过程看似正常,但在测试(评估)阶段,计算准确率的逻辑存在一个关键性错误。
-
错误的核心:n_correct 的赋值问题 在测试循环内部,计算每个批次正确预测数量的代码是:
n_correct = (predictions == labels).sum().item()
这里使用了赋值操作符 =,这意味着在每次迭代中,n_correct 都会被当前批次的正确预测数 覆盖,而不是与之前批次的正确预测数 累加。因此,最终 n_correct 的值将仅仅是 最后一个批次 的正确预测数,而非整个测试集上的总和。由于 n_samples 是正确累加的,这会导致计算出的准确率极低,甚至低于随机猜测,因为它只反映了测试集中一小部分数据的表现。
冗余操作:inputs = torch.flatten(inputs) 在训练和测试循环中,都存在一行 inputs = torch.flatten(inputs)。由于这行代码在 outputs = model(inputs) 之后执行,它不会影响模型的前向传播,因为模型已经接收了原始形状的 inputs。虽然它不会直接导致准确率问题,但它是冗余代码,可能引起混淆。对于 nn.Linear 层,它期望输入是 (batch_size, input_features) 的形状,如果 inputs 的原始形状就是 (batch_size, input_size),则无需进行 flatten 操作。
解决方案
解决上述问题的关键在于正确地累计 n_correct。只需将 = 赋值操作符替换为 += 累加操作符即可。
# Test loop (corrected part) with torch.no_grad(): n_correct = 0 n_samples = 0 for inputs, labels in test_loader: labels = labels.to(device) outputs = model(inputs) labels = torch.flatten(labels) # 保持标签形状转换,以适应CrossEntropyLoss _, predictions = torch.max(outputs, 1) n_samples += labels.shape[0] # 修正:将赋值操作改为累加操作 n_correct += (predictions == labels).sum().item() acc = 100 * n_correct / n_samples print(f'accuracy = {acc}')
通过这一简单的修改,n_correct 将正确地累加整个测试集中的正确预测数,从而计算出真实的模型准确率。
PyTorch模型评估最佳实践
为了避免类似的评估错误并确保模型性能的准确反映,以下是一些PyTorch模型评估的最佳实践:
-
正确累计评估指标
Muse AI
下一代无广告视频托管平台
125
查看详情
- 累加求和: 任何需要跨批次累计的指标(如正确预测数、损失总和等),都应使用 += 操作符进行累加,而不是简单的 = 赋值。
- 平均值计算: 对于需要计算平均值的指标,应在所有批次处理完毕后,用总和除以总样本数(或总批次计数)。
-
使用 torch.no_grad()
- 在模型评估或推理阶段,务必使用 with torch.no_grad(): 上下文管理器。这会禁用梯度计算,从而减少内存消耗并加速计算,因为我们不需要在评估时进行反向传播。
-
模型切换到评估模式
- 调用 model.eval()。这会将模型中的特定层(如 nn.Dropout 或 nn.BatchNorm)切换到评估模式。在评估模式下,Dropout 层会失效,BatchNorm 层会使用训练期间学习到的全局均值和方差,而不是当前批次的统计信息。
- 在评估结束后,如果需要继续训练,记得调用 model.train() 切换回训练模式。
-
数据预处理与标签处理
- 标签维度: 对于多类别分类问题,nn.CrossEntropyLoss 通常期望 outputs 的形状为 (N, C)(N为批量大小,C为类别数),而 labels 的形状为 (N),其中 labels 包含每个样本的类别索引。如果原始标签是 (N, 1),需要使用 squeeze() 或 flatten() 方法将其转换为 (N)。
- 数据归一化: 确保训练集和测试集使用相同的预处理(如归一化、标准化),以保证数据分布的一致性。
-
超参数与模型结构
- 虽然本文的重点是评估逻辑,但超参数(如学习率、批量大小、优化器选择)和模型结构(层数、激活函数)仍然是影响模型性能的关键因素。在确认评估逻辑无误后,应系统地调整这些参数以优化模型表现。
-
训练集、验证集和测试集划分
- 将数据集划分为独立的训练集、验证集和测试集是标准实践。训练集用于模型学习参数,验证集用于调整超参数和进行模型选择,测试集则用于对最终模型性能进行无偏估计。在示例代码中,SDSS 和 testSDSS 类加载的是相同的数据,这意味着训练集和测试集是重复的,这在实际应用中会导致对模型泛化能力的乐观估计。正确的做法是,从原始数据中划分出互不重叠的训练集和测试集。
总结
模型训练准确率不佳,甚至低于随机猜测,不总是意味着模型或超参数的选择有误。有时,问题可能出在看似微小的评估逻辑细节上。本文通过一个具体的案例,揭示了在PyTorch模型评估中,n_correct 变量未正确累计的常见错误,并提供了修正方案。同时,我们强调了PyTorch模型评估的最佳实践,包括正确累计指标、使用 torch.no_grad() 和 model.eval(),以及注意数据和标签的预处理。通过对这些细节的关注和实践,开发者可以更准确地评估模型性能,从而构建出更可靠、高效的深度学习模型。
以上就是解决PyTorch模型训练准确率不佳的问题:深入理解评估逻辑的详细内容,更多请关注其它相关文章!
# 深度学习
# seo与mcn
# 医药营销推广方式
# 遵义网络seo推广优化
# 长沙网站推广工作怎么样
# SEO赚钱壁纸动漫
# 十堰全网推广营销招聘
# 切换到
# 正确地
# 出在
# 一键
# 如何使用
# 转换为
# 而非
# 自动识别
# 而不是
# 这会
# red
# 常见问题
# pytorch
# ai
# 应城营销型网站建设开发
# 网站推广靠谱么
# 社交网站推广
# 浙江关键词快速排名
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
《明末:渊虚之羽》设计师谈设计角色:那会刚毕业 充满激情
凉拌黄瓜怎么拌更入味 凉拌黄瓜简单家常做法
如何在离线环境中使用Composer_Composer离线安装依赖包的技巧与策略
快速CSGO开箱网站指南 CSGO开箱平台推荐
2025AO3夸克浏览器通道_AO3手机HTTPS安全入口分享
漫蛙官网正版漫画入口 漫蛙2官方网页登录地址
Discord Slash 命令响应超时问题的异步解决方案
wps文字怎么插入目录并自动更新_wps文字如何插入目录并自动更新方法
PS5 Pro有点优势但不多! 《燕云十六声》PS5平台与PC性能画面对比
如何在网页中实现特定地点的随机图片展示
outlook中文官网入口地址 outlook官方中文版直达首页链接
解决Python logging 中 datefmt 导致时间戳固定不变的问题
怎样更改Windows系统的默认安装路径_避免C盘爆满的终极设置【技巧】
LINUX怎么设置定时任务_LINUX crontab配置教程
想当下一个《2077》?《心之眼》Steam评价升至"多半好评"
QQ邮箱官方网站登录入口_QQ邮箱网页版在线使用
谷歌邮箱网页版官方页面入口 谷歌邮箱网页端快速访问
J*aScript井字棋(Tic-Tac-Toe)核心交互逻辑实现教程
Golang切片为何属于引用类型_Golang slice底层结构与引用语义说明
基于动态规划的房屋花卉种植最小成本算法详解
《燕云十六声》两周内达九百万玩家!位居畅销榜第五
Windows10怎么开启夜间模式 Windows10系统设置调整色温与亮度缓解夜间用眼疲劳【教程】
淘宝支付提示失败如何解决 淘宝支付流程优化方法
在J*a中如何开发简易博客标签推荐系统_博客标签推荐项目实战解析
AO3同人作品网入口 AO3搜索引擎官网永久地址
《铁拳8》黑皮辣妹新实机:元气满满的18岁少女!
Odoo 16:在表单视图中基于当前记录动态修改Tree视图属性
html网页设计源代码怎么运行_运行html网页设计源代码步骤【指南】
c++20的std::jthread是什么_c++可中断线程与RAII式管理
Win11怎么关闭快速启动_Win11彻底关机设置教程
快手网页版在线登录 快手网页版官网入口快速访问
Lar*el如何生成PDF或Excel文件_Lar*el文档导出工具与使用教程
响应式图片在网页设计中的正确实现方法
J*a里如何实现线程安全的懒加载单例_懒加载单例实现方法解析
J*aScript实现动态背景色下的文本与按钮颜色自适应调整
2025-2030年全球乘用车销量预测:新能源成增长主力
Pandas DataFrame 多条件优先级排序与排名
CSS Flexbox如何实现多行排列_flex-wrap wrap自动换行显示
在VS Code中配置和运行Dart程序的完整步骤
搜狗浏览器如何使用密码生成器创建强密码 搜狗浏览器内置密码安全工具
MAC怎么安装Homebrew包管理器_MAC为开发者和高级用户安装命令行工具
QQ邮箱官方网页版登录 QQ邮箱个人邮箱快速访问
c++中的std::basic_string的SSO优化_c++短字符串优化深度解析
uc手机浏览器网页版入口 uc浏览器手机版便捷登录首页
在J*a中如何使用Stream.map转换元素_Stream映射操作解析
天猫双十一预售商品怎么退款_天猫双十一预售退款操作指南
曝R星经典之作开发图 设计简陋但信息密集!
c++项目目录结构应该如何组织_c++工程化项目结构规范
J*aScript Promise链中如何正确终止后续.then执行并处理错误
Composer如何处理Git子模块(submodule)依赖_Composer与Git Submodule的对比与选择


2025-12-02
浏览次数:次
返回列表
est loop (corrected part)
with torch.no_grad():
n_correct = 0
n_samples = 0
for inputs, labels in test_loader:
labels = labels.to(device)
outputs = model(inputs)
labels = torch.flatten(labels) # 保持标签形状转换,以适应CrossEntropyLoss
_, predictions = torch.max(outputs, 1)
n_samples += labels.shape[0]
# 修正:将赋值操作改为累加操作
n_correct += (predictions == labels).sum().item()
acc = 100 * n_correct / n_samples
print(f'accuracy = {acc}')