5个实用提速深度学习模型的方法

您是否通过深度学习模型获得了良好的准确性,却发现推理时间不足以部署到生产环境中?您是否对如何优化模型的推理速度迷失了方向?那么这篇文章是给你的。众所周知,数据科学项目有一个奇特的特性,即项目者需要不断转换关注重点,根据业务或项目的不同需求。下面罗列了一些具体的关注点:

  • 数据集是如何获取的?是否是自己创建的数据集?(如果是自己的数据集,那么准确的标签是什么?任务中需要使用的样本需要多少?)

  • 如何将模型充分利用到实际项目中来?即使一个模型很好,但是如何将这个模型投入到实际项目中?

  • 你将使用什么模型?目前,学术界已经发表了很多具有价值的算法模型,而我们在研究中时,很多技术已经发生了改变。

  • 最重要的问题:这上述的一切是否可行,也就是按照目前的预算,是否可以用数据集训练出一个模型?并且这样的模型,是否能够满足我们应用场景的需要?

通常,在最后一个问题中,我们主要关注获得数据集的最佳预测准确性。这是最有意义的,因为它允许我们验证项目是否可行。反正,如果我们需要为模型投资更多数据以实现其目标,那么我们就需要权衡效率的问题。对于某些项目,缓慢的推理速度并不是一个破坏因素。但是,如果真的是这样的情况,那么具体会发生什么事情?

这种情况,可能发生在任何深度学习项目中,但在将涉及对象检测的项目部署到生产时通常会出现这种情况。当操作来自相机的图像时,每秒处理的每个帧都很重要。在硬件上投入更多资金绝对可以解决或缓解我们的问题。但是,如果我们打算将我们的产品作为解决方案(比如带有集成边缘 GPU 的摄像机)销售,这会线性增加产品的成本,直到我们无法从投资中获得回报。

针对许多实际情况,我们经历了上述的问题。这里,我们给出不同的方法清单,用来提高算法模型的推理速度。

1.改变模型的权重

从我们的经验来看,优化运行时模型的第一步是充分利用模型的架构。

1.1.1 训练后量化

将算法模型权重的精度,由浮点类型(32-bits)转换到整型(8-bits),将会降低模型的准确度。但是,从内存存储角度来看,这大大降低了存储消耗,反正提高了CPU和硬件加速器的延迟。

具体如何实现这个方法,主要取决于此算法模型所实现的框架。如果算法模型是用TensorFlow实现,那么很幸运,因为TensorFlow给出了模型量化的封装函数。如果算法模型使用PyTorch实现的,那么稍微有点困难。就在写本文的时候,PyTorch对于模型量化的支持,还局限于CPU端的支持。未来PyTorch对于模型量化的支持,将扩充到GPU端,就目前来看对于GPU端的模型量化支持还不够成熟。

当然,针对PyTorch实现的算法进行量化优化也不是没有任何方法,可以利用NVIDIA的TensorRT进行实现,但是为了能够在TensorRT运行时上运行PyTorch模型,模型权重需要先转化为中间模型权重格式。目前,可以实施的方法就是将PyTorch模型权重转换为ONNX模型格式,最终转化到TensorRT上进行运行。

1.1.2 实验举例

如果我们尝试量化一个用PyTorch框架实现的Faster R-CNN算法模型,但是不幸的是,这回产生很多问题。在论文上,所有这些过程都是有道理的,应该很容易做到。然而,在实践中,所有这些转换都可能出现问题。这主要是因为 PyTorch、ONNX 和 TensorRT 的发展会朝着多个方向发展,当一项功能被添加到一个功能中时,旧的集成不一定支持它。可能的问题如下:

  • 我们的模型可能能够在ONNX上运行,但是问题可能发生在将ONNX格式的模型转为TensorRT格式的过程中。尤其是,针对某些网络层,例如是PyTorch中的Resize层。

  • 在我们尝试进行这种转换时,我们碰巧使用PyTorch v1.3 或更高版本构建的模型可以转换并在ONNX Runtime 中运行,但无法通过 ONNX 优化器运行(这在转换网络是尤其重要的一步)。

