Skip to content

Commit

Permalink
Merge pull request #3028 from alibaba/feature/sync
Browse files Browse the repository at this point in the history
MNN:Sync: Sync Internal 2.9.5
  • Loading branch information
jxt1234 authored Sep 12, 2024
2 parents a8b7997 + c01ec71 commit f0e516a
Show file tree
Hide file tree
Showing 356 changed files with 17,965 additions and 51,048 deletions.
4 changes: 0 additions & 4 deletions 3rd_party/OpenCLHeaders/CL/cl2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,6 @@
# pragma message("cl2.hpp: USE_CL_DEVICE_FISSION is deprecated. Define CL_HPP_USE_CL_DEVICE_FISSION instead")
# define CL_HPP_USE_CL_DEVICE_FISSION
#endif
#if !defined(CL_HPP_ENABLE_EXCEPTIONS) && defined(__CL_ENABLE_EXCEPTIONS)
# pragma message("cl2.hpp: __CL_ENABLE_EXCEPTIONS is deprecated. Define CL_HPP_ENABLE_EXCEPTIONS instead")
# define CL_HPP_ENABLE_EXCEPTIONS
#endif
#if !defined(CL_HPP_NO_STD_VECTOR) && defined(__NO_STD_VECTOR)
# pragma message("cl2.hpp: __NO_STD_VECTOR is deprecated. Define CL_HPP_NO_STD_VECTOR instead")
# define CL_HPP_NO_STD_VECTOR
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ option(MNN_INTERNAL "Build with MNN internal features, such as model authenticat
option(MNN_JNI "Build MNN Jni for java to use" OFF)
option(MNN_SUPPORT_BF16 "Enable MNN's bf16 op" OFF)
option(MNN_LOW_MEMORY "Build MNN support low memory for weight quant model." OFF)
option(MNN_CPU_WEIGHT_DEQUANT_GEMM "Build MNN CPU weight dequant related gemm kernels." OFF)

IF (OHOS)
include($ENV{NODE_PATH}/@ali/tcpkg/tcpkg.cmake)
Expand Down
2 changes: 1 addition & 1 deletion codegen/OpFuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ bool codegen(std::vector<Schedule::OpCacheInfo>& infos, std::vector<std::vector<
auto inputs = tensors.first;
auto outputs = tensors.second;
// build Plugin Op
SharedPtr<Command> cmdPlugin;
std::shared_ptr<Command> cmdPlugin;
{
auto sourceCode = fuseModule.codegen();
if(mapKernelSources.find(sourceCode) == mapKernelSources.end()) {
Expand Down
1 change: 1 addition & 0 deletions docs/compile/cmake.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ MNN使用CMake构建项目,CMake中的宏定义列表如下:
| MNN_OPENCV_BENCH | 构建MNN的OpenCV功能是否开启性能benchmark,默认为`OFF` |
| MNN_VULKAN_IMAGE | 构建MNN的Vulkan后端时采用Image内存模式,以便支持FP16和部分移动端上GPU的加速,默认为`ON` |
| MNN_LOW_MEMORY | 是否支持低内存模式,支持低内存模式使用权值量化模型并设置`low_memory`则会使用计算时反量化,默认为`OFF` |
| MNN_CPU_WEIGHT_DEQUANT_GEMM | 是否编译CPU权重反量化的矩阵乘Kernel, 如果打开该编译宏并且在CPU推理时设置MNN::BackendConfig::MemoryMode=Memory_Normal,就会使用权重反量化算子进行权重量化模型的推理,默认为`OFF` |
| MNN_SUPPORT_RENDER | 是否支持图形渲染相关算子实现,默认为 `OFF` |
| MNN_SUPPORT_TRANSFORMER_FUSE | 是否支持Fuse Transformer相关OP实现,默认为 `OFF` |
| MNN_BUILD_LLM | 是否构建基于MNN的llm库和demo,默认为`OFF` |
Expand Down
90 changes: 53 additions & 37 deletions docs/contribute/backend.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# 自定义后端
Backend是MNN对计算设备的抽象。MNN当前已经支持CPU、Vulkan、OpenCL、Metal等Backend,**只在计算设备暂未支持时新增Backend**,新增Op,请参阅[新增Op文档](customize_op)
Runtime-Backend是MNN对计算设备的抽象。MNN当前已经支持CPU、Vulkan、OpenCL、Metal、CUDA等Backend,**只在计算设备暂未支持时新增Backend**,新增Op,请参阅[新增Op文档](op)



## 声明
所有新增Backend都需继承`Backend`类,并实现所有纯虚函数。
Expand All @@ -10,8 +12,10 @@ class XPUBackend final : public Backend {
virtual Execution* onCreate(const std::vector<Tensor*>& inputs, const std::vector<Tensor*>& outputs, const MNN::Op* op) override;
virtual void onExecuteBegin() const override;
virtual void onExecuteEnd() const override;
virtual bool onAcquireBuffer(const Tensor* tensor, StorageType storageType) override;
virtual bool onReleaseBuffer(const Tensor* tensor, StorageType storageType) override;
virtual void onResizeBegin() override;
virtual ErrorCode onResizeEnd() override;

virtual MemObj* onAcquire(const Tensor* tensor, StorageType storageType) override;
virtual bool onClearBuffer() override;
virtual void onCopyBuffer(const Tensor* srcTensor, const Tensor* dstTensor) const override;
}
Expand Down Expand Up @@ -91,7 +95,7 @@ static XPUCreatorRegister<XPUPoolingCreator> __reg(OpType_Pooling);
```
## 内存管理
Backend通过`onAcquireBuffer`为tensor分配内存,通过`onReleaseBuffer`为tensor释放内存。内存有三种存储模式:`STATIC`内存不复用,一般用于op常量存储;`DYNAMIC`内存可复用,一般用于变量存储;`DYNAMIC_SEPERATE`内存在pipeline间可复用,一般用于pipeline常量存储。`_onAcquireBuffer_`_和_`_onReleaseBuffer_`_中可以不实际分配/释放内存,只记录内存用量变更,在_`_onAllocateBuffer_`_调用时,再根据用量计算出优化方案,一次性完成分配/释放。_
Backend通过`onAcquire`创建`MemObj`内存对象,定义其析构函数以便为tensor释放内存。内存有三种存储模式:`STATIC`内存不复用,一般用于op常量存储;`DYNAMIC`内存可复用,一般用于变量存储;`DYNAMIC_SEPERATE`内存在pipeline间可复用,一般用于pipeline常量存储。
```cpp
/** backend buffer storage type */
Expand All @@ -118,31 +122,13 @@ enum StorageType {
*/
DYNAMIC_SEPERATE
};
/**
* @brief allocate buffer of tensor for given storage type.
* @param tensor buffer provider.
* @param storageType buffer storage type.
* @return success or not.
*/
virtual bool onAcquireBuffer(const Tensor* tensor, StorageType storageType) = 0;
/**
* @brief release buffer of tensor for given storage type.
* @param tensor buffer provider.
* @param storageType buffer storage type.
* @return success or not.
*/
virtual bool onReleaseBuffer(const Tensor* tensor, StorageType storageType) = 0;
```

在所有内存都分配完成后,backend会收到`onAllocateBuffer`回调:
```cpp
/**
* @brief callback after all buffers needed by backend ops were allocated.
* @return success or not. (result not used currently)
*/
virtual bool onAllocateBuffer() {
return true;
}
/**
* @brief allocate buffer of tensor for given storage type.
* @param tensor buffer provider.
* @param storageType buffer storage type.
* @return MemObj for release, if failed, return nullptr.
*/
virtual MemObj* onAcquire(const Tensor* tensor, StorageType storageType) = 0;
```

Backend在调用`onClearBuffer`时,需要释放所有`DYNAMIC``DYNAMIC_SEPERATE`存储模式的内存:
Expand Down Expand Up @@ -189,17 +175,47 @@ virtual void onExecuteEnd() const = 0;
```

## 注册Backend
最后,定义Backend Creator,注册方法中调用`MNNInsertExtraBackendCreator`就可以完成Backend的注册,这里的注册方法需要在BackendRegister.cpp中声明并调用:
## Runtime(运行时)
对于使用同一种后端,且存在先后顺序,不会同时运行的模型,MNN提供机制使其共享部分计算资源,比如线程池,内存池等等。
这部分计算资源使用Runtime存储。而Backend则由Runtime创建

### 实现Runtime
Runtime主要实现如下接口:

```
virtual Backend* onCreate(const BackendConfig* config = nullptr, Backend* origin = nullptr) const = 0;
/**
@brief reset runtime
*/
virtual void onReset(int numberThread, const BackendConfig* config, bool full) {
// Do nothing
}
/**
@brief clear unuseful resource
@param level clear level: 0 - 100, bigger mean clear more, smaller mean cache more
*/
virtual void onGabageCollect(int level) = 0;
```

- onCreate :创建 Backend
- onReset :重设默认配置
- onGabageCollect :清理资源以节省内存


### 注册Runtime
注册方法中调用`MNNInsertExtraRuntimeCreator`就可以完成Runtime的注册,这里的注册方法需要在Backend.cpp中声明并调用:
```cpp
class XPUBackendCreator : public BackendCreator {
virtual Backend *onCreate(const Backend::Info &info) const {
return new MetalBackend;
class XPURuntimeCreator : public RuntimeCreator {
virtual Runtime* onCreate(const Backend::Info &info) const {
return new XPURuntime;
}
};
void registerCPUBackendCreator() {
MNNInsertExtraBackendCreator(MNN_FORWARD_CPU, new CPUBackendCreator);
void registerXPURuntimeCreator() {
MNNInsertExtraBackendCreator(MNN_FORWARD_XPU, new XPURuntimeCreator);
};
```
使用cmake编译时,完成代码修改后,也需要相应修改CMakeLists.txt。
使用cmake编译时,完成代码修改后,也需要相应修改CMakeLists.txt。
10 changes: 9 additions & 1 deletion docs/contribute/op.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# 自定义算子
## 概述
在添加自定义算子前,请参阅[算子列表](../en/ops),避免不必要的重复。
在添加自定义算子前,请查看算子列表,避免不必要的重复。

```bash
./MNNConvert -f CAFFE --OP
./MNNConvert -f TF --OP
./MNNConvert -f ONNX --OP
./MNNConvert -f TORCH --OP
```

### MNN 算子转换与实现结构
MNN 的算子转换与实现如下图,
- 模型转换包括以下步骤,二选一:
Expand Down
4 changes: 2 additions & 2 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,15 +250,15 @@ OpenCL / Vulkan 采用静态变量自注册的方式往 MNN 主库注册后端.
## 性能相关
### 使用 GPU 时,调用 copyToHostTensor / copyFromHostTensor 非常慢
### 使用 GPU 时,调用 copyToHostTensor / readMap 非常慢
GPU 后端调用 copy 的时间包含两个部分
- 异构数据拷贝
- 等待数据相关的GPU计算完成
对 GPU 后端而言,在数据被要求对用户可见(比如复制 output tensor 数据出来)之前,是允许异步执行的。
在数据被用户要求可见之时,会等待相应的异步操作完成。
因此有可能 复制 output tensor 的过程包括了等待 GPU 算子异步执行完成,导致缓慢
因此有可能 复制 output tensor 的过程包括了等待 GPU 算子异步执行完成,导致看上去缓慢
### GPU 为什么比 CPU 跑得慢?
有如下原因:
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@

.. toctree::
:maxdepth: 1
:caption: 测试工具
:caption: 工具集
:name: tools

tools/convert
Expand Down
86 changes: 77 additions & 9 deletions docs/inference/module.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@
- 模型推理与`Session`的区别是不需要用户显式resize,支持控制流,所以当模型中有`if``while`时必须使用`Module`推理
### 相关数据结构
- `Module` Module接口的核心类,表示一个模型的虚类;实际加载模型时会创建其子类
- `Executor` 包含若干个`RuntimeManager`,提供内存管理接口,每个`Executor`必须在单线程环境下运行。默认提供全局 `Executor`,需要并发执行时,可自行创建。
- `ExecutorScope` 用于在子线程中绑定`Executor`,多线程并发必需
- `VARP` 作为`Module`的输入输出,也是[Expr API](expr.md)中的基础数据结构
- `Executor` 提供内存管理和后端资源管理能力,每个`Executor`必须在单线程环境下运行。同一个`Executor`可以用于多个顺序执行的`Module`
- `ExecutorScope` 用于在子线程中绑定`Executor`,多线程并发必需。默认在创建`Module`时使用全局 `Executor`,如果有多个Module在不同线程并发执行时,需要各自创建`Executor`,并用`ExecutorScope`绑定。
- `VARP` `Module`的输入输出,也是[Expr API](expr.md)中的基础数据结构

## 工作流程
配置Executor(可选) -> 创建 RuntimeManager(可选) -> 创建Module -> 创建输入VARP -> 使用Module::forwad推理 -> 使用输出VARP -> 销毁Module
### (可选)配置Executor
`Executor`给用户提供接口来配置推理后端、线程数等属性,以及做性能统计、算子执行的回调函数、内存回收等功能。 提供一个全局的Exector对象,用户不用创建或持有对象即可直接使用
创建和配置Executor -> 创建 RuntimeManager(可选) -> 创建Module -> 创建输入VARP -> 使用Module::forwad推理 -> 使用输出VARP -> 销毁Module -> 销毁Executor
### 创建和配置Executor
`Executor`给用户提供接口来配置推理后端、线程数等属性,以及做性能统计、算子执行的回调函数、内存回收等功能。 推荐针对自身模块创建单独的Executor ,若使用全局的Exector对象,对于多个模块在不同线程运行时可能会发生冲突
```cpp
// 配置默认全局Exector
MNN::BackendConfig backend_config; // default backend config
// 创建Exector
MNN::BackendConfig backendConfig; // default backend config
std::shared_ptr<MNN::Express::Executor> executor = MNN::Express::Executor::newExecutor(MNN_FORWARD_CPU, backendConfig, 1);

// 设置使用4线程+CPU
MNN::Express::Executor::getGlobalExecutor()->setGlobalExecutorConfig(MNN_FORWARD_CPU, backend_config, 4);
executor->setGlobalExecutorConfig(MNN_FORWARD_CPU, backend_config, 4);

// 绑定Executor,在创建/销毁/使用Module或进行表达式计算之前都需要绑定
MNN::Express::ExecutorScope _s(executor);

```
### (可选)创建 RuntimeManager
Expand All @@ -39,6 +45,68 @@ std::shared_ptr<MNN::Express::Executor::RuntimeManager> rtmgr(MNN::Express::Exec
rtmgr->setCache(".cachefile");
```
RuntimeManager 可以设置 hint , mode , cache, externalpath ,以支持扩展功能。
```
void setCache(std::string cacheName);
void updateCache();
void setMode(Interpreter::SessionMode mode);
void setHint(Interpreter::HintMode mode, int value);
void setExternalPath(std::string path, int type);
bool getInfo(Interpreter::SessionInfoCode code, void* ptr);
```
#### cache 设置
对于GPU后端(Metal/OpenCL等),可以设置缓存文件路径,存储AutoTuning结果和Program编译结果,以加速第二次之后的Module load 过程。
```
std::shared_ptr<Executor::RuntimeManager> rtmgr(Executor::RuntimeManager::createRuntimeManager(config));
rtmgr->setCache(cacheFileName);

std::shared_ptr<Module> module(Module::load(inputNames, outputNames, modelName.c_str(), rtmgr, mdConfig));
/*... Make Inputs*/
auto outputs = module->onForward(inputs);

// Update cache file
rtmgr->updateCache();
```
#### mode 设置
可以通过设置mode开启/关闭一些功能,示例:
```
// 创建出来的 Module 支持插入回调函数
rtmgr->setMode(Interpreter::Session_Debug);
```
并非所有枚举都适用 Module 的创建,有效值如下:
- Interpreter::SessionMode::Session_Debug : 支持逐算子调试
- Interpreter::SessionMode::Session_Release : 关闭逐算子调试功能,可以轻微提升性能【默认选项】
- Interpreter::SessionMode::Session_Backend_Fix : 固定使用用户设置的后端【默认选项】
- Interpreter::SessionMode::Session_Backend_Auto : MNN根据用户倾向,预估load Module耗时,如果耗时较短则使用用户设置的后端,否则使用CPU
#### hint 设置
通过 hint 设置,可以在后端支持的情况下设置相应属性,有效值如下:
- Interpreter::HintMode::WINOGRAD_MEMORY_LEVEL :使用 Winograd 算法优化卷积时,内存占用倾向,默认为 3 ,若希望降低内存占用可设为 0
- Interpreter::HintMode::GEOMETRY_COMPUTE_MASK :几何计算相关优化开关,1为区域合并,2为复合区域合并,4为使用loop算子,8为支持几何计算重计算,需要多个功能开启时把对应值叠加。默认为功能全开。
- Interpreter::HintMode::DYNAMIC_QUANT_OPTIONS :动态量化选项,1为 Per Batch,2为Per Tensor 。默认为2。
- Interpreter::HintMode::CPU_LITTLECORE_DECREASE_RATE :对于 Android 设备存在大中小核的情况,大核算力到中核算力的衰减比例。默认为50(中核算力为大核的50%)
#### ExternalPath
在设备可能出现内存不足时,可以通过 setExternalPath 指定路径,让MNN把部分内存用mmap分配。这样操作系统可在内存不足时会将其转换为读写文件,避免内存不足程序闪退。示例:
```
runtime_manager_->setExternalPath("tmp", MNN::Interpreter::EXTERNAL_WEIGHT_DIR);
runtime_manager_->setExternalPath("tmp", MNN::Interpreter::EXTERNAL_FEATUREMAP_DIR);
```
- MNN::Interpreter::EXTERNAL_WEIGHT_DIR : 权重重排后的内存转换为文件存储
- MNN::Interpreter::EXTERNAL_FEATUREMAP_DIR : 中间内存转换为文件存储
### 创建Module
`Module`可以通过指定模型,输入输出的名称,配置文件创建
```cpp
Expand Down
4 changes: 2 additions & 2 deletions docs/start/overall.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
### 训练
在训练框架上,根据训练数据训练出模型的阶段。虽然当前MNN也提供了[训练模型的能力](../train/expr.md),但主要用于端侧训练或模型调优。在数据量较大时,依然建议使用成熟的训练框架,如TensorFlow、PyTorch等。除了自行训练外,也可以直接利用开源的预训练模型。
### 转换
将其他训练框架模型转换为MNN模型的阶段。MNN当前支持Tensorflow(Lite)、Caffe、ONNX和TorchScript的模型转换。模型转换工具可以参考[编译文档](../compile/tools.html#id2)[使用说明](../tools/convert.md)。支持转换的算子,可以参考[算子列表文档](../tools/convert.html#id7);在遇到不支持的算子时,可以尝试[自定义算子](../contribute/op.md),或在Github上给我们[提交issue](https://github.com/alibaba/MNN/issues/74)。此外,[模型打印工具](../tools/convert.html#id8)可以用于输出模型结构,辅助调试。除模型转换外,MNN也提供了[模型量化工具](../tools/quant.md),可以对浮点模型进行量化压缩。
将其他训练框架模型转换为MNN模型的阶段。MNN当前支持Tensorflow(Lite)、Caffe、ONNX和TorchScript的模型转换。模型转换工具可以参考[使用说明](../tools/convert.md)。支持转换的算子,可以参考[算子列表文档](../tools/convert.html#id7);在遇到不支持的算子时,可以尝试[自定义算子](../contribute/op.md),或在Github上给我们[提交issue](https://github.com/alibaba/MNN/issues/74)。此外,[模型打印工具](../tools/convert.html#id8)可以用于输出模型结构,辅助调试。除模型转换外,MNN也提供了[模型量化工具](../tools/quant.md),可以对浮点模型进行量化压缩。
### 推理
在端侧加载MNN模型进行推理的阶段。端侧运行库的编译请参考各平台的编译文档:[iOS](../compile/engine.html#ios)[Android](../compile/engine.html#android)[Linux/macOS/Ubuntu](../compile/engine.html#linux-macos)[Windows](../compile/engine.html#windows)。我们提供了[API接口文档](https://github.com/alibaba/MNN/tree/master/doc/API),也详细说明了[会话创建](../inference/session.html#id1)[数据输入](../inference/session.html#id8)[执行推理](../inference/session.html#id17)[数据输出](../inference/session.html#id21)相关的接口和参数。`demo/exec`下提供了使用示例,如图像识别 `demo/exec/pictureRecognition.cpp` ,图像实例分割(人像分割)`demo/exec/segment.cpp`[更多demo](demo.md)。此外,[测试工具](../tools/test.md)[benchmark工具](../tools/benchmark.md)也可以用于问题定位。
在端侧加载MNN模型进行推理的阶段。端侧运行库的编译请参考各平台的编译文档:[iOS](../compile/engine.html#ios)[Android](../compile/engine.html#android)[Linux/macOS/Ubuntu](../compile/engine.html#linux-macos)[Windows](../compile/engine.html#windows)。我们提供了[API接口文档](https://github.com/alibaba/MNN/tree/master/doc/API),也详细说明了[会话创建](../inference/session.html#id1)[数据输入](../inference/session.html#id8)[执行推理](../inference/session.html#id17)[数据输出](../inference/session.html#id21)相关的接口和参数。`demo/exec`下提供了使用示例,如图像识别 `demo/exec/pictureRecognition.cpp` ,图像实例分割(人像分割)`demo/exec/segment.cpp`[更多demo](demo.md)。此外,[测试工具](../tools/test.md)[benchmark工具](../tools/benchmark.md)也可以用于问题定位。
1 change: 0 additions & 1 deletion docs/tools/convert.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# 模型转换工具
[从源码编译](../compile/tools.html#id2)
## 参数说明
```bash
Usage:
Expand Down
Loading

0 comments on commit f0e516a

Please sign in to comment.