FastBERT icon indicating copy to clipboard operation
FastBERT copied to clipboard

复现效果中GPU推理加速比较低

Open dawson-chen opened this issue 4 years ago • 6 comments

你好,我在复现论文效果时遇到两个问题,请教一下。

  1. 当我训练子分类器时,得到的效果没有直接用true label训练效果好;
  2. 最终推理时,我在CPU上得到了11x的速度提升,但是GPU上只有2x。

下面是我分享复现时的细节,并非全部与所问问题相关:

  • 我用的是中文二分类数据集,40w作为训练集,3w作为测试集,后面的效果都是在测试集上得出的;
  • teacher分类器和student分类器都是按照论文中的设置,包括降维后的维度128;
  • 我用的loss是hinton蒸馏论文中的经典公式,temperature设置为1; ps: 我有试过在较浅的层使用较大的temperature来保证论文中Uncertainty是递减的,但是训练效果不太理想就放弃了;
  • 按照论文,真个训练过程分为2步:
    1. 训练主干网络和teacher分类器的参数,使用交叉熵作loss;
    2. 固定主干网络和teacher分类器上的参数,训练子分类器的参数;
  • 训练结果主干网络和原来的模型效果一致(acc 96%);第一层子分类器下降4%的acc(92%);每一层的acc从前到后,整体呈现上升趋势;
  • 推理时我将12层分别切成一个小模型,将上一层的输出当作下一层的输入; 以此来保证整体的计算量没有上升;表一为具体切分规则。
  • 推理时,speed选择为0.2,模型效果几乎没有下降(acc 0.1个百分点);speed=0.5的时候效果下降明显,(acc 4个百分点)。
  • 如果speed选择为0,既会对每一层进行推理,此时在gpu上推理时间为原始bert的5倍;
Blocks Which model belongs to
Embeddings M0
Transformer-0 M0
Stu-Classfier-0 M0
Transformer-1 M1
Stu-Classfier-1 M1
... ...
Transformer11 M11
Tea-Classfier M11

表一:一共分为12段,M0-M11分别对应12个分类器

根据上述最后一条,我猜想GPU上推理加速效果不显著,是因为多出来的输入输出操作占用太多时间。 再次感谢您的研究成果,希望您能多分享一下推理方面的经验,是否有不用切分模型的自适应推理方法呢?

dawson-chen avatar Apr 22 '20 13:04 dawson-chen

很不错的实验,可以发布一下实验代码吗?我也很想在自己任务上做一些尝试。