请记住,这些问题可能会出现也可能不会出现,这取决于我们模型的架构,我们在转换简单的CNN网络时没有问题,但是对于我们正在使用的Faster R-CNN实现,这是另一回事。一些用户可以通过降级PyTorch设法解决了转换过程中的问题。但是,这限制了我们可以访问的ONNX的opset,这反过来也限制了我们可以使用哪个TensorRT 版本来运行您的引擎。希望所有这些问题都能在不久的将来得到解决……但考虑到所有这些框架的开发速度都很快,很可能总会有短暂的不兼容期。

训练后量化绝对是一个强大的工具,虽然有些PyTorch模型不能用这种方法量化,但你仍然应该试一试,考虑到将你的模型导出到ONNX后,可以很方便的使用命令行 trtexec 来转换模型。顺便说一下,它与Nvidia TensorRT docker容器中的 TensorRT 一起很容易获得。如果PyTorch量化失败,那么如果量化仍然是你想要的方法,我们建议你寻找TensorFlow实现。

1.2.1 将模型转换为半精度

与之前的方法类似,这种替代方法旨在权衡速度和内存效率的准确性。它提供了FP32和UInt8之间的中间点,其中:

  • 模型大小最多减少一半(而不是最多 75%)

  • 精度的下降小于 UInt8,这使得精度权衡更接近 FP32。

  • 大多数神经网络权重已经落入这个范围内,尽管进行这种转换有梯度下溢(小梯度值变为零)的风险,这会阻止网络正确学习任何东西。

考虑到如今 GPU 的架构已转向针对 FP16 操作进行优化,尤其是使用张量核心,这种方法为提高速度提供了很好的权衡。此外,事实证明,并非网络的所有层在推理过程中都花费大量时间。这意味着我们可以通过仅在需要速度提升的层(例如卷积)中使用半精度并将其余部分留在 FP32 中来找到更好的权衡。更好的是,在 FP32 中有一些层有助于防止梯度下溢。这种方法称为自动混合精度,它在量化方面的不同之处在于,不是对训练模型的权重进行后处理,而是应该从一开始就使用混合精度来训练模型。

1.2.2 实验举例

TensorFlow 通过为我们提供原生支持来实现这一目标,再次在很大程度上让我们的实际开发更轻松。而如果您使用PyTorch,NVIDIA Apex是你应该使用的工具,幸运的是,根据我们的经验,它比使用PyTorch 模型进行量化所带来的痛苦要少得多。集成 Apex 被宣传为仅在你的代码中添加三行。而实际上,还不止这些。你必须对其进行初始化,更改反向传递调用以使用 Apex 的缩放损失,并修改你保存和加载检查点的方式,实例如下:

from apex.fp16_utils import *
from apex import amp, optimizers
...
# Initialization
opt_level = 'O1'
model, optimizer = amp.initialize(model, optimizer, opt_level=opt_level)
# Train your model
...
with amp.scale_loss(loss, optimizer) as scaled_loss:
scaled_loss.backward()
...

结果也很不错。你获得多少加速将在很大程度上取决于你正在训练的模型。对于我们上面提出的Faster R-CNN模型实例来说,我们获得了超过30%的速度提升,而对我们的Faster R-CNN 模型的准确性没有任何影响。

2.寻找最优模型

我们试图从我们的模型中提取最后一个dropout以缩短推理时间。但也许这还不够。也许我们模型的架构对于我们试图解决的问题来说太大了。减小模型的大小也会降低我们的准确性吗?不必要!这不仅取决于我们希望模型解决的问题的具体性质。而且通过研究,不断提出和试验新的模型架构,通常会产生更纤薄的架构,通过设计实现更高的准确性!更好的是,如果我们实现了前面描述的任何方法,我们就可以重用该工作,并决定对我们的模型进行任何修改。

2.1 改变模型的backbone

在进行迁移学习时,我们可以查看模型的主干和对其进行预训练的数据集,仅作为我们在网格搜索中使用的超参数。我们不需要经过完全训练的模型来评估推理时间。这使我们可以对多个主干进行实验,并查看哪些可以更好地改善推理时间。我们应该期待我们的推理时间有相当大的改进,记住我们的模型仍然需要通过一个主干,虽然相当数量的推理时间发生在主干上,我们模型的外层仍然可以有对推理时间有很大影响。在研究了哪些主干提供了更好的时序之后,使用它的模型需要完全重新训练,以便我们分析主干对模型准确性的影响。

2.2 改变整个模型

