使用PyTorch时,最常见的4个错误(pytorch简单例子)
ztj100 2024-10-27 18:33 42 浏览 0 评论
作者:Yuval Greenfield
编译:ronghuaiyang
导读
这4个错误,我敢说大部分人都犯过,希望能给大家一点提醒。
最常见的神经网络错误:1)你没有首先尝试过拟合单个batch。2)你忘了为网络设置train/eval模式。3)在.backward()之前忘记了.zero_grad()(在pytorch中)。4)将softmaxed输出传递给了期望原始logits的损失,还有其他吗?
这篇文章将逐点分析这些错误是如何在PyTorch代码示例中体现出来的。代码:https://github.com/missinglinkai/common-nn-mistakes
常见错误 #1 你没有首先尝试过拟合单个batch
Andrej说我们应该过拟合单个batch。为什么?好吧,当你过拟合了单个batch —— 你实际上是在确保模型在工作。我不想在一个巨大的数据集上浪费了几个小时的训练时间,只是为了发现因为一个小错误,它只有50%的准确性。当你的模型完全记住输入时,你会得到的结果是对其最佳表现的很好的预测。
可能最佳表现为零,因为在执行过程中抛出了一个异常。但这没关系,因为我们很快就能发现问题并解决它。总结一下,为什么你应该从数据集的一个小子集开始过拟合:
- 发现bug
- 估计最佳的可能损失和准确率
- 快速迭代
在PyTorch数据集中,你通常在dataloader上迭代。你的第一个尝试可能是索引train_loader。
# TypeError: 'DataLoader' object does not support indexing
first_batch = train_loader[0]
你会立即看到一个错误,因为DataLoaders希望支持网络流和其他不需要索引的场景。所以没有__getitem__方法,这导致了[0]操作失败,然后你会尝试将其转换为list,这样就可以支持索引。
# slow, wasteful
first_batch = list(train_loader)[0]
但这意味着你要评估整个数据集这会消耗你的时间和内存。那么我们还能尝试什么呢?
在Python for循环中,当你输入如下:
for item in iterable:
do_stuff(item)
你有效地得到了这个:
iterator = iter(iterable)
try:
while True:
item = next(iterator)
do_stuff(item)
except StopIteration:
pass
调用“iter”函数来创建迭代器,然后在循环中多次调用该函数的“next”来获取下一个条目。直到我们完成时,StopIteration被触发。在这个循环中,我们只需要调用next, next, next… 。为了模拟这种行为但只获取第一项,我们可以使用这个:
first = next(iter(iterable))
我们调用“iter”来获得迭代器,但我们只调用“next”函数一次。注意,为了清楚起见,我将下一个结果分配到一个名为“first”的变量中。我把这叫做“next-iter” trick。在下面的代码中,你可以看到完整的train data loader的例子:
for batch_idx, (data, target) in enumerate(train_loader):
# training code here<br>
下面是如何修改这个循环来使用 first-iter trick :
first_batch = next(iter(train_loader))
for batch_idx, (data, target) in enumerate([first_batch] * 50):
# training code here
你可以看到我将“first_batch”乘以了50次,以确保我会过拟合。
常见错误 #2: 忘记为网络设置 train/eval 模式
为什么PyTorch关注我们是训练还是评估模型?最大的原因是dropout。这项技术在训练中随机去除神经元。
想象一下,如果右边的红色神经元是唯一促成正确结果的神经元。一旦我们移除红色神经元,它就迫使其他神经元训练和学习如何在没有红色的情况下保持准确。这种drop-out提高了最终测试的性能 —— 但它对训练期间的性能产生了负面影响,因为网络是不全的。在运行脚本并查看MissingLink dashobard的准确性时,请记住这一点。
在这个特定的例子中,似乎每50次迭代就会降低准确度。
如果我们检查一下代码 —— 我们看到确实在train函数中设置了训练模式。
def train(model, optimizer, epoch, train_loader, validation_loader):
model.train() # ????????????
for batch_idx, (data, target) in experiment.batch_loop(iterable=train_loader):
data, target = Variable(data), Variable(target)
# Inference
output = model(data)
loss_t = F.nll_loss(output, target)
# The iconic grad-back-step trio
optimizer.zero_grad()
loss_t.backward()
optimizer.step()
if batch_idx % args.log_interval == 0:
train_loss = loss_t.item()
train_accuracy = get_correct_count(output, target) * 100.0 / len(target)
experiment.add_metric(LOSS_METRIC, train_loss)
experiment.add_metric(ACC_METRIC, train_accuracy)
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx, len(train_loader),
100. * batch_idx / len(train_loader), train_loss))
with experiment.validation():
val_loss, val_accuracy = test(model, validation_loader) # ????????????
experiment.add_metric(LOSS_METRIC, val_loss)
experiment.add_metric(ACC_METRIC, val_accuracy)
这个问题不太容易注意到,在循环中我们调用了test函数。
def test(model, test_loader):
model.eval()
# ...
在test函数内部,我们将模式设置为eval!这意味着,如果我们在训练过程中调用了test函数,我们就会进eval模式,直到下一次train函数被调用。这就导致了每一个epoch中只有一个batch使用了drop-out ,这就导致了我们看到的性能下降。
修复很简单 —— 我们将model.train() 向下移动一行,让如训练循环中。理想的模式设置是尽可能接近推理步骤,以避免忘记设置它。修正后,我们的训练过程看起来更合理,没有中间的峰值出现。请注意,由于使用了drop-out ,训练准确性会低于验证准确性。
常用的错误 #3: 忘记在.backward()之前进行.zero_grad()
当在 “loss”张量上调用 “backward” 时,你是在告诉PyTorch从loss往回走,并计算每个权重对损失的影响有多少,也就是这是计算图中每个节点的梯度。使用这个梯度,我们可以最优地更新权值。
这是它在PyTorch代码中的样子。最后的“step”方法将根据“backward”步骤的结果更新权重。从这段代码中可能不明显的是,如果我们一直在很多个batch上这么做,梯度会爆炸,我们使用的step将不断变大。
output = model(input) # forward-pass
loss_fn.backward() # backward-pass
optimizer.step() # update weights by an ever growing gradient ????????????
为了避免step变得太大,我们使用 zero_grad 方法。
output = model(input) # forward-pass
optimizer.zero_grad() # reset gradient ????
loss_fn.backward() # backward-pass
optimizer.step() # update weights using a reasonably sized gradient ????
这可能感觉有点过于明显,但它确实赋予了对梯度的精确控制。有一种方法可以确保你没有搞混,那就是把这三个函数放在一起:
- zero_grad
- backward
- step
在我们的代码例子中,在完全不使用zero_grad的情况下。神经网络开始变得更好,因为它在改进,但梯度最终会爆炸,所有的更新变得越来越垃圾,直到网络最终变得无用。
调用backward之后再做zero_grad。什么也没有发生,因为我们擦掉了梯度,所以权重没有更新。剩下的唯一有变化的是dropout。
我认为在每次step方法被调用时自动重置梯度是有意义的。
在backward的时候不使用zero_grad的一个原因是,如果你每次调用step() 时都要多次调用backward,例如,如果你每个batch只能将一个样本放入内存中,那么一个梯度会噪声太大,你想要在每个step中聚合几个batch的梯度。另一个原因可能是在计算图的不同部分调用backward —— 但在这种情况下,你也可以把损失加起来,然后在总和上调用backward。
常见错误 #4: 你把做完softmax的结果送到了需要原始logits的损失函数中
logits是最后一个全连接层的激活值。softmax也是同样的激活值,但是经过了标准化。logits值,你可以看到有些是正的,一些是负的。而log_softmax之后的值,全是负值。如果看柱状图的话,可以看到分布式一样的,唯一的差别就是尺度,但就是这个细微的差别,导致最后的数学计算完全不一样了。但是为什么这是一个常见的错误呢?在PyTorch的官方MNIST例子中,查看forward 方法,在最后你可以看到最后一个全连接层self.fc2,然后就是log_softmax。
但是当你查看官方的PyTorch resnet或者AlexNet模型的时候,你会发现这些模型在最后并没有softmax层,最后得到就是全连接的输出,就是logits。
这两个的差别在文档中没有说的很清楚。如果你查看nll_loss函数,并没有提得输入是logits还是softmax,你的唯一希望是在示例代码中发现nll_loss使用了log_softmax作为输入。
更多内容,请关注微信公众号“AI公园”。
相关推荐
- Python 操作excel的坑__真实的行和列
-
大佬给的建议__如何快速处理excelopenpyxl库操作excel的时候,单个表的数据量大一些处理速度还能接受,如果涉及多个表甚至多个excel文件的时候速度会很慢,还是建议用pandas来处理,...
- Python os.path模块使用指南:轻松处理文件路径
-
前言在Python编程中,文件和目录的操作是非常重要的一部分。为了方便用户进行文件和目录的操作,Python标准库提供了os模块。其中,os.path子模块提供了一些处理文件路径的函数和方法。本文主要...
- Python常用内置模块介绍——文件与系统操作详解
-
Python提供了多个强大的内置模块用于文件和系统操作,下面我将详细介绍最常用的几个模块及其核心功能。1.os模块-操作系统交互...
- Python Flask 建站框架实操教程(flask框架网页)
-
下面我将带您从零开始构建一个完整的Flask网站,包含用户认证、数据库操作和前端模板等核心功能。##第一部分:基础项目搭建###1.创建项目环境```bash...
- 为你的python程序上锁:软件序列号生成器
-
序列号很多同学可能开发了非常多的程序了,并且进行了...
- PO设计模式全攻略,在 UI 自动化中的实践总结(以企业微信为例)
-
一、什么是PO设计模式?PO(PageObject)设计模式将某个页面的所有元素对象定位和对元素对象的操作封装成一个Page类,即一个py文件,并以页面为单位来写测试用例,实现页面对象和测试用例的...
- 这种小工具居然也能在某鱼卖钱?我用Python一天能写...
-
前两天在某鱼闲逛,本来想找个二手机械键盘,结果刷着刷着突然看到有人在卖——Word批量转PDF小工具...
- python打包成exe,程序有图标,但是任务栏和窗口都没有显示图标
-
代码中指定图标信息#设置应用ID,确保任务栏图标正确显示ifsys.platform=="win32":importctypesapp_id=...
- 使用Python构建电影推荐系统(用python做推荐系统)
-
在日常数据挖掘工作中,除了会涉及到使用Python处理分类或预测任务,有时候还会涉及推荐系统相关任务。...
- python爬取并分析淘宝商品信息(python爬取淘宝商品数据)
-
python爬取并分析淘宝商品信息背景介绍一、模拟登陆二、爬取商品信息1.定义相关参数2.分析并定义正则3.数据爬取三、简单数据分析1.导入库2.中文显示3.读取数据4.分析价格分布5.分析销售...
- OpenCV入门学习基础教程(从小白变大神)
-
Opencv是用于快速处理图像处理、计算机视觉问题的工具,支持多种语言进行开发如c++、python、java等,下面这篇文章主要给大家介绍了关于openCV入门学习基础教程的相关资料,需要的朋友可以...
- python图像处理-一行代码实现灰度图抠图
-
抠图是ps的最基本技能,利用python可以实现用一行代码实现灰度图抠图。基础算法是...
- 从头开始学python:如何用Matplotlib绘图表
-
Matplotlib是一个用于绘制图表的库。如果你有用过python处理数据,那Matplotlib可以更直观的帮你把数据展示出来。直接上代码看例子:importmatplotlib.pyplot...
- Python爬取爱奇艺腾讯视频 250,000 条数据分析为什么李诞不值得了
-
在《Python爬取爱奇艺52432条数据分析谁才是《奇葩说》的焦点人物?》这篇文章中,我们从爱奇艺爬取了5万多条评论数据,并对一些关键数据进行了分析,由此总结出了一些明面上看不到的数据,并...
- Python Matplotlib 库使用基本指南
-
简介Matplotlib是一个广泛使用的Python数据可视化库,它可以创建各种类型的图表、图形和可视化效果。无论是简单的折线图还是复杂的热力图,Matplotlib提供了丰富的功能来满足我们...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- Python 操作excel的坑__真实的行和列
- Python os.path模块使用指南:轻松处理文件路径
- Python常用内置模块介绍——文件与系统操作详解
- Python Flask 建站框架实操教程(flask框架网页)
- 为你的python程序上锁:软件序列号生成器
- PO设计模式全攻略,在 UI 自动化中的实践总结(以企业微信为例)
- 这种小工具居然也能在某鱼卖钱?我用Python一天能写...
- python打包成exe,程序有图标,但是任务栏和窗口都没有显示图标
- 使用Python构建电影推荐系统(用python做推荐系统)
- python爬取并分析淘宝商品信息(python爬取淘宝商品数据)
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)