加速器
- NNAPI
- GPU
- XNNPACK
模型推理速度对比(CPU)
- 量化模型:TFLITE > MNN
- F32/F16模型:TFLITE < MNN
- XNNPACK可加速TFLITE浮点模型
- TFLITE/MNN:F32=F16,F16仅模型减半,推理时仍然是F32参数
XNNPACK
浮点加速库(高度优化的神经网络算子,**具体怎么优化的**),目的是提高CPU上神经网络推理性能。将XNNPACK库集成到TF Lite中,浮点推理的速度平均提升2.3倍。
目的
几乎不影响AI模型推理准确性的同时,“修剪”模型的大小,以提升模型推理速度。
最好情况下能将AI模型的推理速度提升2倍,模型大小“缩水”一半(???)。
实现
利用AI模型的稀疏性实现加速推理。
AI模型分析
移动端轻量级神经网络架构,如MobileNet和EfficientNetLite,主要由深度可分离卷积和1x1卷积组成。其中1x1卷积耗费的推理时间最长,占总计算量65%以上。因此1x1卷积卷积层成为了稀疏化的最优选择。
1x1卷积分析
在现代的推理设备中(如XNNPACK),深度学习模型中1x1卷积的实现以及操作都依赖于HWC张量布局,这种张量配置运行推理引擎并行地处理对应于每个空间位置(即图像的每个像素)的通道(理解:并行的按通道处理)。
然而张量的这种排序并不适合稀疏推理,因为它将通道设置为张量的最内层维,并使访问它的计算成本更高。而Google对XNNPACK更新使得其具有了检测模型是否稀疏的表达能力:从标准的密集推理模式切换到稀疏推理模型,在稀疏推理模型中中XNNPACK使用CHW的张量布局。
为了避免每次操作后在稀疏推理最优的CHW张量布局和标准的HWC张量布局之间来回转换,XNNPACK提供了几种在CHW布局中CNN算子的高效实现。
HWC->CHW张量的重新排序,便可以允许实现加速稀疏的1x1卷积核:
- 在单个条件检查之后(什么条件,检查什么),当对应的通道权值为零时(谁的通道权值),可以跳过张量的整个空间切片,而不是逐像素检测;
- 当信道权值(什么是信道权值)为非零时,可以通过将相邻的像素加载到同一存储单元来提高计算效率。这样使得使用者能够同时处理多个像素,同时也可以在多个线程中并行执行每个操作。
- 当至少80%的权重为零时,会引起1.8~2.3倍加速