Cumberbatch08 avatar Apr 27 '20 06:04 Cumberbatch08

  • 模型效果几乎没有下降(acc 0.1个百分

您的复现很不错,这些问题我们在研究过程中都有遇到哈,我根据自己的经验逐个回答哈,也不一定是对的,仅供参考:

Q1. 当我训练子分类器时,得到的效果没有直接用true label训练效果好; A1. 您用的loss是hinton蒸馏论文中的经典公式,我们在子分类器蒸馏时使用的loss是KL散度(见原文公式6),是否是这里的区别呢?

Q2: 最终推理时,我在CPU上得到了11x的速度提升,但是GPU上只有2x; A2: 这个问题在于GPU对Batch处理是有优化的,GPU处理batch_size=32的批数据耗时并不是batch_size=16批数据的两倍。因此,在GPU上如果有批处理优化的话,提速不明显。而在CPU上,由于没有批处理优化,提速明显。如果想GPU提速也明显的话,需要一些工程上的优化,在剔除低Uncertainty样本后batch_size会减小,可以考虑把多个bacth的样本合并为一个batch送入下一层,以充分使用GPU的批处理能力。

另外,需要注意一点,FLOPs与时间不是线性的。

我们马上会开源代码,方便对比哈。

再补充问一下,您是用Pytorch复现吗? 在根据Uncertainty筛选样本时是否使用了torch.nonzero()函数?

autoliuweijie avatar May 01 '20 14:05 autoliuweijie

先回复您的问题,我用的是tensorflow1.13复现的。由于是静态图,推理时先计算得到uncertainty值,然后用if...else进行筛选。

uncertainty_value = sess.run(uncertainty_tensor, feed_dict={...}) 
if uncertainty_value < speed:
    stop()

下面是针对我的问题,说一下我的疑惑。

根据维基上的公式,交叉熵和KL散度关系如下。在蒸馏时,前项只与老师的预测结果有关,所以交叉熵和KL散度在优化上是等效的。并且我再蒸馏时hinton蒸馏公式T参数设定为1,所以也排除T参数的影响。

kl

其实,我用true_label直接训练子分类器效果也不错了,所以对于我的任务来说用不用蒸馏并不影响应用您论文中的研究内容。

主要是gpu推理的问题,我在gpu上测试时是没有用到批处理优化的,也就是只用单条推理测试极限的加速效果。这样做是因为只要单条推理上加速效果好,在批处理时是可以用一些工程方法实现相似的加速效果,类似您说的重组batch。 对于gpu加速不明显,我目前的推测还是因为tensorflow静态图在分层推理时处理输入输出导致的。我也在寻找更好的分层推理机制,但是在tensorflow1.13中是不支持的。如果您有pytorch上的推理的加速经验,希望能分享一下,非常感激。

另外是我看完论文后衍生出的一些思考,希望和您交流一下。

  1. 论文中给出了先训练骨干网络然后训练层分类网络的方法,所以骨干网络上的参数在训练时只有最后一层能感知到下游分类任务。这样可能造成的影响是这些参数并不是很适合用来分类,所以需要加入子分类器用于进一步的特征提取,从而保证层分类器的输出质量。是否可以将uncertainty应用在训练阶段,使得不确定性高的分类器对应loss占有更少的比例,是不是能够得到更好的层分类效果,并且做到降低层分类器结构的作用。
  2. 前面说对gpu分段推理速度影响最大的是输入输出的操作,那么减少切分点的数量就可以大大的较少这部分所占用的时间。合理的切分点应该保证在特定的speed下,大多数样本只需要第一层分类器的结果。目前这种方法测试是可行的,不确定性基本上是符合递减的特质,所以在给定speed下,第一层的输出对应的不确定性最好略低于speed值,可以将输出输出次数控制到最少。

dawson-chen avatar May 08 '20 14:05 dawson-chen

先回复您的问题,我用的是tensorflow1.13复现的。由于是静态图,推理时先计算得到uncertainty值,然后用if...else进行筛选。

uncertainty_value = sess.run(uncertainty_tensor, feed_dict={...}) 
if uncertainty_value < speed:
    stop()

下面是针对我的问题,说一下我的疑惑。

根据维基上的公式,交叉熵和KL散度关系如下。在蒸馏时,前项只与老师的预测结果有关,所以交叉熵和KL散度在优化上是等效的。并且我再蒸馏时hinton蒸馏公式T参数设定为1,所以也排除T参数的影响。

kl

其实,我用true_label直接训练子分类器效果也不错了,所以对于我的任务来说用不用蒸馏并不影响应用您论文中的研究内容。

主要是gpu推理的问题,我在gpu上测试时是没有用到批处理优化的,也就是只用单条推理测试极限的加速效果。这样做是因为只要单条推理上加速效果好,在批处理时是可以用一些工程方法实现相似的加速效果,类似您说的重组batch。 对于gpu加速不明显,我目前的推测还是因为tensorflow静态图在分层推理时处理输入输出导致的。我也在寻找更好的分层推理机制,但是在tensorflow1.13中是不支持的。如果您有pytorch上的推理的加速经验,希望能分享一下,非常感激。

另外是我看完论文后衍生出的一些思考,希望和您交流一下。

  1. 论文中给出了先训练骨干网络然后训练层分类网络的方法,所以骨干网络上的参数在训练时只有最后一层能感知到下游分类任务。这样可能造成的影响是这些参数并不是很适合用来分类,所以需要加入子分类器用于进一步的特征提取,从而保证层分类器的输出质量。是否可以将uncertainty应用在训练阶段,使得不确定性高的分类器对应loss占有更少的比例,是不是能够得到更好的层分类效果,并且做到降低层分类器结构的作用。
  2. 前面说对gpu分段推理速度影响最大的是输入输出的操作,那么减少切分点的数量就可以大大的较少这部分所占用的时间。合理的切分点应该保证在特定的speed下,大多数样本只需要第一层分类器的结果。目前这种方法测试是可行的,不确定性基本上是符合递减的特质,所以在给定speed下,第一层的输出对应的不确定性最好略低于speed值,可以将输出输出次数控制到最少。
  1. 将uncertainty应用到finetune阶段:这是可以进行尝试的,但是我们在实验过程中遇到了一些困难,那就是后层的student分类器很难收敛,因为到后层的样本较少。如果能解决这个问题,那效果可能会有进一步提升。我们在考虑用随机样本训练(得意于自蒸馏,不需要标签),以增大进入后层的样本数。

  2. 抱歉,我对tensorflow里的机制不是很熟悉,暂时不是很清楚该如何优化。如果您有兴趣开源您的Tensorflow版本代码,我很乐意在README.md里添加一个链接指向您的代码哈。

autoliuweijie avatar May 13 '20 03:05 autoliuweijie

先回复您的问题,我用的是tensorflow1.13复现的。由于是静态图,推理时先计算得到uncertainty值,然后用if...else进行筛选。

uncertainty_value = sess.run(uncertainty_tensor, feed_dict={...}) 
if uncertainty_value < speed:
    stop()

下面是针对我的问题,说一下我的疑惑。 根据维基上的公式,交叉熵和KL散度关系如下。在蒸馏时,前项只与老师的预测结果有关,所以交叉熵和KL散度在优化上是等效的。并且我再蒸馏时hinton蒸馏公式T参数设定为1,所以也排除T参数的影响。 kl 其实,我用true_label直接训练子分类器效果也不错了,所以对于我的任务来说用不用蒸馏并不影响应用您论文中的研究内容。 主要是gpu推理的问题,我在gpu上测试时是没有用到批处理优化的,也就是只用单条推理测试极限的加速效果。这样做是因为只要单条推理上加速效果好,在批处理时是可以用一些工程方法实现相似的加速效果,类似您说的重组batch。 对于gpu加速不明显,我目前的推测还是因为tensorflow静态图在分层推理时处理输入输出导致的。我也在寻找更好的分层推理机制,但是在tensorflow1.13中是不支持的。如果您有pytorch上的推理的加速经验,希望能分享一下,非常感激。 另外是我看完论文后衍生出的一些思考,希望和您交流一下。

  1. 论文中给出了先训练骨干网络然后训练层分类网络的方法,所以骨干网络上的参数在训练时只有最后一层能感知到下游分类任务。这样可能造成的影响是这些参数并不是很适合用来分类,所以需要加入子分类器用于进一步的特征提取,从而保证层分类器的输出质量。是否可以将uncertainty应用在训练阶段,使得不确定性高的分类器对应loss占有更少的比例,是不是能够得到更好的层分类效果,并且做到降低层分类器结构的作用。
  2. 前面说对gpu分段推理速度影响最大的是输入输出的操作,那么减少切分点的数量就可以大大的较少这部分所占用的时间。合理的切分点应该保证在特定的speed下,大多数样本只需要第一层分类器的结果。目前这种方法测试是可行的,不确定性基本上是符合递减的特质,所以在给定speed下,第一层的输出对应的不确定性最好略低于speed值,可以将输出输出次数控制到最少。
  1. 将uncertainty应用到finetune阶段:这是可以进行尝试的,但是我们在实验过程中遇到了一些困难,那就是后层的student分类器很难收敛,因为到后层的样本较少。如果能解决这个问题,那效果可能会有进一步提升。我们在考虑用随机样本训练(得意于自蒸馏,不需要标签),以增大进入后层的样本数。
  2. 抱歉,我对tensorflow里的机制不是很熟悉,暂时不是很清楚该如何优化。如果您有兴趣开源您的Tensorflow版本代码,我很乐意在README.md里添加一个链接指向您的代码哈。

所以fastbert开源是pytorch的版本吗?

Zjq9409 avatar May 13 '20 08:05 Zjq9409

先回复您的问题,我用的是tensorflow1.13复现的。由于是静态图,推理时先计算得到uncertainty值,然后用if...else进行筛选。

uncertainty_value = sess.run(uncertainty_tensor, feed_dict={...}) 
if uncertainty_value < speed:
    stop()

下面是针对我的问题,说一下我的疑惑。

根据维基上的公式,交叉熵和KL散度关系如下。在蒸馏时,前项只与老师的预测结果有关,所以交叉熵和KL散度在优化上是等效的。并且我再蒸馏时hinton蒸馏公式T参数设定为1,所以也排除T参数的影响。

kl

其实,我用true_label直接训练子分类器效果也不错了,所以对于我的任务来说用不用蒸馏并不影响应用您论文中的研究内容。

主要是gpu推理的问题,我在gpu上测试时是没有用到批处理优化的,也就是只用单条推理测试极限的加速效果。这样做是因为只要单条推理上加速效果好,在批处理时是可以用一些工程方法实现相似的加速效果,类似您说的重组batch。 对于gpu加速不明显,我目前的推测还是因为tensorflow静态图在分层推理时处理输入输出导致的。我也在寻找更好的分层推理机制,但是在tensorflow1.13中是不支持的。如果您有pytorch上的推理的加速经验,希望能分享一下,非常感激。

另外是我看完论文后衍生出的一些思考,希望和您交流一下。

  1. 论文中给出了先训练骨干网络然后训练层分类网络的方法,所以骨干网络上的参数在训练时只有最后一层能感知到下游分类任务。这样可能造成的影响是这些参数并不是很适合用来分类,所以需要加入子分类器用于进一步的特征提取,从而保证层分类器的输出质量。是否可以将uncertainty应用在训练阶段,使得不确定性高的分类器对应loss占有更少的比例,是不是能够得到更好的层分类效果,并且做到降低层分类器结构的作用。
  2. 前面说对gpu分段推理速度影响最大的是输入输出的操作,那么减少切分点的数量就可以大大的较少这部分所占用的时间。合理的切分点应该保证在特定的speed下,大多数样本只需要第一层分类器的结果。目前这种方法测试是可行的,不确定性基本上是符合递减的特质,所以在给定speed下,第一层的输出对应的不确定性最好略低于speed值,可以将输出输出次数控制到最少。

您好,请问您能仔细说明一下您tf中实现筛选的部分吗?我也在使用tf进行复现。由于tf1是静态图,导致目前对于“不确定度小于阈值则退出“这一部分的实现比较疑惑。十分感谢您的帮助

WzyPaopao avatar Jul 23 '21 09:07 WzyPaopao