
本教程旨在解决pytorch模型训练后性能低于随机猜测的常见问题。文章通过分析一个具体的分类任务代码,揭示了模型评估阶段常见的准确率累加错误,并提供了正确的实现方法。同时,还探讨了输入数据处理、标签格式、数据集划分等可能导致模型训练无效的其他潜在陷阱,帮助开发者构建健壮、高效的pytorch训练流程。
在深度学习模型的开发过程中,开发者有时会遇到模型训练效果不佳,甚至其性能比随机猜测还要差的情况。这种问题往往令人困惑,尤其是在尝试调整了学习率、批次大小、网络层数等常见超参数后依然无法改善时。本文将通过一个具体的PyTorch分类模型案例,深入剖析导致模型无法有效学习的常见原因,并提供相应的解决方案和最佳实践。
案例分析:一个PyTorch分类模型
我们来看一个典型的PyTorch分类模型代码结构。该模型旨在对SDSS.csv数据集进行分类。代码包括自定义数据集(SDSS和testSDSS)、数据加载器(DataLoader)、一个简单的全连接神经网络(NeuralNet)、训练循环和评估循环。
核心问题概述:
原始代码在数百个epoch后,模型的准确率仍然低于随机猜测。经过仔细排查,我们发现主要问题出在模型评估阶段的准确率计算逻辑上,同时存在其他潜在的数据处理和数据集使用问题。
核心问题:准确率计算的陷阱
在模型评估阶段,一个常见的错误是未能正确累加每个批次的正确预测数量。原始代码中的评估循环片段如下:
with torch.no_grad():
n_correct = 0
n_samples = 0
for inputs, labels in test_loader:
labels = labels.to(device)
outputs = model(inputs)
# ... 其他处理 ...
_, predictions = torch.max(outputs, 1)
n_samples += labels.shape[0]
# 错误:n_correct在每次迭代中被重置
n_correct = (predictions == labels).sum().item()
acc = 100 * n_correct / n_samples
print(f'accuracy = {acc}')问题分析:
在上述代码中,n_correct = (predictions == labels).sum().item() 这一行位于test_loader的循环内部。这意味着在每次处理一个新的批次时,n_correct都会被重新赋值为当前批次的正确预测数,而不是在之前批次的基础上进行累加。因此,最终计算出的acc只反映了最后一个批次的准确率,而非整个测试集的准确率。这导致了模型性能评估的严重偏差。
解决方案:
要正确累加所有批次的正确预测数,应将赋值操作改为累加操作:
n_correct += (predictions == labels).sum().item()
修改后的评估循环片段:
# ... (其他代码) ...
#test
with torch.no_grad():
n_correct = 0 # 初始化总的正确预测数
n_samples = 0 # 初始化总样本数
for inputs, labels in test_loader:
inputs = inputs.to(device) # 将输入数据移动到设备
labels = labels.to(device) # 将标签移动到设备
outputs = model(inputs)
_, predictions = torch.max(outputs.data, 1) # 获取预测结果的类别索引
n_samples += labels.shape[0] # 累加当前批次的样本数
n_correct += (predictions == labels).sum().item() # 正确:累加当前批次的正确预测数
acc = 100 * n_correct / n_samples
print(f'Accuracy of the model on the test samples: {acc:.2f}%')通过这一简单的修改,n_correct将正确地累加所有批次的预测结果,从而得到整个测试集上的真实准确率。
潜在的输入数据处理问题
除了上述的准确率计算错误,原始代码在训练和测试循环中还存在对输入数据inputs进行torch.flatten(inputs)的操作:
# 训练循环中 outputs = model(inputs) inputs = torch.flatten(inputs) # 潜在问题 labels = torch.flatten(labels) loss = criterion(outputs, labels.long()) # 测试循环中 outputs = model(inputs) inputs = torch.flatten(inputs) # 潜在问题 labels = torch.flatten(labels)
问题分析:
NeuralNet模型定义如下:
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 outnn.Linear(input_size, hidden_size)期望的输入形状是 [batch_size, input_size]。如果inputs已经是 [batch_size, input_size] 的形状,那么对其进行 torch.flatten(inputs) 操作会将其展平为 [batch_size * input_size]。这将导致后续模型调用 model(inputs) 时,输入维度与 self.l1 层期望的 input_size 不匹配,从而引发运行时错误或不正确的计算。
PatentPal专利申请写作
AI软件来为专利申请自动生成内容
274
查看详情
通常,torch.flatten()用于将多维张量(例如图像的 [batch_size, channels, height, width])展平为适合全连接层的二维张量([batch_size, channels * height * width])。对于表格数据,如果DataLoader已经提供了 [batch_size, num_features] 的形状,则无需再次展平。
解决方案:
移除训练和测试循环中对inputs的flatten操作:
# 训练循环中 outputs = model(inputs) # 直接将inputs传入模型 labels = labels.flatten() # 标签仍需要展平为 [batch_size] loss = criterion(outputs, labels.long()) # 测试循环中 outputs = model(inputs) # 直接将inputs传入模型 labels = labels.flatten() # 标签仍需要展平为 [batch_size]
数据集划分与评估的考量
原始代码中定义了两个数据集类SDSS和testSDSS,它们是完全相同的,并且都加载了完整的SDSS.csv文件。
class SDSS(Dataset):
# ... 加载SDSS.csv ...
class testSDSS(Dataset):
# ... 加载SDSS.csv ...
dataset = SDSS()
test_dataset = testSDSS()问题分析:
这意味着模型在训练和测试阶段都使用了相同的数据集。这种做法被称为“在训练数据上进行测试”,会导致模型性能评估的严重偏差。模型会记住训练数据中的模式,而不是学习泛化能力,从而在训练集上表现良好(甚至过拟合),但在未见过的新数据上表现糟糕。
解决方案:
为了获得对模型泛化能力的可靠评估,必须将数据集划分为独立的训练集、验证集和测试集。
from torch.utils.data import random_split # 假设SDSS数据集已经加载 full_dataset = SDSS() # 假设SDSS类可以加载整个数据集 # 定义训练集和测试集的比例 train_size = int(0.8 * len(full_dataset)) test_size = len(full_dataset) - train_size # 使用random_split进行划分 train_dataset, test_dataset = random_split(full_dataset, [train_size, test_size]) # 然后创建各自的DataLoader data_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True, num_workers=0) test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False, num_workers=0)
PyTorch CrossEntropyLoss与标签格式
nn.CrossEntropyLoss是PyTorch中用于多类别分类任务的常用损失函数。它内部集成了LogSoftmax和NLLLoss。
关键点:
- 模型输出: CrossEntropyLoss期望模型的输出是原始的logits(即未经过Softmax激活函数处理的输出)。如果模型最后一层已经应用了Softmax,则会导致错误的损失计算。原始代码中的NeuralNet模型最后一层是nn.Linear,输出原始logits,这是正确的。
- 标签格式: CrossEntropyLoss期望的标签是类别索引,形状为 [batch_size],数据类型为 torch.long。原始代码中y_data的形状是 [n_samples, 1],通过 labels = labels.flatten() 和 labels.long() 处理后,可以满足要求。
优化与最佳实践
综合以上分析和解决方案,以下是修正后的关键代码片段和一些最佳实践建议。
修正后的训练循环和评估循环示例:
# ... (deviceconfig, model definition, optimizer, criterion等不变) ... # 假设已经正确划分了train_dataset和test_dataset # 并创建了data_loader (for train) 和 test_loader (for evaluation) # 训练循环 n_total_steps = len(data_loader) # 修正:应为数据加载器的批次总数 for epoch in range(num_epochs): model.train() # 设置模型为训练模式 for i, (inputs, labels) in enumerate(data_loader): inputs = inputs.to(device) labels = labels.to(device) # Forward pass outputs = model(inputs) labels = labels.flatten() # 确保标签形状为 [batch_size] loss = criterion(outputs, labels.long()) # Backward and optimize optimizer.zero_grad() loss.backward() optimizer.step() if (i+1) % 100 == 0: print(f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{n_total_steps}], Loss: {loss.item():.4f}') # 测试/评估循环 with torch.no_grad(): model.eval() # 设置模型为评估模式 n_correct = 0 n_samples = 0 for inputs, labels in test_loader: inputs = inputs.to(device) labels = labels.to(device) outputs = model(inputs) labels = labels.flatten() # 确保标签形状为 [batch_size] # max returns (value, index) _, predictions = torch.max(outputs.data, 1) n_samples += labels.size(0) n_correct += (predictions == labels).sum().item() acc = 100.0 * n_correct / n_samples print(f'Accuracy of the model on the test dataset: {acc:.2f}%')
调试建议:
- 检查数据形状 (.shape): 在模型的不同阶段(数据加载后、进入模型前、模型输出后),打印张量的形状,确保它们符合预期。这是排查维度不匹配错误最有效的方法。
- 监控损失值: 观察训练过程中损失值的变化。如果损失值没有持续下降,或者波动剧烈,可能意味着学习率过高、模型结构不当或数据存在问题。
- 验证标签分布: 确保数据集中的类别分布是合理的。如果存在严重的类别不平衡,可能会导致模型偏向于预测多数类别。
- 从小规模数据开始: 在调试复杂模型时,可以先使用一个非常小的数据集(甚至只有几个样本)进行训练,验证模型是否能过拟合这些少量数据。如果连小规模数据都无法过拟合,说明模型或训练流程存在根本性问题。
- 使用GPU(如果可用): 将计算转移到GPU可以显著加速训练过程,尤其对于大型模型和数据集。
总结
模型训练效果不佳往往不是单一原因造成的,而是多个小问题累积的结果。本文通过一个具体的PyTorch案例,强调了在模型评估阶段正确累加指标的重要性,指出了输入数据处理中flatten操作的潜在误用,并重申了数据集划分对于获得可靠模型评估的关键作用。通过遵循这些最佳实践和调试技巧,开发者可以更有效地识别和解决PyTorch模型训练中的问题,从而构建出性能更优、泛化能力更强的深度学习模型。
以上就是PyTorch模型训练效果不佳?深入剖析常见错误与调试技巧的详细内容,更多请关注其它相关文章!
# 如何用
# seo sem 新媒体哪个好
# 湛江网站建设需要什么
# 范县网站建设在哪里
# 咖啡专卖店设计营销推广
# 重庆可靠网站推广公司
# WP怎样优化SEO
# 网站运行优化报告模板
# 做过SEO优化的网站
# 嘉兴网站建设品牌优化
# 双十一营销推广广告语大全
# 不匹配
# 过程中
# 多维
# 如何将
# git
# 是在
# 这是
# 数据处理
# 专利申请
# 加载
# red
# csv文件
# 常见问题
# pytorch
# 深度学习
# 神经网络
# ai
# csv
相关栏目:
【
企业资讯168 】
【
行业动态20933 】
【
网络营销52431 】
【
网络学院91036 】
【
运营推广7012 】
【
科技资讯60970 】
相关推荐:
C++指针和引用有什么区别_C++内存管理核心概念深度解析
mcjs网页版在线存档 mcjs云存档登录入口
QQ邮箱登录平台入口 QQ邮箱网页版邮箱官方入口
Python模块化编程:有效管理依赖与避免循环引用
如何在 Excel Online 和 Google 表格中更改日期格式
漫画星球免费下拉式入口 漫画星球免费漫画在线阅读网站
在J*a中如何开发简易电子商务商品管理系统_商品管理系统项目实战解析
mc.js官网登录入口 mc.js官方登录入口最新版
不同用户不同价格! 索尼开启账户个性化定价测试
虚幻5科幻题材ARPG大作遭取消!本是《奇异人生》厂商新作
谷歌google账号注册详细步骤 谷歌账号注册官方教程
实现分段式页面滚动导航:CSS与J*aScript教程
海量存储:机器视觉智能化的核心基石
win11 Snap Layouts怎么用 Win11窗口布局与分屏多任务高效指南【必学】
C++如何使用AddressSanitizer(ASan)_C++调试工具中检测内存访问错误的利器
蛙漫安全无毒 官方认证的绿色入口
Win11怎么隐藏桌面图标 Win11一键隐藏所有桌面元素及恢复显示
铁路12306官网网页端快速入口 铁路12306官方首页登录教程
sublime如何配置Python开发环境_将sublime打造成轻量级Python IDE
PyTorch模型训练效果不佳?深入剖析常见错误与调试技巧
iCloud登录入口网页版 苹果iCloud官网登录
HTML空白字符处理机制:渲染、DOM与编码实践
如何在离线环境中使用Composer_Composer离线安装依赖包的技巧与策略
妖精动漫免费平台 妖精动漫官网资源观看网址
Django AJAX 文件上传教程:解决图片无法保存到模型的常见问题
Win11怎么合并任务栏图标 Win11开启任务栏合并减少图标占空间【方法】
抖音网页版平台入口 抖音网页版官网在线访问教程
优化 Jest 模拟:强制未实现函数抛出错误以提升测试效率
荣耀Play7T运行卡顿解决_荣耀Play7T性能优化
Win11怎么设置开机NumLock亮 Win11修改注册表InitialKeyboardIndicators值
印象笔记如何设离线包出差查阅_印象笔记设离线包出差查阅【离线阅读】
消息称三星明年 2 月正式发布 HBM4,与 SK 海力士同台竞技
韩小圈电脑版在线入口_网页版免费登录地址
Composer的 archive 命令怎么用_快速打包你的PHP项目及其Composer依赖
将HTML动态表格多行数据保存到Google Sheet的教程
Golang如何使用const iota_Go iota常量计数器讲解
深入理解字体排版:Adobe光学字偶距与CSS字偶距的差异与实现
Windows10怎么开启夜间模式 Windows10系统设置调整色温与亮度缓解夜间用眼疲劳【教程】
顺丰国际快递查询 国际件官方查询入口
J*aScript动态调整元素颜色:基于背景亮度智能切换文本与按钮样式
Golang如何实现微服务鉴权与权限控制_Golang微服务鉴权与权限管理实践
C++ string find函数返回值npos详解_C++字符串查找失败的判断条件
Windows 11怎么更改用户头像_Windows 11账户设置修改个人资料图片
Win11怎么开启高性能模式_Windows 11电源计划优化设置
uc手机浏览器网页版入口 uc浏览器手机版便捷登录首页
三星GalaxyS24怎样用相机拍摄夜景流光_iPhoneGalaxyS24相机拍摄夜景流光【夜拍技法】
Excel文件在线转换快速入口 Excel在线格式转换网站
c++中的std::forward_list和std::list有什么不同_c++ forward_list与list区别分析
小红书商家版怎样在笔记嵌入商品卡路径_小红书商家版在笔记嵌入商品卡路径【挂载教程】
理解J*aScript Promise的微任务队列与执行顺序