数据科学家的日常工作不仅是从事数据科学项目,还要密切关注研究以及它如何影响当前的技术状态。尽管我们模型的主干是我们模型的一个重要组成部分,但我们只能通过尝试优化一些保持其他事物静态的东西来做这么多。如果毕竟方法推理时间仍然不符合你的喜好,那么是时候查看新开发的模型并验证这些模型所承诺的内容是否适用于你的实际用例。

2.3 实验举例

以物体检测问题为例,一些模型专门针对速度进行了优化,例如 YOLO,而同时其他模型提供了多种配置,这些配置随神经网络的深度和它们接收的输入的大小而变化,例如 EfficentDet,允许你训练和比较准确度与速度之间的权衡如何变化。更重要的是,令人惊叹的机器学习社区通常会提供这些模型的开源实现,供我们协作并帮助我们不要重新发明轮子!例如zylo117对EfficientDet 的 PyTorch 实现。

3.知识蒸馏

我们最后提出的改善模型推理时间的选项是通过知识蒸馏。假设我们有一个大模型(或模型的集合),它的预测精度很高,但其推理速度并不理想。Knowledge Distillation 建议通过使用我们的大模型作为训练器来训练一个具有较少参数的较小模型。这实质上是训练我们的小模型输出与我们的大模型或集成相同的预测。这样做的一个很大优势是我们不仅限于使用标记数据。

请注意,虽然我们的准确性可能会受到影响,但我们应该能够从中获得不错的速度提升。不幸的是,我们没有愉快地自己实施这种方法。但是知识蒸馏最近非常流行,并已用于对象分类、对象检测、声学模型和 NLP等。如果你想了解更多关于 知识蒸馏的信息,请查看Geoffrey Hinton等人的这篇论文。

4.总结

在本博客中,我们描述了五种方法来改善深度学习模型的推理时间。特别是,我们建议你按照我们列出的顺序实现它们,因为我们为实现模型量化和自动混合精度所做的任何编码对于我们对模型进行的任何进一步更改都具有重要价值。

我们希望这篇文章对你有价值,无论是通过为你当前面临的问题提供指导,还是在需要时用我们的知识武装你的项目!如果你有本博文中未涵盖的加速模型推理的方法,请告诉我们……对模型的推理速度优化有任何疑问吗?如果可以,我们很乐意在评论中回答这些问题。

5.参考链接

https://www.tensorflow.org/api docs/python/tf/quantization/quantize

https://pytorch.org/docs/stable/quantization.html

https://developer.nvidia.com/zh-cn/tensorrt

https://github.com/onnx/onnx

https://arxiv.org/abs/1506.01497

https://github.com/onnx/onnx-tensorrt/issues/302

https://github.com/NVIDIA/TensorRT/issues/284

https://github.com/onnx/onnx/issues/2417

https://ngc.nvidia.com/catalog/containers/nvidiatensorrt

https://developer.nvidia.com/blog/mixed-precision-training-deep-neural-networks/

https://github.com/NVIDIAapex

https://github.com/zylo117Yet-Another-EfficientDet-Pytorch

https://arxiv.org/pdf/1503.02531.pdf

作者:匡吉

热门文章

暂无图片
编程学习 ·

C语言二分查找详解

二分查找是一种知名度很高的查找算法,在对有序数列进行查找时效率远高于传统的顺序查找。 下面这张动图对比了二者的效率差距。 二分查找的基本思想就是通过把目标数和当前数列的中间数进行比较,从而确定目标数是在中间数的左边还是右边,将查…
暂无图片
编程学习 ·

GMX 命令分类列表

建模和计算操作命令: 1.1 . 创建拓扑与坐标文件 gmx editconf - 编辑模拟盒子以及写入子组(subgroups) gmx protonate - 结构质子化 gmx x2top - 根据坐标生成原始拓扑文件 gmx solvate - 体系溶剂化 gmx insert-molecules - 将分子插入已有空位 gmx genconf - 增加…
暂无图片
编程学习 ·

一文高效回顾研究生课程《数值分析》重点

数值分析这门课的本质就是用离散的已知点去估计整体,就是由黑盒子产生的结果去估计这个黑盒子。在数学里这个黑盒子就是一个函数嘛,这门课会介绍许多方法去利用离散点最大化地逼近这个函数,甚至它的导数、积分,甚至微分方程的解。…
暂无图片
编程学习 ·

在职阿里5年,一个28岁女软测工程师的心声

