TF模型训练中数据shuffle对模型性能的影响

未经shuffle的loss曲线出现周期性的震荡,测试后模型的泛化效果也很差。

什么是Shuffle?

shuffle(中文意思:洗牌,混乱)。shuffle在机器学习与深度学习中代表的意思是,将训练模型的数据集进行打乱的操作。
原始的数据,在样本均衡的情况下可能是按照某种顺序进行排列,如前半部分为某一类别的数据,后半部分为另一类别的数据。但经过打乱之后数据的排列就会拥有一定的随机性,在顺序读取的时候下一次得到的样本为任何一类型的数据的可能性相同。

模型训练过程中需要Shuffle么?

Shuffle是一种训练的技巧,因为机器学习其假设和对数据的要求就是要满足独立同分布。所以任何样本的出现都需要满足“随机性”。所以在数据有较强的“人为”次序特征的情况下,Shuffle显得至关重要。

但是模型本身就为序列模型,则数据集的次序特征为数据的主要特征,并且模型需要学到这种次序规律时,则不可以使用Shuffle。否则会将数据集中的特征破坏。

Shuffle为什么重要?

Shuffle可以防止训练过程中的模型抖动,有利于模型的健壮性.

假设训练数据分为两类,在未经过Shuffle的训练时,首先模型的参数会去拟合第一类数据,当大量的连续数据(第一类)输入训练时,会造成模型在第一类数据上的过拟合。当第一类数据学习结束后模型又开始对大量的第二类数据进行学习,这样会使模型尽力去逼近第二类数据,造成新的过拟合现象。这样反复的训练模型会在两种过拟合之间徘徊,造成模型的抖动,也不利于模型的收敛和训练的快速收敛

Shuffle可以防止过拟合,并且使得模型学到更加正确的特征
NN网络的学习能力很强,如果数据未经过打乱,则模型反复依次序学习数据的特征,很快就会达到过拟合状态,并且有可能学会的只是数据的次序特征。模型的缺乏泛化能力。
如:100条数据中前50条为A类剩余50条为B类,模型在很短的学习过程中就学会了50位分界点,且前半部分为A后半部分为B。则并没有学会真正的类别特征。

小结

其实Shuffle的作用归结起来就是两点,在针对随机性敏感的数据集上

  1. 提升模型质量
  2. 提升预测表现

在模型训练前,我们往往对数据进行shuffle,即随机打乱数据,为什么要这么做呢?不这么做会出现什么问题?何时应该shuffle,何时不该shuffle呢?

下面,本文就以上三个问题发表下自己的拙见。

Q1:为什么要进行shuffle?

A1:不论是机器学习还是深度学习,我们总是基于数据独立同分布的假设条件,也就是说,数据的出现应该是随机的,而不是按照某种顺序排列好的。以上就是需要shuffle的根本原因。因此,我们需要在每个epoch的开始把数据shuffle一下。

Q2:不shuffle会出现什么问题?

A2:泛化能力差。

①模型学到的可能只是数据次序,并未学到有用的信息,导致泛化能力差。

②如果数据是排序过的,比如按类别排序,会导致模型一会儿过拟合这个类,一会儿过拟合那个类,这一方面会使得训练过程的loss周期性震荡;另一方面,在训练结束时,模型总是对最近训练的那类数据过拟合而导致泛化能力差。

比如做公式识别(将图片的公式转换为latex形式),如果不shuffle,按图片的宽高比排列数据,且第一张图片和最后一张图片的宽高比相差很大,在这种情况下,不shuffle直接训练,就会出现loss周期性震荡的现象,比如每个epoch的开始,loss会突然上升很多,然后逐渐下降,等下一个epoch开始的时候,loss又会突然上升,循环往复。

Q3:何时应该shuffle,何时不该shuffle呢?

A3:当我们使用优化器进行模型训练时,比如使用SGD优化方法,不可避免地,在结束模型训练时,模型对刚刚学习过的那类数据有着更好的表现。

因此,①如果我们想让模型泛化能力更强,我们应该对数据进行shuffle,这样模型最后见过的数据在一定程度上是能代表总体的,有着更强的泛化能力,通常情况下,我们都是要进行shuffle的。

②如果我们想让模型学会某种次序关系或者我们希望模型对某部分数据表现的更好一点,那么我们则要根据自己的目的来决定数据的顺序,并决定是局部shuffle还是完全不shuffle。比如,对于时间序列数据,根据过去的数据预测未来的数据,我们则希望越近期的数据,模型给予更高的关注度,一种方式就是将近期的数据放在后面,那么等模型训练完的时候,最近见过的数据就是近期的数据,自然对近期数据有更高的关注,这样在预测未来数据的时候,近期的数据能发挥更大的作用。

所以,是否shuffle要具体情况具体分析。
 

数据集shuffle数量过大导致训练超时

问题现象

训练执行报错:

020-11-27 11:26:00.510219: I tensorflow/core/kernels/data/shuffle_dataset_op.cc:145] Filling up shuffle buffer (this may take a while): 2169 of 10000
2020-11-27 11:26:10.454132: I tensorflow/core/kernels/data/shuffle_dataset_op.cc:145] Filling up shuffle buffer (this may take a while): 3252 of 10000
2020-11-27 11:26:20.375176: I tensorflow/core/kernels/data/shuffle_dataset_op.cc:145] Filling up shuffle buffer (this may take a while): 3915 of 10000
2020-11-27 11:26:30.543144: I tensorflow/core/kernels/data/shuffle_dataset_op.cc:145] Filling up shuffle buffer (this may take a while): 4672 of 10000
2020-11-27 11:26:40.479843: I tensorflow/core/kernels/data/shuffle_dataset_op.cc:145] Filling up shuffle buffer (this may take a while): 5439 of 10000
2020-11-27 11:26:50.496244: I tensorflow/core/kernels/data/shuffle_dataset_op.cc:145] Filling up shuffle buffer (this may take a while): 6232 of 10000
2020-11-27 11:26:50.638388: W tensorflow/core/framework/op_kernel.cc:1639] Unavailable: Internal errors
2020-11-27 11:26:53.638664: F tf_adapter/kernels/geop_npu.cc:669] GeOp33_0GEOP::::DoRunAsync Failed
[ERROR] RUNTIME(62299)model execute error, retCode=0x91, [the model stream execute failed].
[ERROR] RUNTIME(62299)model execute task failed, device_id=0, model stream_id=575, model task_id=1, model_id=522, first_task_id=65535
Fatal Python error: Aborted

原因分析

当开启预处理下沉时,NPU采用预处理与前后向运算并行的方式工作。此时如果预处理过程对数据进行了shuffle且shuffle数量过大,则可能在前向计算任务下发很长时间后,预处理仍然无法输出有效数据,导致前向计算任务超时。

以shuffle数量设置为10000引发的任务超时为例,通过上述日志信息可以看到,在前向计算任务超时时,buffer仍未获取到足够的数据(仅获取到了6232个数据),从而发生task超时的错误打印。

解决方案

开发者可以采取以下策略解决:

可以根据超时时间内实际完成的shuffle数量,适当减少shuffle的数量。例如本例中实际完成的shuffle数量为6232个数据,我们配置为5000:

dataset = dataset.shuffle(buffer_size=5000)

也可以关闭数据预处理下沉开关,enable_data_pre_proc=False,从而保证预处理与前后向运算串行,但是可能会有性能上的损失。

run_config = NPURunConfig(enable_data_pre_proc=False)

Guess you like

Origin blog.csdn.net/pearl8899/article/details/121792312