为什么此前利用稀疏化加速推理的方法应用不广泛
- 因为神经网络本身难以解释(黑盒),导致稀疏化过程也难以解释,以至于缺乏稀疏化工具。
- 端侧设备缺乏对稀疏化操作的支持。
Google开发稀疏化新工具
为移动端设备和Web端,发布了一系列针对TensorFlow Lite、XNNPACK浮点加速库的稀疏化新工具。
- XNNPACK库包含了可检测模型否稀疏的方法(如何检测呢)。
- TF Lite工具包包含基于幅度的剪枝等让模型“缩水”的方法。
AI模型稀疏化过程(代码实现参考TF Lite模型优化工具包)
影响稀疏网络质量的超参数:训练时间、学习速率、剪枝计划。官方建议运行超参数搜索来找到应用程序的最佳位置。
AI模型稀疏化:改进CPU推理速度。
**
- 从原始模型开始训练,在训练过程中逐渐将网络中的部分权重设置为0,即“修剪”模型(剪枝过程);
- 适当增加训练时间,提升模型准确度(与修剪前模型相差不会太多, 稀疏度高于70%,模型精度会下降明显);
- 获得稀疏AI推理模型,可以以压缩格式有效存储(怎么存储),相较于原始模型减少了1/2;
稀疏性
在神经网络模型中,将部分网络的权重参数设置为0,以加快推理速度。
- 需要保证模型精度的情况下,将部分权重参数设置为0;
- 为什么设置为0后可以加快推理速度?
因为AI模型进行推理任务时往往涉及到大量矩阵乘法运算,将矩阵中的部分参数设置成0,可以极大地加快矩阵运算速度(乘、加运算),缩短推理时间。
TFLITE + XNNPACK
TFLITE于TF2.3及后续版本中,将XNNAPCK Delegate集成到源码中。
使用方法
XNNCPAC后端已包含在针对Android、iOS的TF Lite预构建二进制文件中,只需修改单行代码即可启用。下载预构建的TF Lite2.3 Android归档(AAR)已包含XNNPACK,只需一行代码即可在
Interpreter.Options对象中启用:// JAVA版本,C++版本不支持Interpreter.Options interpreterOptions = new Interpreter.Options();interpreterOptions.setUseXNNPACK(true);Interpreter interpreter = new Interpreter(model, interpreOptions)
Windows、macOS和Linux版TF Lite也支持XNNPACK,可通过构建时的选择加入机制启用。使用Bazel构建TF Lite时,只需要添加
--define tflite_with_xnnpack=true即可启用XNNPACK后端,默认情况下TF Lite将使用此后端。
Support
- 支持F32、F16格式模型;
- 对于不支持的浮点算子将以透明方式回退到TF Lite默认实现;
- 不支持对权重或激活定点量化的模型;
- 对小型神经网络模型和低端手机上的TF Lite助益最大;
- 支持检测模型是否稀疏化。
- Dynamically allocated (with
kTfLiteDynamicallocation type) inputs and outputs are not supported. - Resizing model inputs (via
Interpreter::ResizeInputTensor) is supported, but cause a complete reinitialization of the delegate instance, which has considerable overhead. - 计划在后续版本中,将所以平台的XNNPACK后端设置为默认启用。
使用方法实践版(TF2.4.2)
1、自行编译包含xnnpack的库,测试里面是否包含XNNPACK;
方法一(无效)bazel选项添加--define tflite_with_xnnpack=true,TF Lite interpreter默认使能xnnpack库。
该方法中Interpreter::SetNumThreads并不能对xnnpack的线程数生效,需要手动指定xnnpack线程数,否则more使用单线程推理。
// Load modeltflite::Model* model;...// Construct the interpreptertflite::ops::builtin::BuiltinOpResolver resolver;std::unique_ptr<tflite::Interpreter> interpreter;TfLiteStatus res = tflite::InterpreterBuilder(model, resolver, num_threads);
方法二
修改BUILD文件,链接//tensorlfow/lite:tflite_with_xnnpack,通过代码使能xnnpcak。
// add xnnpackTfLiteXNNPackDelegateOptions xnnpack_options = TfLiteXNNPackDelegateOptionsDefault();// 重新设置线程数xnnpack_options.num_threads = info->param.number_of_threads;xnnpack_delegate = TfLiteXNNPackDelegateCreate(&xnnpack_options);TfLiteInterpreterOptionsAddDelegate(options, xnnpack_delegate);
3、使用low-level delegate API使能xnnpack(不推荐,除非需要判断是否使能xnnpack)
// Build the interpreterstd::unique_ptr<tflite::Interpreter> interpreter;...// IMPORTANT: initialize options with TfLiteXNNPackDelegateOptionsDefault() for// API-compatibility with future extensions of the TfLiteXNNPackDelegateOptions// structure.TfLiteXNNPackDelegateOptions xnnpack_options =TfLiteXNNPackDelegateOptionsDefault();xnnpack_options.num_threads = num_threads;//TfLiteDelegate* xnnpack_delegate =TfLiteXNNPackDelegateCreate(&xnnpack_options);if (interpreter->ModifyGraphWithDelegate(xnnpack_delegate) != kTfLiteOk) {// Report error and fall back to another delegate, or the default backend}...// Run inference using XNNPACKinterpreter->Invoke()...// IMPORTANT: release the interpreter before destroying the delegateinterpreter.reset();TfLiteXNNPackDelegateDelete(xnnpack_delegate);