简单的先说一下,坐标杭州,14届本科毕业,算上年前在阿里巴巴的面试,一共有面试了有6家公司(因为不想请假,因此只是每个晚上去其他公司面试,所以面试的公司比较少) ​ 编辑切换为居中…
暂无图片
编程学习 ·

字符串左旋c语言

目录 题目: 解题思路: 第一步: 第二步: 第三步: 总代码: 题目: 实现一个函数,可以左旋字符串中的k个字符。 例如: ABCD左旋一个字符得到BCDA ABCD左旋两个字符…
暂无图片
编程学习 ·

设计模式--观察者模式笔记

模式的定义与特点 观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式&#xf…
暂无图片
编程学习 ·

睡觉突然身体动不了,什么是睡眠痽痪症

很多朋友可能有这样的体验,睡觉过程中突然意识清醒,身体却动弹不了。这时候感觉非常恐怖,希望旁边有一个人推自己一下。阳光以前也经常会碰到这样的情况,一年有一百多次,那时候很害怕晚上到来,睡觉了就会出…
暂无图片
编程学习 ·

深入理解C++智能指针——浅析MSVC源码

文章目录unique_ptrshared_ptr 与 weak_ptrstd::bad_weak_ptr 异常std::enable_shared_from_thisunique_ptr unique_ptr 是一个只移型别(move-only type,只移型别还有std::mutex等)。 结合一下工厂模式,看看其基本用法&#xff…
暂无图片
编程学习 ·

@TableField(exist = false)

TableField(exist false) //申明此字段不在数据库存在,但代码中需要用到它,通知Mybatis-plus在做写库操作是忽略它。,.
暂无图片
编程学习 ·

Java Web day15

第十二章文件上传和下载 一、如何实现文件上传 要实现Web开发中的文件上传功能,通常需要完成两步操作:一.是在Web页面中添加上传输入项;二是在Servlet中读取上传文件的数据,并保存到本地硬盘中。 需要使用一个Apache组织提供一个…
暂无图片
编程学习 ·

【51nod 2478】【单调栈】【前缀和】小b接水

小b接水题目解题思路Code51nod 2478 小b接水 题目 输入样例 12 0 1 0 2 1 0 1 3 2 1 2 1输出样例 6解题思路 可以发现最后能拦住水的都是向两边递减高度(?) 不管两个高积木之间的的积木是怎样乱七八糟的高度,最后能用来装水的…
暂无图片
编程学习 ·

花了大半天写了一个UVC扩展单元调试工具

基于DIRECTSHOW 实现的,用的是MFC VS2019. 详见:http://www.usbzh.com/article/detail-761.html 获取方法 加QQ群:952873936,然后在群文件\USB调试工具&测试软件\UVCXU-V1.0(UVC扩展单元调试工具-USB中文网官方版).exe USB中文网 USB中文…
暂无图片
编程学习 ·

贪心(一):区间问题、Huffman树

区间问题 例题一:区间选点 给定 N 个闭区间 [ai,bi]请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。 输出选择的点的最小数量。 位于区间端点上的点也算作区间内。 输入格式 第一行包含整数 N,表示区间数。 接下来 …
暂无图片
编程学习 ·

C语言练习实例——费氏数列

目录 题目 解法 输出结果 题目 Fibonacci为1200年代的欧洲数学家,在他的着作中曾经提到:「若有一只免子每个月生一只小免子,一个月后小免子也开始生产。起初只有一只免子,一个月后就有两只免子,二个月后有三只免子…
暂无图片
编程学习 ·

Android开发(2): Android 资源

个人笔记整理 Android 资源 Android中的资源,一般分为两类: 系统内置资源:Android SDK中所提供的已经定义好的资源,用户可以直接拿来使用。 用户自定义资源:用户自己定义或引入的,只适用于当前应用的资源…
暂无图片
编程学习 ·

零基础如何在短时间内拿到算法offer

​算法工程师是利用算法处理事物的职业 算法(Algorithm)是一系列解决问题的清晰指令,也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。 如果一个算法有缺陷,或不适合于某个问题,执…
暂无图片
编程学习 ·

人工智能:知识图谱实战总结

人工智能python,NLP,知识图谱,机器学习,深度学习人工智能:知识图谱实战前言一、实体建模工具Protegepython,NLP,知识图谱,机器学习,深度学习 人工智能:知识图…
暂无图片
编程学习 ·

【无标题】

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…