config, model definition, optimizer, criterion等不变) ...
# 假设已经正确划分了train_dataset和test_dataset
# 并创建了data_loader (for train) 和 test_loader (for evaluation)
# 训练循环
n_total_steps = len(data_loader) # 修正:应为数据加载器的批次总数
for epoch in range(num_epochs):
model.train() # 设置模型为训练模式
for i, (inputs, labels) in enumerate(data_loader):
inputs = inputs.to(device)
labels = labels.to(device)
# Forward pass
outputs = model(inputs)
labels = labels.flatten() # 确保标签形状为 [batch_size]
loss = criterion(outputs, labels.long())
# Backward and optimize
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (i+1) % 100 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{n_total_steps}], Loss: {loss.item():.4f}')
# 测试/评估循环
with torch.no_grad():
model.eval() # 设置模型为评估模式
n_correct = 0
n_samples = 0
for inputs, labels in test_loader:
inputs = inputs.to(device)
labels = labels.to(device)
outputs = model(inputs)
labels = labels.flatten() # 确保标签形状为 [batch_size]
# max returns (value, index)
_, predictions = torch.max(outputs.data, 1)
n_samples += labels.size(0)
n_correct += (predictions == labels).sum().item()
acc = 100.0 * n_correct / n_samples
print(f'Accuracy of the model on the test dataset: {acc:.2f}%')