speed-up
之前文章中介绍了通过模型压缩来加速其推理速度的主要思路,并就知识蒸馏总结了三篇内容,分别是:模型替换之bert-of-theseus 、知识迁移 和 看样本下菜的FastBERT。本文总结两种与模型无关的加速方案。
训练加速
训练加速的主要方法包括pipeline 和混合精度,其中pipeline是指通过构造一个input pipeline将数据IO与GPU计算分开,从而避免GPU因IO而空闲,这个问题不是本篇重点,想进一步了解的可以参考tensorflow数据读取机制-何之源和Doc-tf-data-dataset
混合精度
混合精度是指训练时在模型中同时使用 16 位和32位浮点类型,从而加快运行速度,减少内存使用的一种训练方法。通过让模型的某些部分保持使用 32 位类型以保持数值稳定性,可以缩短模型的单步用时,而在评估指标(如准确率)方面仍可以获得同等的训练效果。(tf doc)简单说就是开启混合精度,既能更省显存又能加速训练,保证性能的前提下,偶尔还能提高性能,真是又省又快又好,了解更多混合精度相关知识,可以参考浅谈混合精度训练.
然而很早之前笔者就知道开启混合精度的好处了,在pytorch 下有apex 可以很方便的开启,但是在keras(tensorflow 1.x) 下尝试了多次,也没能找到正确的方法,最近笔者又一次尝试,终于找到了正确的姿势,这里也分享一下。
对应的软硬件要求
tensorflow要求版本在1.14+ ,对应的显卡需要算力(compute capability)在7及以上, 可以在cuda-gpus#compute查看对应型号卡的算力
如何开启
对应代码中,只需要增加一行代码,修改一下optimizer即可。不过仍有两点非常需要注意:
- 修改optimizer最好在build model前完成,否则某些情况下可能会报错。
- optimizer需要是tf.train.Optimizer or tf.keras.optimizers.Optimizer继承来的,不支持keras 原生的optimizer。
1 |
|
当在打印信息中看到 tensorflow/core/grappler/optimizers/auto_mixed_precision.cc
相关信息,则说明已成功开启混合精度。
1 | ... |
一些测试结果
笔者在V100 下用bert-base 做了部分测试,测试结果如下:
batch_size=32, maxlen=128
epoch 1 | epoch 2 | epoch 3 | epoch 4 | epoch 5 | |
---|---|---|---|---|---|
开启前: | |||||
277s | 246s | 244s | 246s | 244s | |
164ms/step | 147ms/step | 146ms/step | 147ms/step | 146ms/step | |
bset acc: | 0.57 | ||||
开启后: | |||||
235s | 200s | 201s | 200s | 201s | |
140ms/step | 120ms/step | 121ms/step | 120ms/step | 121ms/step | |
best acc: | 0.576 |
batch_size=64, maxlen=128
epoch 1 | epoch 2 | epoch 3 | epoch 4 | epoch 5 | |
---|---|---|---|---|---|
开启前: | |||||
234s | 202s | 201s | 203s | 203s | |
281ms/step | 242ms/step | 241ms/step | 244ms/step | 244ms/step | |
best acc: | 0.567 | ||||
开启后: | |||||
180s | 141s | 140s | 140s | 141s | |
216ms/step | 169ms/step | 168ms/step | 168ms/step | 169ms/step | |
best acc: | 0.571 |
可以看到,batch size越大,加速比越可观,约能节省1/3的训练时间,同时,性能不会出现明显下降甚至可能也会高一点点。
另外,测试使用的bert 是keras 代码,其中有一条日志是converted 1265/17548 nodes to float16 precision
,所以约有不到10%的节点使用了半精度?所以猜测使用半精度的节点越多加速比越可观。
推理加速
推理时通常需要我们提供一个SDK或一个API 服务,这里我们只讨论API 服务的情况。
而API 服务通常有两种做法:
- 在server 端load 模型,然后直接预测给出结果;
- backend 调用tf-serving ,模型的预测由tf-serving 来提供,其余的(数据的预处理,结果的后处理等)则在backend 端进行。tf-serving 具有热更新,支持多模型多版本,异步调用,高可用等特性,所以也推荐使用tf-serving。使用了tf-serving后,完整的路线变为:
client –> backend –> rpc/rest –> tf-serving
其中tf-serving 提供了两种形式的api:restful api 和 grpc
对应的demo 代码可以查看serving
测试
关于头图
可爱修狗