如何评价阿里开源的移动端深度学习推理框架mnn?
14 个回答
假装谢邀,利益也不相关
开场
“千呼万唤始出来,犹抱琵琶半遮面”,随着MNN的开源,BAT三家互联网巨头的移动终端深度学习推理框架终于凑齐了。时间有限,只留了一天时间试用MNN框架,一句话概括“后发优势明显,对硬件支持完善,速度基本全面超越”。
后发优势
吸取了最近两年开源的移动端推理框架的各种优秀成果
- 针对conv3x3s1优化的winograd;
- 针对网络图的优化以及层间数据复用;
- 为提高访存效率,加入nchw4策略;
- 支持int8低比特网络模型压缩及加速;
- ……待补充。
硬件支持完善
- cpu:为追求速度的极限,使用纯汇编实现了arm32、arm64两种版本的kernel;
- gpu:支持metal、opencl、opengl、vulkan,全覆盖目前主流移动终端版本gpu,特别是对次时代框架vulkan的支持,极大满足了最新android平台网络模型部署需求;
- 框架支持:TensorFlow、Caffe、ONNX,虽然未直接支持PyTorch和MxNet,但可以通过ONNX作为中间桥梁进行转换;
- dsp:( 没找到.....这个情有可原,毕竟移动终端SoC中使用dsp的只有高通一家,希望后面能够完善。
Int8量化
目前只支持TensorFlow Lite的int8模型转换,近期会更新一个Post Training Quantization工具,速度对比只有MobileNet v1的(只留给我一天时间试用哇,哪里来得及测试这么多嘛……
好吧,我知道前面这些你们都不会看,图来了(谢谢星纬大师贡献小米9试机,羡慕有新手机的小伙伴)~



为了直观的体现出高通855中GPU的强劲性能,对比下Kirin970中寒武纪NPU,然而高通855真正用来跑AI的是性能更厉害的DSP……


结束语
感谢mnn团队支持开源社区工作,提供优秀的框架,推动业界发展,希望后期能持续维护。
传送门
不请自来,正主儿坐镇。:)
说说我们的想法,欢迎讨论交流。
MNN 的诞生源于淘系技术部的一群对技术充满热情的同学,在充分的行业调研后认为当时的推理引擎如 TFLite 不足以满足手机淘宝这样一个亿级用户与日活的超级 App 。
于是我们从零开始自己搭建了属于阿里巴巴的推理引擎 MNN 。1年前的这个时候,MNN在Github上开源。它比其他的推理引擎更快更轻量,更符合手机淘宝这样庞大、复杂的生产部署环境。
今年3月份,MNN 的引擎设计与优化理念还获得了学术界的认可,在MLSys 2020上发表了论文,并进行了oral presentation。
开源1年以来,获益于公司内外的用户反馈和业务推动,MNN 在许多方面都取得了长足的进步:
- 在阿里巴巴集团内部得到广泛推广,成为了端上推理引擎的事实标准,覆盖了如手机淘宝、手机天猫、优酷、钉钉、闲鱼等 20 多个 App 。
- 新添了模型训练的支持,从此 MNN 不再是单纯的推理引擎,而是具有推理+训练能力的深度学习引擎。基于 MNN 的训练能力,我们可以进行 Quantization-Aware Training (QAT)。在MobileNet上,MNN 量化训练之后的模型准确率几乎不降。
- 持续投资于异构硬件后端的优化,尤其是利用 ARMv8.2 指令集,获得了两倍的性能提升。
- 进一步完善 Python 工具链,累计新增超过 150 个接口。
- 开源了应用层开箱即用的解决方案MNNKit,包含了人脸跟踪与检测、人像分割、手势识别场景的解决方案。
- 开办了三期《MNN学院》直播(1期, 2期, 3期),增加了与用户们交流,也获得了忠粉们的大量高质量反馈意见。
截止到今天,MNN 在开源社区获得了近 4000 的 Github Stars ,这是大家对我们的工作所投的4000 张认可票,也是鞭策我们完善 MNN 的动力。
近日,MNN 发布了 1.0.0 正式版本。自此,MNN 不再被 Github 贴上“Pre-release”的标签了!
相较于0.2.2版本,1.0.0版本的主要升级在于:模型训练、异构性能和Python工具链。
下面,我们逐项说明。
模型训练
模型构建
MNN支持使用 Express (表达式)接口来构建模型,如下例所示,接口还是比较简洁明了的。模型的构建、训练和保存具体可以参考说明文档。
VARP x = inputs[0];
x = conv1->forward(x);
x = _MaxPool(x, {2, 2}, {2, 2});
x = conv2->forward(x);
x = _MaxPool(x, {2, 2}, {2, 2});
x = _Convert(x, NCHW);
x = _Reshape(x, {0, -1});
x = ip1->forward(x);
x = _Relu(x);
x = dropout->forward(x);
x = ip2->forward(x);
x = _Softmax(x, 1);
return {x};以MNIST数据集 + Lenet网络为例,一个epoch 60000张图片,一般可达到97-98%的准确率。性能上,同款MBP上,MNN比PyTorch和Caffe都有明显优势;而手机上,MNN也达到了完全可用的性能水准。

量化训练
模型量化既可以降低模型大小,又可以利用硬件特性提升推理性能,可谓业务应用必备之选。但美中不足之处在于,模型量化会带来一定的精度损失 —— 对于精度攸关的项目,就难免要做出艰难的选择了。

为此,MNN借助自身模型训练能力,实现了模型训练量化,具体实现可以参考说明文档。精度和压缩率方面,我们以MobileNet V2为例说明:

注1:训练和验证均采用ImageNet数据集。训练采用32为batch size,执行100个迭代,即,使用了3200张图片进行训练;精度验证则使用了50000张图片。
注2:原始模型为TensorFlow官方模型,官方准确率为71.8%,但因预处理代码上有细微差别,我们测试原始模型的准确率结果稍高于官方;
可以看出,在实现了73%模型尺寸压缩的情况下,量化模型的精度甚至要稍高于原始模型。
迁移学习示例
这里节选MobileNet V2的4分类迁移学习示例,来说明模型的Finetune,完整示例请参考文档。
class MobilenetV2TransferModule : public Module {
public:
MobilenetV2TransferModule(const char* fileName) {
// 读取原始MobilenetV2模型
auto varMap = Variable::loadMap(fileName);
// MobilenetV2的输入节点
auto input = Variable::getInputAndOutput(varMap).first.begin()->second;
// MobilenetV2分类层之前的节点,AveragePooling的输出
auto lastVar = varMap["MobilenetV2/Logits/AvgPool"];
// 初始化一个4分类的全连接层,MNN中可以用卷积来表示全连接层
NN::ConvOption option;
option.channel = {1280, 4};
mLastConv = std::shared_ptr<Module>(NN::Conv(option));
// 初始化内部特征提取器, 内部提取器设成不需要训练
mFix.reset(PipelineModule::extract({input}, {lastVar}, false));
// 注意这里只注册了我们新初始化的4分类全连接层,那么训练时将只更新此4分类全连接层
registerModel({mLastConv});
}
virtual std::vector<VARP> onForward(const std::vector<VARP>& inputs) override {
// 输入一张图片,获得MobilenetV2特征提取器的输出
auto pool = mFix->forward(inputs[0]);
// 将上面提取的特征输入到新初始化的4分类层进行分类
auto result = _Softmax(_Reshape(_Convert(mLastConv->forward(pool), NCHW), {0, -1}));
return {result};
}
// MobilenetV2特征提取器,从输入一直到最后一个AveragePooling
std::shared_ptr<Module> mFix;
// 重新初始化的4分类全连接层
std::shared_ptr<Module> mLastConv;
};
int main(int argc, const char* argv[]) {
std::string trainImagesFolder = argv[2];
std::string trainImagesTxt = argv[3];
std::string testImagesFolder = argv[4];
std::string testImagesTxt = argv[5];
// 读取模型,并替换最后一层分类层
std::shared_ptr<Module> model(new MobilenetV2TransferModule(argv[1])); // arg1: /path/to/mobilenetV2Model
// 进入训练环节
MobilenetV2Utils::train(model, 4, 0, trainImagesFolder, trainImagesTxt, testImagesFolder, testImagesTxt);
return 0;
}
异构性能
x86
在x86上,我们重点优化了矩阵乘法。在分析过AVX和Arm向量乘指令差异后,我们修改了AVX下的权重矩阵布局,降低了I/O布局,以充分利用CPU算力。
此外,我们允许在支持FMA扩展的设备上,启用扩展,将乘法和加法合为一条指令,以进一步降低指令耗时。
当前,FMA扩展的启用开关还放置在CMakeLists.txt中,后续会在运行时判别。

综合两项优化,x86上有30%左右的性能优化。
ARM64
在ARM64上,我们面向中低端设备,调整了矩阵乘法的分块策略,矩阵中每个元素的均摊I/O降低了22%;同时,将数据对齐从32字节调整为64字节,与ARM架构CPU下场景的L1 cacheline匹配;最后,优化了缓存预取。优化结果如下:

ARMv8.2
ARM在「Bringing Armv8.2 Instructions to Android Runtime」一文中,列举了可以在Android运行时中应用的ARMv8.2新特性。其中,FP16 extensions和Dot Product可以分别应用于浮点计算加速和量化计算加速。
FP16 extensions

亦记作asimdhp(Advanced SIMD Half Precision),是ARMv8.2架构的可选扩展。asimdhp可用时,可以使用相关SIMD指令实现float16的读写计算。float16将float32所需的位数降低了一半,因此在SIMD下,可以实现两倍的并发吞吐,从而优化性能。为此,我们在卷积中,采用[N,C/8,H,W,8]的数据布局,新增了部分卷积实现,效果如下:

精度上几乎没有下降,但是性能足足提升了一倍。搭配上MNN转换工具的--fp16输出选项,模型大小还能减小一半。一箭双雕。
Dot Product

亦记作asimddp(Advanced SIMD Dot Product),是ARMv8.2架构的可选扩展。asimddp可用时,可以使用SDOT/UDOT指令实现int8/uint8的点积计算。SDOT/UDOT指令如上图所示,一次可以处理两个4x4 int8/uint8数据乘,并累加到4x1的int32/uint32的寄存器上。这样强大的硬件加速指令,还是双发射的。

实战表现效果也非常明显,在原先int8无法发挥效用的设备上,ARMv8.2也成功实现了耗时减半。
Python工具链
2019年的绿盟开发者大会上,我们发布了MNN的Python前端和Python版的转换、量化、可视化工具。而今,Python又增加了对MNN Express (表达式)、模型训练的封装,累计新增超过150个接口。具体可以参考说明文档。
依然是前文的Express构图,使用Python改写的版本如下:
class Net(nn.Module):
"""construct a lenet 5 model"""
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.conv(1, 20, [5, 5])
self.conv2 = nn.conv(20, 50, [5, 5])
self.fc1 = nn.linear(800, 500)
self.fc2 = nn.linear(500, 10)
def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool(x, [2, 2], [2, 2])
x = F.relu(self.conv2(x))
x = F.max_pool(x, [2, 2], [2, 2])
x = F.convert(x, F.NCHW)
x = F.reshape(x, [0, -1])
x = F.relu(self.fc1(x))
x = self.fc2(x)
x = F.softmax(x, 1)
return x
对熟悉Python的开发者来说,是不是要亲切上许多呢?
注:目前Python Express API处于BETA阶段。我们会根据社区和内部的反馈持续改进Python API,包含进行backward incompatible的改动。
后续计划
2020年,我们计划每个季度发布一个稳定版本。
未来的计划,主要集中在性能、训练、NPU支持和模型压缩。
性能
性能是MNN的立身之本,相信很多朋友选择MNN,也主要出于它飙车般的性能。有兴趣的朋友,可以去看看MNN发表在今年MLSys的论文解读。
- CPU上,移动设备方面,ARMv8.2将是新手机的主流,上文所展示2倍加速比非常诱人,我们会进一步挖掘ARMv8.2的优化空间;其他平台方面,x86的性能在单机训练、服务端推理的场景中举足轻重,会是性能优化的另一个目标。
- GPU上,我们会聚焦Vulkan —— Android下一代GPGPU API的事实标准。
训练
MNN最新拥有的训练能力已经通过Express(表达式)接口支持常用模型的训练、量化、蒸馏,我们会进一步完善训练能力,添加更多算子和求导的支持,以支持更多的模型。
NPU支持
NPU具有超高的性能、超低的能耗,将是未来手机的标配。NPU的支持,也是许多MNN用户经常在钉钉群里提出的需求。MNN在未来的1年,会逐步支持更多的NPU,请大家拭目以待!
模型压缩
MNN目前已经拥有Post-training quantization和Quantization-aware training的能力。我们会持续投入模型压缩(如蒸馏,稀疏,剪枝,低比特等),给业界提供更多优秀的、即插即用模型压缩算法。
————————————————————————————————————————————
以上答案来自阿里巴巴淘系技术MNN团队。
我们是阿里巴巴淘系技术,淘系技术部隶属于阿里巴巴新零售技术事业群,旗下包含淘宝技术、天猫技术、农村淘宝技术、闲鱼、躺平等团队和业务,是一支是具有商业和技术双重基因的螺旋体。
刚刚入驻知乎,将会给大家带来超多干货分享,立体化输出我们对于技术和商业的思考与见解。
详情介绍可以看这里 阿里巴巴淘系技术介绍
欢迎收藏点赞关注我们!未来会很精彩!:)


