一年的打磨,MNN正式版发布!( 二 )


symm int8
72.456%
3.5M
训练量化模型
symm int8
71.1%
3.5M
注1:训练和验证均采用数据集 。训练采用32为,执行100个迭代,即,使用了 3200 张图片进行训练;精度验证则使用了 50000 张图片 。
注2:原始模型为官方模型,官方准确率为 71.8%,但因预处理代码上有细微差别,我们测试原始模型的准确率结果稍高于官方;
可以看出,在实现了 73% 模型尺寸压缩的情况下,量化模型的精度甚至要稍高于原始模型 。
?迁移学习示例
这里节选V2 的 4 分类迁移学习示例,来说明模型的,完整示例请参考文档【9】 。
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(NN::Conv(option));// 初始化内部特征提取器, 内部提取器设成不需要训练mFix.reset(PipelineModule::extract({input}, {lastVar}, false));// 注意这里只注册了我们新初始化的4分类全连接层,那么训练时将只更新此4分类全连接层registerModel({mLastConv});}virtual std::vector onForward(const std::vector& inputs) override {// 输入一张图片,获得MobilenetV2特征提取器的输出auto pool= mFix->forward(inputs[0]);// 将上面提取的特征输入到新初始化的4分类层进行分类auto result = _Softmax(_Reshape(_Convert(mLastConv->forward(pool), NCHW), {0, -1}));return {result};}// MobilenetV2特征提取器,从输入一直到最后一个AveragePoolingstd::shared_ptr mFix;// 重新初始化的4分类全连接层std::shared_ptr 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 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 扩展的启用开关还放置在 .txt 中,后续会在运行时判别 。

一年的打磨,MNN正式版发布!

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

文章插图
?ARMv8.2
ARM 在「 Armv8. to」【10】一文中,列举了可以在运行时中应用的 ARMv8.2 新特性 。其中,FP16 和Dot 可以分别应用于浮点计算加速和量化计算加速 。
一年的打磨,MNN正式版发布!

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