共计 2997 个字符,预计需要花费 8 分钟才能阅读完成。
download:2022 为峰 Python 全栈测试开发班 V5.1- 天涯共此时
Tricks 帮忙你进步调试 Pytorch 的效率。
领导浏览
好的工具和工作习惯能够大大提高工作效率。
每个深度学习我的项目都不一样。无论你有多少教训,你总会遇到新的挑战和意想不到的行为。你在我的项目中应用的技能和思维形式将决定你能多快找到并解决这些妨碍你胜利的阻碍。
从实用的角度来看,深度学习我的项目是从代码开始的。一开始组织起来很容易,然而随着我的项目复杂度的减少,在调试和完整性检查上破费的工夫会越来越多。令人诧异的是,很多都能够主动实现。在这篇文章中,我将通知你如何去做。
找出你的训练损失没有缩小的起因。
实现主动模型验证和异样检测。
应用 PyTorch Lightning 节俭贵重的调试工夫。
招数二: 记录训练数据的直方图。
总是查看输出数据的范畴是很重要的。如果模型权重和数据是十分不同的量级,则在极其状况下可能导致没有或非常低的学习进度和数值不稳固。例如,当数据扩大以谬误的程序利用或遗记规范化时,就会产生这种状况。在咱们的例子中是这样吗?咱们应该可能通过打印最小值和最大值来找出答案。然而等等!这不是一个好的解决方案,因为它会不必要地净化代码,并在须要时破费太多工夫来反复它。更好的办法: 写一个回调类来帮咱们做!
类输出监视器(pl。回拨):
def on_train_batch_start(self,trainer,pl_module,batch,batch_idx,dataloader_idx):
if(batch idx+1)% trainer . log every n steps = = 0:
x,y = 批次
logger = 培训师
logger . experience . add histogram(” input “,x,global step = trainer . global _ step)
logger . experience . add histogram(” target “,y,global step = trainer . global _ step)
像这样应用回调:
model = LitClassifier()
培训师 = pl。培训师 (gpus = 1,回调 =[InputMonitor()])
trainer.fit(型号)
复制代码
一个简略的回调,将训练数据的直方图记录到 TensorBoard。
PyTorchlighting 中的回调能够保留任何能够注入训练器的代码。在进入训练步骤之前,计算输出数据的直方图。将此函数封装到回调类中有以下长处:
它与你的钻研代码是离开的,没有必要批改你的 LightningModule!
它是可移植的,因而能够在将来的我的项目中重用,只须要批改两行代码: 导入回调,而后将其传递给 Trainer。
能够通过子类化或者联合其余回调来扩大。
当初有了新的回调函数,咱们能够关上 TensorBoard 并切换到“直方图”选项卡来查看训练数据的散布:
在指标范畴 [0,9] 中,这是正确的,因为 MNIST 有一个 10 位的类,但图像的值在 -130 和 -127 之间,这是谬误的!咱们很快发现第 41 行规范化中有一个问题:
转变。Normalize(128,1) #谬误的规范化
复制代码
这两个数字应该是输出数据 (在咱们的例子中是图像中的像素) 的平均值和标准差。为了解决这个问题,咱们增加了实在平均值和标准偏差,并命名了参数以使其更加清晰:
转变。归一化 (平均值 =0.1307,标准差 =0.3081)
复制代码
咱们能够查这些数字,因为它们是已知的。对于本人的数据集,你得本人去计算。
归一化后像素的平均值为 0,标准差为 1,就像分类器的权重一样。咱们能够通过看 TensorBoard 的直方图来确认这一点。
技巧 3: 检测正向流传中的异样
在解决了标准化问题后,咱们当初也能够在 TensorBoard 中取得预期的直方图。惋惜损失并没有缩小。还有一个问题。我晓得数据是正确的,并且开始寻找谬误的一个好中央是网络的前向门路。一个常见的误差源是张量形态的操作,如置换、整形、视图、平坦等。,或利用于一维的操作,如 softmax。当这些函数利用于谬误的大小或谬误的程序时,咱们通常会失去形态不匹配的谬误,但状况并非总是如此!这些谬误很难追踪。
让咱们来看看一种能让咱们疾速检测出这些谬误的技术。
疾速查看模型是否在批处理中混合数据。
想法很简略: 如果咱们扭转第 n 个输出样本,它应该只影响第 n 个输入。如果其余输入 i≠n 也发生变化,模型就会混数据,这就不好了!施行该测试的一种牢靠办法是计算所有输出的第 n 个输入的梯度。对于所有 i≠n 的突变必须为零(以上动画中的红色),对于 i = n 的突变必须非零(以上动画中的绿色)。如果满足这些条件,模型就通过了测试。以下是 n = 3 时的实现:
用所有输出查看第 n 个小批量样品的梯度
n = 3
1. 输出批次须要梯度
example_input = torch.rand(5,1,28,28,requires_grad=True)
2. 通过模型运行批处理
输入 = 模型(示例_输出)
3. 计算第 n 个输入样本的虚构损耗并反向流传
输入[n]。abs()。sum()。向后()
4. 查看样本 I 上的梯度!= n 都是零!
健全性查看: 如果这没有返回 0,您有一个 bug!
i = 0
example_input.grad[i]。abs()。sum()。我的项目 ()
复制代码
上面是同样的闪电回调:
类 CheckBatchGradient(pl。回拨):
定义 on_train_start(自我、教练、模型):
n = 0
示例输出 = 模型. 示例输出阵列. 至(模型. 设施)
example input . requires grad = True
零 grad()
输入 = 模型 (示例_输出)
输入[n]。abs()。sum()。向后()
zero grad inds = list(range(example _ input . size(0)))
零梯度指数
if example input . grad[zero grad _ inds]。abs()。sum()。item() > 0
raise RuntimeError(“ 您的模型混合了批处理维度中的数据!”)
像这样应用回调:
model = LitClassifier()
培训师 = pl。训练器 (gpus = 1,回调 =[CheckBatchGradient()])
trainer.fit(型号)
复制代码
当这个测试利用于 LitClassifer 时,您能够立刻发现它混合了数据。既然咱们晓得咱们要找的是什么,咱们很快就在正向传输中发现了一个谬误。第 35 行中的 Softmax 利用于谬误的尺寸:
output = F.log_softmax(x,dim=0)
复制代码
应该是:
output = F.log_softmax(x,dim=1)
复制代码
好了,分类器工作了!并且训练和验证损失迅速缩小。
摘要
编写好的代码从组织开始。PyTorch Lightning 通过删除围绕训练周期工程、检查点保留、日志记录等的样板代码来解决这一部分。剩下的就是理论的钻研代码: 模型、优化和数据加载。如果事件没有依照咱们预期的形式运行,很可能是这三局部代码中的某一部分有谬误。在这篇博文中,咱们实现了两个回调来帮忙咱们 1)监控进入模型的数据,以及 2)验证咱们的网络中的层不会在批处理维度中混合数据。回调的概念是向现有算法增加任意逻辑的一种十分优雅的形式。一旦实现,通过批改两行代码就能够很容易地集成到一个新我的项目中。