Releases: alibaba/MNN
【LLM相关性能优化,形状缓存机制】2.9.0
MNN-LLM 正式合入
增加Transformer相关算子与对应图优化功能
- 编译 MNN 时打开宏 MNN_LOW_MEMORY 和 MNN_SUPPORT_TRANSFORMER_FUSE ,增加在线权重反量化、动态量化和Transformer相关算子支持
- -DMNN_SUPPORT_TRANSFORMER_FUSE=ON -DMNN_LOW_MEMORY=ON
- 转换模型时加上 --transformerFuse=1 开启Transformer模型相关图优化
新增 LLM 模块
使用方法
构建 LLM 文件包
- 下载模型,推荐使用魔搭
- pip install modelscope
- 执行脚本(以千问7b为例)
from modelscope import snapshot_download
from transformers import AutoModelForCausalLM, AutoTokenizer
# Downloading model checkpoint to a local dir model_dir
model_dir = snapshot_download('qwen/Qwen-7B-Chat')
#model_dir = snapshot_download("modelscope/Llama-2-7b-chat-ms", revision='v1.0.5',
ignore_file_pattern=[r'.+\.bin$'])
#model_dir = snapshot_download('qwen/Qwen-1_8B-Chat')
print(model_dir)
- 使用 MNN 目录下面的 transformers/llm/export/llm_export.py 进行模型导出,把 torch 模型转换成 onnx
- 示例
- python3 llm_export.py --embed_bin --embed_bf16 --onnx_path onnx --type Qwen-7B-Chat --path /Users/xtjiang/.cache/modelscope/hub/qwen/Qwen-7B-Chat --export_embed --export_token --mnn_path mnn --export
- 务必加 --embed_bin 参数,将 embeding 层导出成 bin 文件
- 完成后会产出两个文件夹
- onnx
- llm.onnx
- tokenizer.txt
- 其他外置权重数据,不用关注
- mnn
- embeddings_bf16.bin
- onnx
- 示例
- 使用 MNNConvert 转换 onnx 模型,并进行量化
- ./MNNConvert -f ONNX --modelFile onnx/llm.onnx llm.mnn --weightQuantBits=4 --transformerFuse=1 --saveExternalData
- 一般需要20-30 分钟,请耐心等待
- 产出 llm.mnn 与 llm.mnn.weight
- 建文件夹,组合上述步骤产出的文件,这里以千问7b为例
- 文件夹名:qwen-7b-int4
- 包含文件
- embeddings_bf16.bin
- llm.mnn
- llm.mnn.weight
- tokenizer.txt
编译LLM引擎并使用
-
编译MNN打开 MNN_BUILD_LLM 宏,编译 transformers/llm/engine 目录,产出 libllm 和 llm_demo
-
使用 llm_demo 运行 llm
- 参数:
- llm.mnn 文件路径
- forwardtype :0 为 CPU ,3 为 OpenCL
- Memory | Precision :Memory * 4 + Precision ,如果 memory 和 preicsion 都为 low ,即设为 10
- 示例:
- ./llm_demo ../../qwen-7b-int4/llm.mnn 0 10
- 【然后进行对话】
- ./llm_demo ../../qwen-7b-int4/llm.mnn 0 10 prompt.txt :使用预设的问题进行测试
- ./llm_demo ../../qwen-7b-int4/llm.mnn 0 10
- 参数:
-
CPU / GPU
性能测试
-
8Gen1
| model | CPU 4线程 | | OpenCL | |
| --- | --- | --- | --- | --- |
| | prefill | decode | prefill | decode |
| qwen-1.8b | 207.56 | 35.58 | 28.58 | 20.40 |
| qwen-7b | 25.86 | 7.5 | 7.95 | 7.70 |
| llama3-8b | 22.09 | 5.59 | 内存不足 | 内存不足 | -
8Gen3
| model | CPU 4线程 | | OpenCL | |
| --- | --- | --- | --- | --- |
| | prefill | decode | prefill | decode |
| qwen-1.8b | 205.70 | 47.07 | 61.25 | 21.56 |
| qwen-7b | 40.93 | 11.01 | 20.26 | 10.60 |
| llama3-8b | 36.44 | 7.83 | 19.10 | 2.14 | -
注:暂未对 llama3-8b 结构支持 Transformer 相关图优化,因此GPU性能较差
形变缓存机制
背景
对于语音/文本类的模型,往往涉及张量某个维度的逐步变化,这种情况下每次都会进行几何计算、申请内存等操作,导致不可忽略的性能损耗。考虑到输入单个维度变化的情况下,网络中会存在部分算子形状不变,这部分计算是可以去除的。
为了对这种情况进行优化,MNN新增了形变缓存机制,使模型输入形状变化时,形状不变的算子跳过形变相关操作,以提升性能。
原理
- MNN 通过两个状态去优化Resize过程,先在 Check 状态下寻找不变形状的算子,然后切换到 Fix 状态,分离易变形状与不变形状算子进行处理。对应于 Interpreter.hpp 里面增加两个 SessionMode
- Session_Resize_Check
- Session_Resize_Fix
- Check 状态
- 存储或检查输入的形状是否与上次一致,对应跳过几何计算阶段,但资源分配阶段不跳过
- Fix 状态
- 根据算子的形状不变标志,跳过几何计算与资源分配阶段
基于 Module API 使用
对应 API
- **Module::**traceOrOptimize
示例
- 网络输入为 speech ,输出为 out0 ,out1 ,输入大小为: 1,3,X
std::shared_ptr<MNN::Express::Module> net(MNN::Express::Module::load(fileName, {"speech"}, {"out0", "out1"}), MNN::Express::Module::destroy);
net->traceOrOptimize(MNN::Interpreter::Session_Resize_Check);
int validShape[] = {64, 112};
for (int i=0; i<2; ++i) {
auto varp = MNN::Express::_Input({1, 3, validShape[i]}, MNN::Express::NCHW);
varp->writeMap<float>();
auto outputs = net->onForward({varp});
}
net->traceOrOptimize(MNN::Interpreter::Session_Resize_Fix);
// Forward and use output
基于 Intrepreter - Session API使用
相关API
- Interpreter::setSessionMode
示例
- 网络输入为 speech ,输出为 out0 ,out1 ,输入大小为: 1,3,X
std::shared_ptr<MNN::Interpreter> net(MNN::Interpreter::createFromFile(fileName), MNN::Interpreter::destroy);
MNN::ScheduleConfig config;
/*Set up config
......
*/
MNN::Session* session = net->createSession(config);
auto input = net->getSessionInput(session, "speech");
auto out0 = net->getSessionOutput(session, "out0");
auto out1 = net->getSessionOutput(session, "out1");
net->setSessionMode(Interpreter::Session_Resize_Check);
/*Resize Session for each valid size Begin*/
/*Demo: */
net->resizeTensor(input, {1, 3, 112});
net->resizeSession(session);
net->resizeTensor(input, {1, 3, 64});
net->resizeSession(session);
/*Resize Session for each valid size End*/
net->setSessionMode(Interpreter::Session_Resize_Fix);
/*Fill input and run session
......
*/
鸿蒙系统支持、功能完善与Github Issue 修正
功能完善
- 支持华为鸿蒙系统上的编译与运行
- 参考 MNN/project/harmony 下面的脚本进行编译
- 增加 WinogradLevel 配置,支持用户设定较低的Winograd 输出计算尺寸 ,以节省内存
- setSessionHint(WINOGRAD_MEMORY_LEVEL, 0) :使用最低计算尺寸
- setSessionHint(WINOGRAD_MEMORY_LEVEL, 3) :使用默认计算尺寸
- 修正 onnx onehot 算子在输入尺寸未知时转换出错问题
- 修正 Sigmoid / Tanh 等算子量化后出错的问题
- 优化 Tile 算子的几何计算分解,降低产出的Region数,以减少对应GPU后端的初始化耗时
- 支持 LayerNorm RMS 模式及相应的图优化
- 原生支持onnx-external data ,降低 Onnx 大模型转换所需要内存
- Metal 后端 NC4HW4 布局模式修改为C4NHW4,以优化 batch > 1 的卷积性能
- Metal 后端支持 BatchMatMul / Gather / GatherND 等对应生成的 Loop 算子
- Metal 后端支持 GridSampler3D
- Metal 后端支持可变精度设置
- precision 为 low / normal 时使用 fp16 存储
- precision 为 high 时使用 fp32 存储
- 计算一律使用 fp32
- CPU 后端修正权值在线反量化模式下,输入输出通道不对齐时出错的问题
- OpenCL 后端优化 Pooling 算子在 KernelSize 很大时的性能问题
- OpenCL 后端增加 Kernel 缓存机制,降低部分设备上 resize 耗时
- 其他Bugfix与优化
相应 Issue 修正
2.8.1
2.8.1
2.8.0
1. 新特性
- MNN支持以JSON文件格式导入量化参数 (issue-2587)
- 支持 MaxPooling with index (issue-2268)
- MNN支持NNAPI中Deconvolution算子
- MNNConvert支持 Onnx 中 dim < 2 的矩阵乘算子
- TestConvert 增加测试非 CPU 后端的能力
- Pymnn支持构建 MNN 训练模型,以支持离线训练模式
- 优化MNNConvert,大幅降低大模型转换时的内存占用
- OpenCL 支持 Loop 算子特殊形式,广播 Binary
- 支持 Unary, Prelu 算子量化
2. 性能优化
- ONNX ScatterND算子性能优化 (issue-2530)
- CPUTopKV2算子性能优化,将tflite的实现修改为stl的实现;
- ARM汇编实现
MNNTranspose16Bit8x8
, 提升fp16的转置性能; - ARM/X86使用动态量化方案优化权重量化的矩阵乘、卷积算子;llm模型推理性能大幅提升;
llm cpu性能测试
mnn-llm
在MNN 2.8.0版本的CPU性能如下,测试均使用4线程, 速度为prefill / decode
单位为tok/s
model | android(f16/32) | macos (f32) | linux (f32) | windows (f32) |
---|---|---|---|---|
qwen-1.8b-int4 | 100.21 / 22.22 | 84.85 / 19.93 | 151.00 / 35.89 | 117.30 / 33.40 |
qwen-1.8b-int8 | 99.95 / 16.94 | 67.70 / 13.45 | 118.51 / 24.90 | 97.19 / 22.76 |
chatglm-6b-int4 | 17.37 / 6.69 | 19.79 / 6.10 | 34.05 / 10.82 | 30.73 / 10.63 |
chatglm2-6b-int4 | 26.41 / 8.21 | 20.78 / 6.70 | 36.99 / 11.50 | 33.25 / 11.47 |
chatglm3-6b-int4 | 26.24 / 7.94 | 19.67 / 6.67 | 37.33 / 11.92 | 33.61 / 11.21 |
qwen-7b-int4 | 14.60 / 6.96 | 19.79 / 6.06 | 33.55 / 10.20 | 29.05 / 9.62 |
baichuan2-7b-int4 | 13.87 / 6.08 | 17.21 / 6.10 | 30.11 / 10.87 | 26.31 / 9.84 |
llama-2-7b-int4 | 17.98 / 5.17 | 19.72 / 5.06 | 34.47 / 9.29 | 28.66 / 8.90 |
测试的系统和设备信息如下,
os | device | CPU | Memory |
---|---|---|---|
android | XiaoMi12 | Snapdragon 8gen1 | 8 GB |
macos | MacBook Pro 2019 | Intel(R) Core(TM) i7-9750H CPU | 16 GB |
linux | PC | Intel(R) Core(TM) i7-13700K | 32GB |
windows | PC | Intel(R) Core(TM) i7-13700K | 32GB |
3. Bugfix
3.1 关联 Github Issue 解决
- 修复MNN2.5.3版本后量化模型不能得到正确结果 (issue-2614)
- 修复tflite模型转换到MNN时重复算子检测卡死的问题 (issue-2573)
- 支持Pytorch FX 量化而得的 ONNX 模型转换 (issue-2548)
3.2 其他 Bugfix 或优化
工具类:
- 修复Defer Allocator 实际分配内存后未做成功与否的检查
- 修复量化工具中由index=-1导致的crash问题
- 修复模型转换工具在转大模型时会crash的问题
- 修复模型转换工具在转换ONNX模型的Clip算子时不能正确处理 int32_t数据的问题
- 修复使用OpenCL训练时的内存泄露问题
- OpenCL单测错误问题修复
编译兼容性问题:
- 修复在X86_x64下SSE指令不兼容导致的编译错误
- 修复IOS 工程文件中由于局部变量在线程函数外导致的编译错误
- 修复一些ARM编译器无法识别 "vmov.f16 q0, #5.0"导致的编译错误
结果错误(crash)类问题:
- 修复C++版本下Binary函数中(<=,<,>=,>,==)的返回值类型导致的结果错误
- 修复 1x1 Strassen矩阵在Low Memory时crash问题
- 修复coreML在deconvolution算子padding!=0时crash问题
- 修复 ModuleAPI在运行时使用 Defer Allocator来申请内存的问题
2.7.2
Merge pull request #2618 from alibaba/feature/sync [MNN:Sync] Sync Internal 2.7.2
2.7.1
MNN 2.7.1
【内存分配优化、性能优化、Bugfix】2.7.0
1. 新特性
- 新增LayerNorm int8量化算子支持:
- CUDA 后端 新增 TopKV2 算子支持
- 新增 DeferAllocator ,支持延迟分配内存,默认在 CPU Backend 中启用,内部模型测试平均降低内存占用 19.13%
- OpenCL Buffer 模式新增Range/Select/Cast/ArgMax 等算子支持
- OpenCL支持用户设置platform_id/device_id/platform_num接口,以选择显卡核心,并支持默认优先选用独显(NVIDIA/AMD独显)
- 优化 OpenCL 后端内存分配逻辑,降低ChatGLM模型的内存占用
2. 性能优化
-
OpenCL优化Mali-GPU计算量大的卷积运算(image/buffer存储混用)。性能提升10%-20%。
-
CPU浮点模型优化Winograd卷积的准入条件、1x1Strassen算法。性能提高3%~18%。
-
CPU量化模型优化WinogradInt8、DepthwiseInt8。性能提高4%~22%。
-
CUDA优化广播Binary算子性能、Blit算子性能。
-
CUDA支持编译CodeGen功能,针对Unary/Raster/Binary算子进行算子在线融合,整体性能提升5%-10%。
3. Bugfix
3.1 关联 Github Issue 解决
- Tflite FC + Relu 情况下模型转换到 MNN 未正确解析 Relu #2332
- Onnx 模型中FP16 常量 转换到 MNN 时不支持#2477
- Onnx 新的 LayerNorm 算子不支持(目前采用效率较低的算子组合实现)#2509
- Vulkan Image 模式部分情形下计算错误#2433
- Yolov8 MNN CUDA 推理出错 #2428
- OpenCL Codegen 部分 case 下出现编译错误 #2523
3.2 其他 Bugfix 或优化
- 修正 Vulkan Buffer 模式单元测试 convolution3d 出错的问题
- 修正 ScatterND 算子在 update tensor 长度为空的计算错误问题
- 修正 Onnx EinSum 算子在部分情况下转换到 MNN 出错的问题
- 修正 Onnx Split 算子转换问题
- 支持 Onnx 的 GEMM + Relu 算子的合并
2.6.3
Merge pull request #2550 from alibaba/feature/sync [MNN:Sync] Sync Internal 2.6.3
【新增Int8 量化算子,OpenCL后端适配 recordable queue】2.6.0
1. 新特性
- 新增int8量化算子支持:
- Softmax
- Interp
- Binary
- Unary
- Scale
- OpenCL 支持 Loop 算子特定情形;
- BatchMatMul
- Gather
- x86_64支持Gelu-bf16;
- CUDA支持bf16模型推理;
- benchmark 工具支持直接测试模型量化后的性能(不需要先用量化工具量化模型)
- Pymnn Tensor/Var使用Tuple创建时支持混合类型数据;
- 权值量化模型支持低内存推理模式,计算时反量化;
- 支持ChatGLM-6B模型推理内存占用3G;
- 支持构建了ChatGLM-MNN Android app;
2. 优化
- OpenCL支持高通reocrd queue ,以降低创建 GPU Command Buffer 所需的时间;
Oneplus 9 机型 Benchmark 测试结果如下
Model | unrecord | record |
---|---|---|
resnet-v2-50.mnn | 21.254 | 20.160 |
MobileNetV2_224.mnn | 4.853 | 4.186 |
mobilenet-v1-1.0.mnn | 6.424 | 5.315 |
nasnet.mnn | 46.751 | 20.260 |
SqueezeNetV1.0.mnn | 7.35 | 6.832 |
squeezenetv1.1.mnn | 3.936 | 3.693 |
mobilenetV3.mnn | 14.201 | 6.743 |
inception-v3.mnn | 33.111 | 32.032 |
- 稀疏卷积内存优化,降低内存占用;
- 减少异构(CPU低精度/GPU)运行 MNN 模型时的常量内存占用;
- CUDA优化int8算子性能;
- 减少Permute几何计算产生的region数量;
- 重新调整ConvolutionInt8及im2col在AVX512-VNNI下的分块大小,提升性能20%-30%;
- X86新增bilinear/nearest sample的SIMD实现,提升ImageProcess性能 50% 左右;
3. Bugfix
3.1 关联 Github Issue 解决
- 修复CUDA Raster错误导致输出为0的问题;issue-2333
- 修复OpenCL Gather算子出错的问题;issue-2424
- 修复ImageProcess出错的问题;issue-2386
- OpenCL支持用户选择device id; issue-2343
3.2 其他 Bugfix
- CUDA CMakeList对未支持架构增加报错信息;
- testMNNFromOnnx脚本在模型测试正确时不启用DEBUG模式;
- load_module_from_file中的shape_mutable默认改为True(存在子图的模型无法在False情形下运行);
- MNNConvert使用keepInputFormat选项时,也同时将输出Tensor的format转换为原始格式
- 修复log记录时设备为空时Crash的情况;
- 修复BinaryOp单元测试在Windows下无法编译的问题;
- 修复MNN_SUPPORT_DEPRECATED_OP宏不控制OptimizedComputer的问题;
- 修复fp16多线程且分块方向为channel时convolution计算出错的问题;
- 修复deconvolutionInt8访存越界的问题;
- 修复TensorArrayWrite几何计算产生zero region的问题;
- 修复CUDA depthwise conv出错的问题;
- 修复一些文档格式、内容的错误;
- 修复多线程下createRuntime和setGlobalConfig出错的问题;
- 修复Vec.hpp中无用代码导致的编译失败问题;
- 修复OpenCL对gpuDevice的assert失败的问题;
- 修复OpenCL bianry mod出错的问题;
- 修复CUDA argmax出错的问题;
- 修复pymnn/example/mnn_numpy_cv_demo.py中形状不对的问题;
2.5.0
1. 新特性
- MNN OpenCV新增算子:
- erode
- convertMaps
- remap
- adaptiveThreshold
- bilateralFilter
- solve (MNN numpy新增solve)
- normalize
- split
- merge
- addWeight
- 支持Tflite int8量化模型转换到MNN模型;
- ARM CPU支持GELU-bf16
- CUDA 新增算子:
- GridSampler
- Multi-Input Convolution
- Multi-Input Deconvolution
- CUDA针对多卡推理,支持用户设置运行device_id
- 支持Deconvolution-int8
- runSession/runSessionWithCallBack函数加锁,避免多线程调用出错
- 支持非拓扑序ONNX模型转换
- 支持ONNX多版本Softmax转换
2. 重构/优化
- 优化内存分配与回收时机,新增Session
- 简化ONNX Slice算子模型转换
- Cuda性能优化
- Argmax针对dim size较大的情况性能优化
- Softmax在channel较大时性能优化
- MatMul算子预重排逻辑优化
- 优化后ChatGLM模型在A10显卡上性能优于Pytorch 2.0
- OpenCL优化,resnet测试优于OpenVINO
- 使用intel subgroup扩展优化winogard算子,调整数据排布格式与准入条件
- 根据输入尺寸调整conv2d算子的数据排布格式,使用intel subgroup扩展优化
- 优化后ResNet18模型在intel UHD Graphics 630显卡上性能优于OpenVINO
- GELU-bf16实现后性能提升
3. Bugfix
3.1 关联 Github Issue 解决
- 修复CPURaster 的 singleConvert 部分情况出错 issue-2264
- 修复atan2计算错误的问题
- 修复ONNX dynamic shape转换出错的问题 issue-2276
- 修复i8mm时Im2col出错的问题
- 修复CPUConvolutionDepthwise错误的问题 issue-2291
- 修复CUDA int8编译失败的问题 issue-2321
- 修复Onnx Loop 算子的 M 和 cond 为optional 时,转换失败的问题 issue-2267
- 修复Raster中fastblit 中turnPackRegion 部分情况下出错的问题 issue-2337
3.2 其他 Bugfix
- 修复 onnx 子图中 identity 被优化导致 输出数和原始子图不一致的问题
- 修复 Onnx sequense 相关算子转换问题
- 修复 TensorArrayConcat 计算 newAxis = 1 时的问题(此时为 stack)
- 修复 TensorArray 计算 eleSize 时,axis < 0 时计算出错的问题
- 修复低精度计算或者 GPU 无法运行 mnn 训练模型的问题
2.4.0 NNAPI后端/CUDA后端支持量化模型
一、新特性
- NNAPI 支持int8 量化模型;
- MNN OpenCL/Metal支持算子在线Fuse与代码生成;
- 支持使用cibuildwheel构建Python Wheel包;
- Github Action支持自动化构建多端库与Whl包;
- (测试中)CUDA后端支持量化模型运行
二、重构/优化
- CUDA优化Softmax/DepthwiseConv算子
- 优化 KernelSize = 3x3 的 OpenCL 卷积算子性能
- 优化了MaxPool/AvgPool的int8量化计算;
- 移除原来的LLVMJit, C等Codegen后端;
- 更新MNN.podspec, MNNBridge.podspec;
- 增加GELU模块Fuse为GELU算子的功能,Vulkan 和 OpenCL 后端支持 GELU 算子
- NetModule析构函数中增加gc函降低内存占用;
- OpenCL支持设置推理低优先级配置;
- OpenCL updateCache支持异步,降低阻塞时间;
- fastTestOnnx.py / fastTestTf.py / fastTestTflite.py / fastTestTorch.py 分别更名为 testMNNFromOnnx.py / testMNNFromTf.py / testMNNFromTflite.py / testMNNFromTorch.py
- Android Demo新增使用README文档;
三、Bugfix
- 修复Android Demo运行Crash的问题;
- 修复Metal中的onSync的Bug;
- 修复Metal多段模型推理的Bug;
- 修复在Windows下MNN Train的编译问题;
- 修复perm值非法时的Crash问题;
- 修复Pad的输入参数为负数时(此时等效为Crop),计算出错的问题
- 修正 Relu Int8 不支持非对称量化的问题
- 修正部分AVX2架构的机器上运行量化模型crash的问题
- 修正Module API 运行静态模型crash的问题
- 修正Winograd量化过程未使用相同变换矩阵的问题
- 修正Winograd量化计算多Batch输入错误的问题
- 修正 OpenCL Relu 算子在 AMD GPU 上段错误的问题
- 修正 OpenCL ROIPooling 算子实现错误