autoliuweijie / FastBERT

The score code of FastBERT (ACL2020)
https://www.aclweb.org/anthology/2020.acl-main.537/
604 stars 90 forks source link

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

Open dawson-chen opened 4 years ago

dawson-chen commented 4 years ago

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

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

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

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上推理加速效果不显著,是因为多出来的输入输出操作占用太多时间。 再次感谢您的研究成果,希望您能多分享一下推理方面的经验,是否有不用切分模型的自适应推理方法呢?

Cumberbatch08 commented 4 years ago

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

autoliuweijie commented 4 years ago
  • 模型效果几乎没有下降(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()函数?

dawson-chen commented 4 years ago

先回复您的问题,我用的是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值,可以将输出输出次数控制到最少。
autoliuweijie commented 4 years ago

先回复您的问题,我用的是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里添加一个链接指向您的代码哈。

Zjq9409 commented 4 years ago

先回复您的问题,我用的是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的版本吗?

WzyPaopao commented 3 years ago

先回复您的问题,我用的是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是静态图,导致目前对于“不确定度小于阈值则退出“这一部分的实现比较疑惑。十分感谢您的帮助